Ejemplo n.º 1
0
    async def publish_properties(self):
        """publish device and node properties"""
        publish = self.publish

        # device properties
        await publish("$homie", "4.0.0")
        await publish("$name", self.device_name)
        await publish(DEVICE_STATE, STATE_INIT)
        await publish("$implementation", bytes(platform, UTF8))
        await publish(
            "$nodes", ",".join([n.id for n in self.nodes])
        )

        # node properties
        nodes = self.nodes
        for n in nodes:
            await n.publish_properties()

        if self._extensions:
            await publish("$extensions", ",".join(self._extensions))
            if "org.homie.legacy-firmware:0.1.1:[4.x]" in self._extensions:
                await publish("$localip", utils.get_local_ip())
                await publish("$mac", utils.get_local_mac())
                await publish("$fw/name", "Microhomie")
                await publish("$fw/version", __version__)
            if "org.homie.legacy-stats:0.1.1:[4.x]" in self._extensions:
                await self.publish("$stats/interval", str(self.stats_interval))
                # Start stats coro
                launch(self.publish_stats, ())
Ejemplo n.º 2
0
 async def killer(self):
     loop = asyncio.get_event_loop()
     while self.tstop > loop.time():
         # Must loop here: might be retriggered
         await asyncio.sleep_ms(self.tstop - loop.time())
     if self._running and self.func is not None:
         launch(self.func, self.args)  # Execute callback
     self._running = False
Ejemplo n.º 3
0
 async def killer(self):
     loop = asyncio.get_event_loop()
     twait = time.ticks_diff(self.tstop, loop.time())
     while twait > 0 and self._running:  # Return if stop() called during wait
         # Must loop here: might be retriggered
         await asyncio.sleep_ms(twait)
         twait = time.ticks_diff(self.tstop, loop.time())
     if self._running and self.func is not None:
         launch(self.func, self.args)  # Execute callback
     self._running = False
Ejemplo n.º 4
0
 async def killer(self):
     twait = time.ticks_diff(self.tstop, time.ticks_ms())
     while twait > 0:  # Must loop here: might be retriggered
         await asyncio.sleep_ms(twait)
         if self.tstop is None:
             break  # Return if stop() called during wait
         twait = time.ticks_diff(self.tstop, time.ticks_ms())
     if self.tstop is not None and self.func is not None:
         launch(self.func, self.args)  # Timed out: execute callback
     self.tstop = None  # Not running
Ejemplo n.º 5
0
    async def connection_handler(self, client):
        """subscribe to all registered device and node topics"""
        if self._first_start is False:
            await self.publish(DEVICE_STATE, STATE_RECOVER)

        retained = []
        subscribe = self.subscribe

        # Broadcast topic
        await self.mqtt.subscribe("{}/{}/#".format(self.btopic, T_BC), QOS)

        # Micropython extension
        await self.mqtt.subscribe("{}/{}".format(self.dtopic, T_MPY), QOS)

        # node topics
        nodes = self.nodes
        for n in nodes:
            props = n._properties
            for pid, p in props.items():
                if p.restore:
                    # Restore from topic with retained message
                    await self.add_node_cb(n)
                    t = "{}/{}".format(n.id, pid)
                    await subscribe(t)
                    retained.append(t)

                if p.settable:
                    await self.add_node_cb(n)
                    await subscribe("{}/{}/set".format(n.id, pid))

        # on first connection:
        # * publish device and node properties
        # * enable WDT
        # * run all coros
        if self._first_start is True:
            await self.publish_properties()

            unsubscribe = self.unsubscribe
            # unsubscribe from retained topics
            for t in retained:
                await unsubscribe(t)

            self._first_start = False

            # activate WDT
            if LINUX is False and self.debug is False:
                launch(self.wdt, ())

            # start coros waiting for ready state
            _EVENT.set()
            await sleep_ms(MAIN_DELAY)
            _EVENT.clear()

        await self.publish(DEVICE_STATE, STATE_READY)
Ejemplo n.º 6
0
 async def switchcheck(self):
     loop = asyncio.get_event_loop()
     while True:
         state = self.pin.value()
         if state != self.switchstate:
             # State has changed: act on it now.
             self.switchstate = state
             if state == 0 and self.close_func:
                 launch(self._close_func, self._close_args)
             elif state == 1 and self._open_func:
                 launch(self._open_func, self._open_args)
         # Ignore further state changes until switch has settled
         await asyncio.sleep_ms(Switch.debounce_ms)
Ejemplo n.º 7
0
    def on_active_msg(self, topic, payload, retained):
        if payload == FALSE:
            if self.active:
                asyn.launch(asyn.NamedTask.cancel, (_SENSOR,))
                self.active = False
        elif payload == TRUE:
            if not self.active:
                self.active = True
                loop = get_event_loop()
                loop.create_task(
                    asyn.NamedTask(_SENSOR, self.pir_sensor)()
                )
        else:
            return

        self.active_property.data = payload
Ejemplo n.º 8
0
    def callback(self, topic, payload, retained):
        if b"active" in topic:
            if payload == FALSE:
                if self.active:
                    asyn.launch(asyn.NamedTask.cancel, ("pir_sensor", ))
                    self.active = False
            elif payload == TRUE:
                if not self.active:
                    self.active = True
                    loop = get_event_loop()
                    loop.create_task(
                        asyn.NamedTask("pir_sensor", self.pir_sensor)())
            else:
                return

            self.pir_property.data = payload
            if retained:
                self.pir_sensor.update_delta()
Ejemplo n.º 9
0
    def callback(self, topic, payload, retained):
        """ Gets called when a payload arrive on node topics

            This method is keeped for backward compatibilty. Old
            Microhomie versions still can overwrite this method in child
            classes to handle mesages.
        """
        # unsubscribe from retained topic
        if retained:
            launch(self.device.unsubscribe, (topic, ))

        t = topic.split(SLASH)
        pid = t.pop()  # property id
        if pid == SET:
            pid = t.pop()

        try:
            p = self._properties[pid]
            p.msg_handler(topic, payload, retained)
        except KeyError:
            pass
Ejemplo n.º 10
0
 async def buttoncheck(self):
     loop = asyncio.get_event_loop()
     if self._long_func:
         longdelay = Delay_ms(self._long_func, self._long_args)
     if self._double_func:
         doubledelay = Delay_ms()
     while True:
         state = self.rawstate()
         # State has changed: act on it now.
         if state != self.buttonstate:
             self.buttonstate = state
             if state:
                 # Button is pressed
                 if self._long_func and not longdelay.running():
                     # Start long press delay
                     longdelay.trigger(Pushbutton.long_press_ms)
                 if self._double_func:
                     if doubledelay.running():
                         launch(self._double_func, self._double_args)
                     else:
                         # First click: start doubleclick timer
                         doubledelay.trigger(Pushbutton.double_click_ms)
                 if self._true_func:
                     launch(self._true_func, self._true_args)
             else:
                 # Button release
                 if self._long_func and longdelay.running():
                     # Avoid interpreting a second click as a long push
                     longdelay.stop()
                 if self._false_func:
                     launch(self._false_func, self._false_args)
         # Ignore state changes until switch has settled
         await asyncio.sleep_ms(Pushbutton.debounce_ms)
Ejemplo n.º 11
0
    def sub_cb(self, topic, payload, retained):
        topic = topic.decode()
        payload = payload.decode()

        self.dprint(
            "MQTT MESSAGE: {} --> {}, {}".format(topic, payload, retained)
        )

        # Only non-retained messages are allowed on /set topics
        if retained and topic.endswith(T_SET):
            return

        # broadcast callback passed to nodes
        if T_BC in topic:
            nodes = self.nodes
            for n in nodes:
                n.broadcast_callback(topic, payload, retained)
        # Micropython extension
        elif topic.endswith(T_MPY):
            if payload == "reset":
                launch(self.reset, ("reset",))
            elif payload == "webrepl":
                launch(self.reset, ("webrepl",))
            elif payload == "yaota8266":
                launch(self.reset, ("yaotaota",))
        else:
            # node property callbacks
            nt = topic.split(SLASH)
            node = nt[len(self.dtopic.split(SLASH))]
            if node in self.callback_topics:
                self.callback_topics[node](topic, payload, retained)
Ejemplo n.º 12
0
 def add_node(self, node):
     """add a node class of Homie Node to this device"""
     collect()
     node.device = self
     self.nodes.append(node)
     launch(node.publish_data, ())