def delete(self,ctx=None): self.server.stop_gevent() self.server = None if self.evt is not None: self.evt.delete() super(QBconn,self).delete() simple_event("qbroker","disconnect",*self.name)
def _reporter(self, id): # log(DEBUG,"OFFSpoller report",repr(id)) id = id.lower() if id not in devices: if id not in self.seen_new: self.seen_new.add(id) simple_event("onewire", "alarm", "new", bus=self.bus.bus.name, path=self.path, id=id) return # not yet known, presumably on next scan if id in self.seen_new: self.seen_new.remove(id) if id not in self.seen: self.seen.add(id) simple_event("onewire", "alarm", "state", id, bus=self.bus.bus.name, path=self.path, id=id, state="on") elif id in self.old_seen: self.old_seen.remove(id)
def lineReceived(self, data): db = "" e = "" if not data: return # empty line if data[0] in PREFIX: for d in data[1:]: if e: try: db += chr(eval("0x" + e + d)) except SyntaxError: simple_event("fs20", "unknown", "hex", data=data) return e = "" else: e = d if e: log("fs20", WARN, "fs20 odd length " + data) self.datagramReceived(data[0], db, timestamp=self.timestamp) self.timestamp = None elif data[0] == PREFIX_TIMESTAMP: self.timestamp = float(data[1:]) elif data[0] == "P": pass # idle elif data[0] == "+": log("fs20", DEBUG, "fs20 trace " + data) else: simple_event("fs20", "unknown", "prefix", prefix=data[0], data=data[1:])
def lineReceived(self,data): db = "" e = "" if not data: return # empty line if data[0] in PREFIX: for d in data[1:]: if e: try: db += chr(eval("0x"+e+d)) except SyntaxError: simple_event("fs20","unknown","hex", data=data) return e="" else: e=d if e: log("fs20",WARN,"fs20 odd length "+data) self.datagramReceived(data[0], db, timestamp=self.timestamp) self.timestamp = None elif data[0] == PREFIX_TIMESTAMP: self.timestamp = float(data[1:]) elif data[0] == "P": pass # idle elif data[0] == "+": log("fs20",DEBUG,"fs20 trace "+data) else: simple_event("fs20","unknown","prefix", prefix=data[0],data=data[1:])
def get(self, state, ext=None, handler=None): simple_event("fs20", "state", *self.name, state=state, ext=ext) ctx = Context(value=state) if ext is not None: ctx.ext = ext simple_event(ctx, "input", "fs20", *self.name)
def datagramReceived(self, prefix, data, handler=None, timestamp=None): try: ext = PREFIX[prefix] except KeyError: simple_event("fs20", "unknown", "prefix", prefix=prefix, data=data) else: return ext.datagramReceived(self.ctx, data, handler, timestamp)
def run(self, ctx, **k): event = self.params(ctx) if not len(event): raise SyntaxError(u"Usage: state ‹name…›") s = self.coll(*event) s.working = True try: if hasattr(self, "value") and s.value is None: s.set_value(self.value) s.time = now() if s.value is None and self.trigger \ or s.value is not None and self.ptrigger: old = s.old_value if s.old_value is not None else "-" val = s.value if val is None: val = "-" simple_event("state", "new", *s.name, value=self.value, prev_value=old) except BaseException: s.delete() raise finally: s.working = False
def on_disconnect(self): simple_event("rpc","disconnect",*self.name) if self.workers is not None: for w in self.workers: unregister_worker(w) self.workers = None super(RPCconn,self).delete()
def delete(self, ctx=None): self.conn.close() self.conn = None self.stop_job("job") simple_event("amqp", "disconnect", *self.name, deprecated=True) simple_event("amqp", "state", *self.name, state="disconnect") super(AMQPclient, self).delete()
def delete(self,ctx=None): self.conn.close() self.conn = None self.stop_job("job") simple_event("amqp","disconnect",*self.name, deprecated=True) simple_event("amqp","state",*self.name, state="disconnect") super(AMQPclient,self).delete()
def on_disconnect(self): simple_event("rpc", "disconnect", *self.name) if self.workers is not None: for w in self.workers: unregister_worker(w) self.workers = None super(RPCconn, self).delete()
def delete(self, ctx=None): self.server.stop_gevent() self.server = None if self.evt is not None: self.evt.delete() super(QBconn, self).delete() simple_event("qbroker", "disconnect", *self.name)
def retime(self, dest): simple_event("wait","update",*self.name,dest=dest, loglevel=TRACE, deprecated=True) simple_event("wait","state",*self.name, end_time=dest, loglevel=TRACE, state="update") with log_wait("wait","delete1",self.name): with self._lock: self.end = dest self._set_pling()
def get(self, state, ext=None, handler=None): simple_event("fs20","state", *self.name, state=state, ext=ext) ctx = Context(value=state) if ext is not None: ctx.ext = ext simple_event(ctx, "input","fs20", *self.name)
def recv(self, msg): if msg.type is MT_MULTILINE: for x in msg.msg: if x == "": continue m = _num.match(x) if m is None: continue mon = int(m.group(0)) self.data[mon] = x[m.end():] recvs, self.queue.receivers = self.queue.receivers, [] for r in recvs: mid = getattr(r, "msgid", None) if mid is None or mid in self.data: log("wago", TRACE, "found monitor", r) self.queue.receivers.append(r) else: try: raise DroppedMonitor(mid) except DroppedMonitor as ex: fix_exception(ex) res = r.error(ex) if res is SEND_AGAIN: log("wago", TRACE, "retry monitor", r) self.queue.enqueue(r) else: log("wago", TRACE, "drop monitor", r) assert res is None or res is False, "%s.error returned %s" % ( repr(r), repr(res)) return MINE if msg.type is MT_NAK or msg.type is MT_ERROR: simple_event("wago", "monitor", "error", msg=msg.msg) return MINE return NOT_MINE
def datagramReceived(self, prefix, data, handler=None, timestamp=None): try: ext = PREFIX[prefix] except KeyError: simple_event("fs20","unknown","prefix",prefix=prefix,data=data) else: return ext.datagramReceived(self.ctx, data, handler, timestamp)
def recv(self,msg): if msg.type is MT_MULTILINE: for x in msg.msg: if x == "": continue m = _num.match(x) if m is None: continue mon = int(m.group(0)) self.data[mon]=x[m.end():] recvs,self.queue.receivers = self.queue.receivers,[] for r in recvs: mid = getattr(r,"msgid",None) if mid is None or mid in self.data: log("wago",TRACE,"found monitor",r) self.queue.receivers.append(r) else: try: raise DroppedMonitor(mid) except DroppedMonitor as ex: fix_exception(ex) res = r.error(ex) if res is SEND_AGAIN: log("wago",TRACE,"retry monitor",r) self.queue.enqueue(r) else: log("wago",TRACE,"drop monitor",r) assert res is None or res is False, "%s.error returned %s"%(repr(r),repr(res)) return MINE if msg.type is MT_NAK or msg.type is MT_ERROR: simple_event("wago","monitor","error", msg=msg.msg) return MINE return NOT_MINE
def _start(self): reported = False while True: sleep(self.freq) try: self.time_start = now() self.old_seen = self.seen.copy() # log(DEBUG,"SCAN",self.path,"IN",self.bus) self.bus.dir(path=self.path+('alarm',), proc=self._reporter, cached=False) for id in self.old_seen: simple_event("onewire","alarm","state",id, bus=self.bus.bus.name, path=self.path, id=id, state="off") self.seen.remove(id) except Exception as e: self.last_error = e if not reported: reported = True fix_exception(e) process_failure(e) self.time_len = now()-self.time_start sleep(self.freq*10) else: reported = False self.time_len = now()-self.time_start for x in self.simul: x[0] += 1 if x[0] >= x[1]: x[0] = 0 self.bus.set(self.path+('simultaneous',x[2]),x[3])
def em_proc_thermo_hygro(ctx, data): if len(data) != 7: simple_event("fs20","em","bad_length","thermo_hygro",len=len(data),data=data) return None temp = data[1]/10 + data[2] + data[3]*10 if data[0] & 8: temp = -temp hum = data[4]/10 + data[5] + data[6]*10 return {"temperature":temp, "humidity":hum}
def go_down(self, _=None): if not self.is_up: return self.is_up = False if _ is not None: process_failure(_) simple_event("onewire","down",typ=self.typ,id=self.id,bus=self.bus.name,path=self.path, deprecated=True) simple_event("onewire","device","state",self.id, typ=self.typ,id=self.id,bus=self.bus.name,path=self.path, state="down")
def not_up_event(self, external=False, error=None): simple_event("fs20", "avr", "error", *self.name, deprecated=True) simple_event("fs20", "avr", "state", *self.name, state="error", error=error)
def _rewrite(self, wval, wnextval): res = self.timer.q.get() if isinstance(res, BaseException): reraise(res) simple_event("output", "change", *self.name, prev_value=self.repr(wval), value=self.repr(wnextval))
def tx_proc_hygro(ctx, data): if len(data) != 7: simple_event("fs20","tx","bad_length","hygro",len=len(data),data=data) return None if data[2] != data[5] or data[3] != data[6]: simple_event("fs20","tx","bad_repeat","hygro",data=data) return None hum = data[2]*10 + data[3] + data[4]/10 return {"humidity":hum}
def tx_proc_thermo(ctx, data): if len(data) != 7: simple_event("fs20","tx","bad_length","thermo",len=len(data),data=data) return None if data[2] != data[5] or data[3] != data[6]: simple_event("fs20","tx","bad_repeat","thermo",data=data) return None temp = data[2]*10 + data[3] + data[4]/10 -50 return {"temperature":temp}
def on_connect(self): global conn_seq conn_seq += 1 self.name = self.dest + ("n"+str(conn_seq),) self.ctx = Context() self.ctx.out = Reporter(self) self.ctx.words = global_words(self.ctx) self.workers = set() simple_event("rpc","connect",*self.name) Collected.__init__(self)
def on_connect(self): global conn_seq conn_seq += 1 self.name = self.dest + ("n" + str(conn_seq), ) self.ctx = Context() self.ctx.out = Reporter(self) self.ctx.words = global_words(self.ctx) self.workers = set() simple_event("rpc", "connect", *self.name) Collected.__init__(self)
def delete(self,ctx=None): if self.working: raise StateChangeError(self,u"‹deleted›") self.working = True self.time = now() try: if self.value is not None: simple_event("state","delete",*self.name, prev_value=self.value) finally: super(State,self).delete()
def error(self, err): log("wago", DEBUG, "Got error", self, err) simple_event("output", "error", *self.queue.name, value=self.val, error=err) if not self.result.ready(): self.result.set(err) super(WAGOtimedOutputRun, self).error(err)
def one_value(self, step): """\ Get one value from some "set monitor" command. Override this for active monitoring. """ if self.send_check_event and step==1: simple_event(self.ectx, "monitor","checking",*self.name) with log_wait("monitor","one_value",*self.name): return self.watcher.get(block=True, timeout=None)
def do_post(self): self.slotter = None if self.running != "during" or self.waiter is not None: log(ERROR,"timeslot error post",self.running,*self.name) return self.running = "next" simple_event("timeslot","end",*self.name, deprecated=True) simple_event("timeslot","state",*self.name, state="end") self.next = time_delta(self.interval, now=self.next)-dt.timedelta(0,self.duration) self.waiter = callLater(False, self.next, self.do_pre)
def event(self,ctx,data): d={} for m,n in data.items(): try: n = n * self.faktor[m] except KeyError: pass try: n = n + self.offset[m] except KeyError: pass d[m]=n simple_event("fs20","em", *self.name, **d) self.last = now() self.last_data = data
def delete(self,ctx=None): if self.timer: self.timer.cancel() self.timer = None try: if self.state: simple_event("pwm","change",*self.name, value=0) except Exception as ex: fix_exception(ex) process_failure(ex) finally: super(CommonPM,self).delete()
def not_up_event(self, external=False, error=None): simple_event("onewire", "error", *self.name, error=error, deprecated=True) simple_event("onewire", "link", "state", *self.name, state="error", error=error)
def tell(self, s, i): d = self['%s.%s' % (s, i)] if d != "": simple_event('moat', 'update', self.name, s, i, value=d, name=self.name, subsys=s, part=i)
def event(self,ctx,data): d={} for m,n in data.items(): try: n = n * self.faktor[m] except KeyError: pass try: n = n + self.offset[m] except KeyError: pass d[m]=n simple_event("fs20","tx", *self.name, **d) self.last = now() self.last_data = data
def delete(self, ctx=None): if self.working: raise StateChangeError(self, u"‹deleted›") self.working = True self.time = now() try: if self.value is not None: simple_event("state", "delete", *self.name, prev_value=self.value) finally: super(State, self).delete()
def on_info_msg(self,msg): if not self._direct and not TESTING and getattr(msg,'message_id','').startswith(base_mseq): return # dup typ = getattr(msg,'content_type','') try: codec = get_codec(typ) data = codec.decode(msg.body) except Exception as e: data = { "raw": msg.body, "content_type": typ, "error": e } self.last_recv = msg.__dict__ if 'timestamp' not in data: data['timestamp'] = now() simple_event(*(self.prefix+tuple(msg.routing_key.split('.')[self.strip:])), _direct=self._direct, **data)
def datagramReceived(self, data, handler=None, timedelta=None): if len(data) < 2: raise WrongDatagram(data) if self.last_dgram is not None and timedelta is not None and \ self.last_dgram == data and timedelta < 0.15: return self.last_dgram = data fcode = ord(data[1]) if fcode & 0x20: if len(data) < 3: raise WrongDatagram(data) ext = ord(data[2]) else: if len(data) < 2: raise WrongDatagram(data) ext = None dc = ord(data[0]) try: dev = self.devs[dc] except KeyError: simple_event("fs20", "unknown", "device", homecode=self.code, device=dc, data=data) return try: fn = switch_names[fcode & 0x1F] except KeyError: simple_event("fs20", "unknown", "function", homecode=self.code, device=dc, fcode=fcode & 0x1F, data=data) return if fcode & 0x80: hdl = dev.getReply else: hdl = dev.get if ext is not None: hdl(fn, ext, handler=handler) else: hdl(fn, handler=handler) data = chr(dc) + chr(fcode | 0x80) + data[2:] self.send(data, handler)
def process(self, event, **k): dev = event.ctx.id if not dev.startswith('f0.'): return name = devices[dev].get('config/name') seq = 0 n = name while n in Moats: if Moats[n].dev == dev: return # dup seq += 1 n = "%s.%d" % (name, seq) Moat(name=n, dev=dev) simple_event(event.ctx, "moat", "new", n, dev=dev)
def tx_proc_thermo(ctx, data): if len(data) != 7: simple_event("fs20", "tx", "bad_length", "thermo", len=len(data), data=data) return None if data[2] != data[5] or data[3] != data[6]: simple_event("fs20", "tx", "bad_repeat", "thermo", data=data) return None temp = data[2] * 10 + data[3] + data[4] / 10 - 50 return {"temperature": temp}
def tx_proc_hygro(ctx, data): if len(data) != 7: simple_event("fs20", "tx", "bad_length", "hygro", len=len(data), data=data) return None if data[2] != data[5] or data[3] != data[6]: simple_event("fs20", "tx", "bad_repeat", "hygro", data=data) return None hum = data[2] * 10 + data[3] + data[4] / 10 return {"humidity": hum}
def __init__(self, name, host, port, vhost, username, password): self.name = name self.host = host self.port = port self.vhost = vhost self.username = username self.password = password self.workers = [] try: self.conn = amqp.connection.Connection(host=self.host, userid=self.username, password=self.password, login_method='AMQPLAIN', login_response=None, virtual_host=self.vhost) except Exception as ex: simple_event("amqp", "error", *name, error=str(ex), deprecated=True) simple_event("amqp", "state", *name, error=str(ex), state="error") fix_exception(ex) process_failure(ex) else: super(AMQPclient, self).__init__() simple_event("amqp", "connect", *name, deprecated=True) simple_event("amqp", "state", *name, state="connect")
def process(self, event,**k): dev = event.ctx.id if not dev.startswith('f0.'): return name = devices[dev].get('config/name') seq = 0 n = name while n in Moats: if Moats[n].dev == dev: return # dup seq += 1 n = "%s.%d" % (name,seq) Moat(name=n,dev=dev) simple_event(event.ctx, "moat","new",n, dev=dev)
def up(self): with log_wait("monitor up "+repr(self)): while self.job and self.job.dead: gevent.sleep(0.1) # link will clear if not self.job: self.value = None simple_event("monitor","start",*self.name) self.start_job("job",self._run_loop) self.state_change_at = now() def tell_ended(_): simple_event("monitor","stop",*self.name) self.job.link(tell_ended)
def do_pre(self): self.waiter = None if self.running != "next" or self.slotter is not None: log(ERROR,"timeslot error pre",self.running,*self.name) return if self.next is None: self.next = now() self.last = self.next self.running = "during" simple_event("timeslot","begin",*self.name, deprecated=True) simple_event("timeslot","state",*self.name, state="begin") self.next += dt.timedelta(0,self.duration) self.slotter = callLater(False,self.next, self.do_post)
def _reporter(self, id): # log(DEBUG,"OFFSpoller report",repr(id)) id = id.lower() if id not in devices: if id not in self.seen_new: self.seen_new.add(id) simple_event("onewire","alarm","new", bus=self.bus.bus.name, path=self.path, id=id) return # not yet known, presumably on next scan if id in self.seen_new: self.seen_new.remove(id) if id not in self.seen: self.seen.add(id) simple_event("onewire","alarm","state",id, bus=self.bus.bus.name, path=self.path, id=id, state="on") elif id in self.old_seen: self.old_seen.remove(id)
def _loop(self): simple_event("amqp","start",*self.name, _direct=True, deprecated=True) simple_event("amqp","state",*self.name, _direct=True, state="up") try: while True: self.conn.drain_events() finally: simple_event("amqp","stop",*self.name, _direct=True, deprecated=True) simple_event("amqp","state",*self.name, _direct=True, state="down")
def retime(self, dest): simple_event("wait", "update", *self.name, dest=dest, loglevel=TRACE, deprecated=True) simple_event("wait", "state", *self.name, end_time=dest, loglevel=TRACE, state="update") with log_wait("wait", "delete1", self.name): with self._lock: self.end = dest self._set_pling()
def event(self,ctx,data): d={} for m,n in data.items(): try: n = n * self.faktor[m] except KeyError: pass else: data[m] = n if self.delta is not None: if self.last_data: val = n-self.last_data[m] if val < 0: val = val + 0x10000 # 16-bit rollover if val >= 0 or self.delta == 0: d[m]=val else: d[m]=n simple_event("fs20","en", *self.name, **d) self.last = now() self.last_data = data
def dataReceived(self, ctx, data, handler=None, timedelta=None): if len(data) < 4: return # obviously way too short qs = 0 for d in data: qs += ord(d) qs -= ord(data[-1]) # the above loop added it, that's nonsense qs = (ord(data[-1]) - qs) & 0xFF # we want the actual difference code = ord(data[0])*256+ord(data[1]) try: g = groups[(code,qs)] except KeyError: simple_event("fs20","unknown","hc", hc=to_hc(code),checksum=qs,data=data) else: return g.datagramReceived(data[2:-1], handler, timedelta=timedelta)
def recv(self, msg): if msg.type is MT_IND_ACK and self.msgid is None: self.msgid = msg.msgid return RECV_AGAIN if msg.type is MT_IND and msg.msgid == self.msgid: self.ping_start() self.last_recv = now(True) return RECV_AGAIN if msg.type is MT_IND_NAK and msg.msgid == self.msgid: if self.ping_timer is not None: self.ping_timer.cancel() self.ping_timer = None simple_event("wago", "ping", "cancel", msg=msg.msg) return MINE if (msg.type is MT_NAK or msg.type is MT_ERROR) and self.msgid is None: simple_event("wago", "ping", "error", msg=msg.msg) return MINE return NOT_MINE
def run(self,ctx,**k): event = self.params(ctx) if len(event) < 2: raise SyntaxError(u"Usage: set state ‹value› ‹name…›") value = event[0] name = Name(*event[1:]) s = States[name] old = s.value if old is None: old = "-" if value == old: return # no change! s.old_value = s.value s.set_value(value if value != "-" else None) tm = s.time s.time = now() simple_event("state","change",*s.name, prev_value=old,value=value,prev_time=tm)
def recv(self,msg): if msg.type is MT_IND_ACK and self.msgid is None: self.msgid = msg.msgid return RECV_AGAIN if msg.type is MT_IND and msg.msgid == self.msgid: self.ping_start() self.last_recv = now(True) return RECV_AGAIN if msg.type is MT_IND_NAK and msg.msgid == self.msgid: if self.ping_timer is not None: self.ping_timer.cancel() self.ping_timer = None simple_event("wago","ping","cancel", msg=msg.msg) return MINE if (msg.type is MT_NAK or msg.type is MT_ERROR) and self.msgid is None: simple_event("wago","ping","error", msg=msg.msg) return MINE return NOT_MINE
class Output(CommonIO): """This represents a single output.""" storage = Outputs.storage last_value = None timer = None timing = OutTimer _tmwrite = None typ = "???output" def list(self): yield super(Output, self) if self.last_value is not None: yield ("last write", self.last_time) yield ("last value", self.last_value) def _write(self, val): """Write an output. Override this.""" raise NotImplementedError("You need to override %s._write()" % (self.__class__.__name__, )) def write(self, val, timer=None, nextval=None, async=False): """Read an input, check range.""" self.check(val) if nextval is not None: self.check(nextval) wnextval = self.trans(nextval) else: wnextval = None wval = self.trans(val) if self.timer is not None: # and (self.last_value != wval or timer is not None): ## ? self.timer.cancel() self.timer = None if self.last_value != wval: simple_event("output", "change", *self.name, prev_value=self.last_value, value=self.repr(wval)) self.last_value = wval self.last_time = now() if timer is None: self._write(wval) else: self.timer = self.timing(self, timer, nextval) if self._tmwrite is not None: self._tmwrite(wval, self.timer, wnextval) else: self._write(wval) if async: gevent.spawn(self._rewrite_ex, wval, wnextval) else: self._rewrite(wval, wnextval)
def on_info_msg(self, msg): if not self._direct and not TESTING and getattr( msg, 'message_id', '').startswith(base_mseq): return # dup typ = getattr(msg, 'content_type', '') try: codec = get_codec(typ) data = codec.decode(msg.body) except Exception as e: data = {"raw": msg.body, "content_type": typ} if typ: data['error'] = e self.last_recv = msg.__dict__ if 'timestamp' not in data: data['timestamp'] = now() simple_event(*(self.prefix + tuple(msg.routing_key.split('.')[self.strip:])), _direct=self._direct, **data)
def do_switch(self): """Click""" if self.state: self.state = 0 tn = self.t_off else: self.state = 1 tn = self.t_on simple_event("pwm","change",*self.name, value=self.state) try: self.last = self.next if tn is not None: self.next = self.last + dt.timedelta(0,tn) self.timer = callLater(False,self.next,self.do_timed_switch) else: self.next = None except Exception as e: fix_exception(e) process_failure(e) simple_event("pwm","error",*self.name, error=e)
def run(self,ctx,**k): event = self.params(ctx) if not len(event): raise SyntaxError(u"Usage: state ‹name…›") s = self.coll(*event) s.working = True try: if hasattr(self,"value") and s.value is None: s.set_value(self.value) s.time = now() if s.value is None and self.trigger \ or s.value is not None and self.ptrigger: old = s.old_value if s.old_value is not None else "-" val = s.value if val is None: val = "-" simple_event("state","new",*s.name, value=self.value, prev_value=old) except BaseException: s.delete() raise finally: s.working = False