async def on_message(self, topic, msg, retain): """ Changes the state of the pump. In switch mode a safety shutdown coro will be started. In repeating mode only the state of the pump gets changed. """ print("on_message", topic, msg, retain, self._repeating_mode) if retain is True: await asyncio.sleep( 2 ) # so that other retained message about on_time,off_time and mode get processed first if self._repeating_mode is False: if self._off_coro is not None: asyncio.cancel(self._off_coro) if msg in _mqtt.payload_on: if (await super().on_message(topic, msg, retain)) is True: if self._repeating_mode is False: self._off_coro = self._wait_off() asyncio.get_event_loop().create_task(self._off_coro) elif msg in _mqtt.payload_off: if (await super().on_message(topic, msg, retain)) is False: if self._repeating_mode is False: self._off_coro = self._wait_off() asyncio.get_event_loop().create_task( self._off_coro) # try again else: await _log.asyncLog("error", "unsupported payload: {!s}".format(msg)) return False return True
async def on_message(self, topic, msg, retain): if retain is True: return False m = memoryview(topic) if m[-4:] == b"/set": return False if m == memoryview(self._topic)[:-2]: print("received amount", msg) self._icomp = int(msg) # no return so it can end if 0 components are expected elif self._icomp is None: await _log.asyncLog("error", "Need amount of components first") return False else: if type(msg) != dict: await _log.asyncLog("error", "Received config is no dict") return False name = topic[topic.rfind("/") + 1:] del topic gc.collect() _log.info("received config for component", name, ":", msg, local_only=True) if name in self._rcomp: # received config already, typically happens if process was # interrupted by network error return False self._rcomp.append(name) self._saveComponent(name, msg) await config.registerComponent(name, msg) if len(self._rcomp) == self._icomp: # received all components asyncio.cancel(self._watcher_coro) return False
async def _read(self): a = time.ticks_us() p = self._ppin if p is not None: p.value(1) vol = self._adc.readVoltage() if self.DEBUG is True: print("#{!s}, V".format(self.getTopic(SENSOR_BINARY_MOISTURE)[-1]), vol) if p is not None: p.value(0) if vol >= self._cv: state = False if self._lv != state: # dry if self._pub_coro is not None: asyncio.cancel(self._pub_coro) self._pub_coro = _mqtt.publish(self.getTopic(SENSOR_BINARY_MOISTURE), "OFF", qos=1, retain=True, timeout=None, await_connection=True) asyncio.get_event_loop().create_task(self._pub_coro) self._lv = state else: state = True if self._lv != state: # wet if self._pub_coro is not None: asyncio.cancel(self._pub_coro) self._pub_coro = _mqtt.publish(self.getTopic(SENSOR_BINARY_MOISTURE), "ON", qos=1, retain=True, timeout=None, await_connection=True) asyncio.get_event_loop().create_task(self._pub_coro) self._lv = state b = time.ticks_us() if WaterSensor.DEBUG: print("Water measurement took", (b - a) / 1000, "ms")
async def _preprocessor(self, coroutine, *args, timeout=None, await_connection=True): coro = None start = time.ticks_ms() i = 0 if len(args) == 4 else 1 # 0: publish, 1:(un)sub try: while timeout is None or time.ticks_diff(time.ticks_ms(), start) < timeout * 1000: if not await_connection and not self._isconnected: return False if self._ops_coros[i] is coro is None: coro = self._operationTimeout(coroutine, *args, i=i) asyncio.get_event_loop().create_task(coro) self._ops_coros[i] = coro elif coro: if self._ops_coros[i] != coro: return True # published await asyncio.sleep_ms(20) _log.debug("timeout on", "(un)sub" if i else "publish", args, local_only=True) self.__timedout += 1 except asyncio.CancelledError: raise # the caller should be cancelled too finally: if coro and self._ops_coros[i] == coro: async with self.lock: asyncio.cancel(coro) return False # else: returns value during process return False
async def _connected_handler(self, client): try: await self.publish(self.getDeviceTopic( config.MQTT_AVAILABILITY_SUBTOPIC), "online", qos=1, retain=True) # if it hangs here because connection is lost, it will get canceled when reconnected. if self.__first_connect is True: # only log on first connection, not on reconnect as nothing has changed here await _log.asyncLog( "info", str(os.name if platform == "linux" else os.uname())) await _log.asyncLog( "info", "Client version: {!s}".format(config.VERSION)) self.__first_connect = False elif self.__first_connect is False: await _log.asyncLog("debug", "Reconnected") # resubscribe topics because clean session is used if self._sub_coro is not None: asyncio.cancel(self._sub_coro) self._sub_coro = self._subscribeTopics() asyncio.get_event_loop().create_task(self._sub_coro) for cb in self._reconnected_subs: res = cb(client) if type(res) == type_gen: await res self._connected_coro = None except asyncio.CancelledError: if self._sub_coro is not None: asyncio.cancel(self._sub_coro)
async def off(self, extended_switch, component, component_on, component_off): """Turn device off""" if self._coro is not None: asyncio.cancel(self._coro) else: await component_off() return True
async def _remove(self): """Will be called if the component gets removed""" # Cancel any loops/asyncio coroutines started by the component try: asyncio.cancel(self._loop_coro) except Exception: pass await super()._remove()
async def _kill_task(self): if self.task is not None: await d(0) # the task has to be started, otherwise cancel will block todo: remove if possible cancel(self.task) await d(0) # be sure it gets killed io.oled.fill(0) # prepare oled for next task self._area = None # no area in use
def stop(leds, coros): global running running = False while coros: asyncio.cancel(coros.pop()) # Remove power from external hardware for led in leds: led.off() Latency(200) # Slow down scheduler to conserve power
async def _connected(self, client): _log.debug("mqtt connected", local_only=True) self.__reconnects += 1 if self.__last_disconnect is not None: self.__downtime += (time.ticks_ms() - self.__last_disconnect) / 1000 self.__last_disconnect = None if self._connected_coro is not None: # processed subscriptions would have to be done again anyway asyncio.cancel(self._connected_coro) self._connected_coro = self._connected_handler(client) asyncio.get_event_loop().create_task(self._connected_coro)
async def off(self): """Turn switch off. Can be used by other components to control this component""" if self.lock.locked() is True and self._wfl is False: return False async with self.lock: res = await self._off( ) # if _off() returns True the value should be published if res is True: self._setState(False) if self._pub_task: asyncio.cancel(self._pub_task) self._pub_task = None self._pub_task = asyncio.get_event_loop().create_task( self.__publish("OFF")) return res
def changeto(self, r: int, g: int, b: int, time=0, loop_cmd=False): self.looping = loop_cmd for action in self.current_action: try: asyncio.cancel(action) except AttributeError as e: if "pend_throw" in e.args[0]: continue else: raise self.current_action = (self.transition(r, time, self.RED), self.transition(g, time, self.GREEN), self.transition(b, time, self.BLUE)) for action in self.current_action: self.loop.create_task(action)
def run_until_any(self, coros): stopcoros = [] done = [] pending = list(coros) for coro in coros: def stopper(coro): yield from coro pending.remove(coro) done.append(coro) yield asyncio.StopLoop(0) stopcoro = stopper(coro) stopcoros.append(stopcoro) self.call_soon(stopcoro) self.run_forever() for stopcoro in stopcoros: asyncio.cancel(stopcoro) return done, pending
def heartbeat(enabled=True): """Show LED indicator that the async loop is running.""" global _heartbeat_coroutine blue_led = pyb.LED(4) # blue if enabled and (_heartbeat_coroutine is None): # Start async def heartbeat_task(): while True: blue_led.on() await asyncio.sleep_ms(HEARTBEAT_PULSE) blue_led.off() await asyncio.sleep_ms(HEARTBEAT_PERIOD - HEARTBEAT_PULSE) _heartbeat_coroutine = heartbeat_task() upyt.sched.loop.create_task(_heartbeat_coroutine) elif (not enabled) and (_heartbeat_coroutine is not None): # Stop asyncio.cancel(_heartbeat_coroutine) blue_led.off() _heartbeat_coroutine = None
async def changeMode(self, topic, msg, retain): print("changeMode", topic, msg, retain, self._repeating_mode) if msg not in _mqtt.payload_on and msg not in _mqtt.payload_off: raise ValueError("unsupported payload {!r}".format(msg)) if msg in _mqtt.payload_on: if self._repeating_mode is True: # already on return True elif self._repeating_mode is False: await super().on_message(self._topic, "OFF", retain) self._off_coro = self._repeating() asyncio.get_event_loop().create_task(self._off_coro) elif msg in _mqtt.payload_off: if self._off_coro is not None: asyncio.cancel(self._off_coro) # will shut down pump self._off_coro = None if self._repeating_mode is True: return True elif self._repeating_mode is False: await super().on_message(self._topic, "OFF", retain) return True return True
async def run(s_sock, loop, spectrum, np, np_state): coroColorChange = changeNeoPixelColor(spectrum, np) poller = select.poll() poller.register(s_sock, select.POLLIN) while True: res = poller.poll(1) # 1ms block if res: # Only s_sock is polled conn, addr = s_sock.accept() # get client socket request = conn.recv(1024) request = str(request) led_on = request.find('/?led=on') led_off = request.find('/?led=off') if led_on == 6 and np_state == "OFF": np_state = "ON" loop.create_task(coroColorChange) if led_off == 6 and np_state == "ON": np_state = "OFF" asyncio.cancel(coroColorChange) setNeoPixel(np, 0, 0, 0) coroColorChange = changeNeoPixelColor(spectrum, np) # Implies if led_on and "ON", dont change state # Implies if led_off and "OFF", dont change state loop.create_task(sendWebPage(conn, np_state)) await asyncio.sleep_ms(200)