async def op(self, params): log.debug("Run scheduled job with param: %s", params) x = await self.__opc.op_request(params, False) if x[CODE] == 200: log.info("Run scheduled job done: %s", x) else: log.warning("Run scheduled job failed: %s", x)
async def __process_sensor_queue(self, result): if PRINT_SENSOR_DATA: log.debug("Process sensor queue: %s", result) if self.__consumers is None or len(self.__consumers) <= 0: return for c in self.__consumers: await c.consume(result)
def __create_scheduler(self, j, onetime=False): log.debug("create cron item %s", j) (sec, m, hr, mday, mon, wday) = parse(j[SCHEDULE]) p = j[PARAMS] if onetime: t = asyncio.create_task( schedule(self.op, p, secs=sec, mins=m, hrs=hr, mday=mday, month=mon, wday=wday, times=1)) self.__onetime.append(t) else: t = asyncio.create_task( schedule(self.op, p, secs=sec, mins=m, hrs=hr, mday=mday, month=mon, wday=wday)) self.__cron.append(t)
async def index(request, response): try: t, p, m, d, _ = await parse_request(request) r = await opc.op(t, p, m, d) except BaseException as e: #NOSONAR log.debug("Request error: %r", e) r = result(500, str(e)) code = r[CODE] if 200 <= code <= 299: v = None if VALUE not in r else r[VALUE] if v is None: s = "" else: s = dumps(enc(v)) else: if VALUE in r: r.pop(VALUE) s = dumps(enc(r)) response.code = r[CODE] # Start HTTP response with content-type text/html response.add_header('Content-Type', 'application/json') response.add_header('Content-Length', str(len(s))) await response._send_headers() #pylint: disable=protected-access await response.send(s)
def __connect(self, force = False, reload = False): if self.is_connected() and not force and not reload: return True self.disconnect() self.load(reload) self.__check_config() if self.__valid_config: if self.config_item(ENABLED, False): if self.__with_auth: self.__client = MQTTClient( DEVICE_NAME, self.config_item(HOST), self.config_item(PORT), self.config_item(USER), self.config_item(PASSWORD), 0, SSL) else: self.__client = MQTTClient( DEVICE_NAME, self.config_item(HOST), self.config_item(PORT), None, None, 0, SSL) else: log.info("MQTT disabled") return False else: log.error("Invalid mqtt config") return False self.__client.connect() self.__client.DEBUG = DEBUG self.__client.set_callback(self.__sub_callback) self.__client.subscribe(bytes(CMD_TOPIC, 'utf-8')) self.__connected = True log.debug("Mqtt broker connected") return True
async def __op(self, p): asyncio.sleep(0) try: mop = p[OP].lower() if mop == 'on': self.__relay.on() elif mop == 'off': self.__relay.off() elif mop == 'flip': self.flip() elif mop == 'blink': onms = p[ON_MS] offms = p[OFF_MS] if type(onms) == int and type(offms) == int: asyncio.create_task(self.async_blink(int(onms), int(offms))) else: return INVALID_ARGS elif mop == 'stop-blink': self.stop_async_blink() else: return INVALID_ARGS except BaseException as e: log.debug("Op error: %r", e) return INVALID_ARGS return result(200, None, self.get_state())
def __int_sub(self): try: if self.is_connected(): log.debug("mqtt sub-check") self.__client.check_msg() self.__last_ping_tm = time() except: #pylint: disable=bare-except self.__connected = False
def send(self, r): try: if not self.is_authed(): log.debug("No authenticated central") return self.write(dumps(r)) except BaseException as e: log.debug("Send failed: %r" , e)
async def _call(self, data): try: r = await self._opc.op_request(data, False) self.send(r) except BaseException as e: #NOSONAR msg = "Call failed %r" % e log.debug(msg) self.send(result(500, msg))
async def cleanup_cron(self, empty_cfg=False): log.debug("Clean up cron job") if self.__cron is not None and len(self.__cron) > 0: for t in self.__cron: cancel_task(t) self.__cron.clear() self.__cron = [] if empty_cfg: await self.__set([])
async def __cleanup_onetime(self, _): log.debug("Clean up one time job") if self.__onetime is not None and len(self.__onetime) > 0: for t in self.__onetime: cancel_task(t) self.__onetime.clear() self.__onetime = [] await asyncio.sleep(0) return result()
def __keep_alive(self): if time() > self.__last_ping_tm + KEEP_ALIVE: try: if self.is_connected(): log.debug("Mqtt ping") self.__client.ping() self.__last_ping_tm = time() except: #pylint: disable=bare-except self.__connected = False
def setup(self): try: log.debug("Load cron jobs") self.cleanup_cron() js = self.load() for j in js: self.__create_scheduler(j, False) except BaseException as e: #NOSONAR #pylint: disable=bare-except log.error("Load cron failed %r", e) self.cleanup_cron()
def disconnect(self): log.debug("Disconnect mqtt") self.__connected = False if self.__client is None: return try: self.__client.disconnect() except: #pylint: disable=bare-except pass self.__client = None
async def monitor(self): log.debug("Setup wifi monitor") while hw.WIFI: try: await sleep(hw.WIFI_CHECK_INTVAL) if not self.check_connection(): log.info("Wifi is not ready, reconnecting...") await self.async_connect(True) except: #NOSONAR # pylint: disable=W0702 pass
async def int_op(self, path, command, param): ''' 显式调用,传入operator,command 和参数,适合REST格式。参数必须时command接受的Json格式 无需认证 ''' p = path + ":" + command log.debug(OP_INFO, p, param) if p in self.commands: h = self.commands[p] return await h(param) return result(404, NOT_FOUND % p)
async def monitor(self): ''' 清理非法连接 ''' log.debug("BLE connection monitor") while True: try: sleep(1) self.check_auth() except: # NOSONAR # pylint: disable=W0702 pass
async def produce(self, q): ''' 产生传感器数据,发送到处理队列 ''' log.debug("Start sensor data producer: %s", self.__name) from uasyncio import sleep_ms while True: try: vals = await self.async_sensor_values() log.debug("Get sensor data") await q.put(vals) await sleep_ms(self.__interval) except BaseException as e: log.warning("Get sensor data failed: %r", e)
def _parse(self): try: bs = self.read() log.debug("Read data: %s", bs) d = bs.decode().strip() json = loads(d) if ENCRYPTED_INPUT: # 处理加密 st = Sec() json = st.dec_payload(json) if TOKEN not in json: return None, json return json[TOKEN], json except BaseException as e: log.debug("Invalid request: %s" , e) return None, None
async def op_request(self, req, req_auth=True): ''' 处理类似Json的请求,只使用List/Dict/基础类型 ''' log.debug("Req: %r", req) if COMMAND not in req or PATH not in req or ARGS not in req: log.debug("Invalid request, no path/cmd/args property.") return result(400, 'Invalid request, no path/cmd/args property.') cmd = req[COMMAND] path = req[PATH] p = req[ARGS] t = None if req_auth and TOKEN in req: t = req[TOKEN] return await self.op(t, path, cmd, p, req_auth)
async def __loop(self): old_msg = None log.debug("Start mqtt loop") while True: try: if self.is_connected(): old_msg = await self.__int_pub(old_msg) self.__int_sub() self.__keep_alive() else: while not self.is_connected(): self.connect() await sleep(RECONNECT_INTERVAL) except: #pylint: disable=bare-except self.__connected = False # 指示连接错误 await sleep(SLEEP_INTERVAL)
def publish(self, ret, retain = False, qos = 0, topic = None): t = None try: ret['i'] = DEVICE_NAME if topic is None: t = self.config_item(TOPIC) else: t = topic if t is None: log.debug("None topic, ignored") return log.debug("Add msg to pub queue: topic: %s, %r ", t, ret) l = {'t': bytes(t, 'utf-8'), 'm': bytes(dumps(ret), 'utf-8'), 'r': retain, 'q': qos} self.__pub_queue.put_nowait(l) except BaseException as e: log.error("Publish to topic %s failed: %r", t, e)
def _irq(self, event, data): # Track connections so we can send notifications. if event == _IRQ_CENTRAL_CONNECT: conn_handle, _, _ = data self._connections[conn_handle] = 0 log.debug("New connection") elif event == _IRQ_CENTRAL_DISCONNECT: conn_handle, _, _ = data log.debug("Disconnected") if conn_handle in self._connections: del self._connections[conn_handle] # Start advertising again to allow a new connection. self._advertise() elif event == _IRQ_GATTS_WRITE: conn_handle, value_handle = data if conn_handle in self._connections and value_handle == self._rx_handle: self._rx_buffer += self._ble.gatts_read(self._rx_handle) self._handle()
async def __int_pub(self, o): '''从旧消息或队列里读取,如果qos大于0,且失败,返回未发送得消息''' while True: m = self.__next(o) if m is None: return None qos = 0 try: qos = m['q'] if self.is_connected(): log.debug("Publish msg %r", m) self.__client.publish(m['t'], m['m'], m['r']) self.__last_ping_tm = time() return None except BaseException as e: log.debug("Publish error: %r", e) self.__connected = False if qos > 0: return m return None
def __callback(self, b): log.debug("IRQ data: %r", b) state = disable_irq() tm = ticks_ms() log.debug("tm: %d, old: %d, %gap", tm, self.ticks, self.cool_down_gap) if tm > self.ticks + self.cool_down_gap: self.ticks = tm try: self._get_data(b) if self.handler is not None: log.debug("Call handler") schedule(self.handler, self.__handler_data) if self.queue is not None: log.debug("Send sensor data to queue") create_task(self.queue.put(self.__handler_data)) sleep_ms(self.interval) except BaseException as e: # NOSONAR log.error("Excetion while check and call irq handler: %r", e) enable_irq(state)
async def __add_one_time_job(self, c): log.debug("Add one time job: %s", c) self.__create_scheduler(c, True) return result()
def write(self, data, authed = False): for conn_handle in self._connections: if not authed or self._connections[conn_handle] < 0: log.debug("Send data: %s", data) self._ble.gatts_notify(conn_handle, self._tx_handle, data)