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 info(self): if self.running not in ("off","error"): tm = unixdelta(self.next-now()) elif self.last is not None: tm = unixdelta(now()-self.last) else: tm = "never" return "%s %s" % (self.running,tm)
def time_int(self): if self.started_at is None: return None if not self.running.is_set(): delta = now() - self.started_at elif self.job: delta = self.started_at - now() else: delta = now() - self.started_at return unixdelta(delta)
def time_name(self): if self.started_at is None: return "never" if not self.running.is_set(): delta = now() - self.started_at elif self.job: delta = self.started_at - now() else: delta = now() - self.started_at delta = unixdelta(delta) res = humandelta(delta) return u"‹"+res+"›"
def exposed_cmd_list(self, *args): # don't call this 'exposed_list'! c = get_collect(args, allow_collection=True) try: if c is None: for m in all_collect(skip=False): yield m.name, elif isinstance(c, Collection): if args[-1] == "*": for n, m in c.items(): yield n, m return for n, m in c.items(): try: m = m.info except AttributeError: m = m.name else: if callable(m): m = m() if isinstance(m, six.string_types): m = m.split("\n")[0].strip() if m is not None: yield (n, m) else: yield n, else: for p, t in flatten((c, )): if isinstance(t, datetime): if TESTING: if t.year != 2003: t = "%s" % (humandelta(t - now(t.year != 2003)), ) else: t = "%s (%s)" % ( humandelta(t - now(t.year != 2003)), t) ti = t.rfind('.') if ti > 0 and len(t) - ti > 3 and len( t) - ti < 9: # limit to msec t = t[:ti + 3] + ")" # otherwise transmit the datetime as-is elif not isinstance(t, (date, time, timedelta)): t = six.text_type(t) yield p, t except Exception as e: fix_exception(e) yield "* ERROR *", repr(e) process_failure(e)
def _list(self, args=(), **kw): c = get_collect(args, allow_collection=True) res = [] if c is None: for m in all_collect(skip=False): res.append((m.name, )) elif isinstance(c, Collection): if args[-1] == "*": for n, m in c.items(): res.append((n, m)) return for n, m in c.items(): try: m = m.info except AttributeError: m = m.name else: if callable(m): m = m() if isinstance(m, str): m = m.split("\n")[0].strip() if m is not None: res.append((n, m)) else: res.append((n, )) else: q = Queue(3) job = spawn(flatten, q, (c, )) job.link(lambda _: q.put(None)) for p, t in flatten((c, )): if isinstance(t, datetime): if moat.TESTING: if t.year != 2003: t = "%s" % (humandelta(t - now(t.year != 2003)), ) else: t = "%s (%s)" % ( humandelta(t - now(t.year != 2003)), t) ti = t.rfind('.') if ti > 0 and len(t) - ti > 3 and len( t) - ti < 9: # limit to msec t = t[:ti + 3] + ")" # otherwise transmit the datetime as-is elif not isinstance(t, (date, time, timedelta)): t = str(t) res.append((p, t)) return res
def exposed_cmd_list(self,*args): # don't call this 'exposed_list'! c = get_collect(args, allow_collection=True) try: if c is None: for m in all_collect(skip=False): yield m.name, elif isinstance(c,Collection): if args[-1] == "*": for n,m in c.items(): yield n,m return for n,m in c.items(): try: m = m.info except AttributeError: m = m.name else: if callable(m): m = m() if isinstance(m,six.string_types): m = m.split("\n")[0].strip() if m is not None: yield (n,m) else: yield n, else: for p,t in flatten((c,)): if isinstance(t,datetime): if TESTING: if t.year != 2003: t = "%s" % (humandelta(t-now(t.year != 2003)),) else: t = "%s (%s)" % (humandelta(t-now(t.year != 2003)),t) ti = t.rfind('.') if ti>0 and len(t)-ti > 3 and len(t)-ti<9: # limit to msec t= t[:ti+3]+")" # otherwise transmit the datetime as-is elif not isinstance(t,(date,time,timedelta)): t = six.text_type(t) yield p,t except Exception as e: fix_exception(e) yield "* ERROR *",repr(e) process_failure(e)
def __init__(self,parent,name, names=("off","on"), **k): self.ctx = parent.ctx self.start = now() self.names = names for a,b in k.items(): self.arg(a,b) self.validate() super(CommonPM,self).__init__(*name)
def list(self): n = now() yield super(OutTimer,self) yield ("output",self.parent.name) yield ("start", self.started) yield ("end", self.end) yield ("next value",self.val)
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 _do_measure(self): log("monitor",TRACE,"Start run",self.name) try: self.running.clear() self.started_at = now() self._monitor() if self.send_check_event: simple_event(self.ectx, "monitor","checked",*self.name) if self.new_value is not None: self.last_value = self.value self.value = self.new_value if hasattr(self,"delta"): if self.last_value is not None: val = self.value-self.last_value self._ectx.value_delta = val if val >= 0 or self.delta == 0: simple_event(self.ectx,"monitor","update",*self.name) else: simple_event(self.ectx,"monitor","update",*self.name) except Exception as e: fix_exception(e) process_failure(e) finally: log("monitor",TRACE,"Stop run",self.name) self.running.set() self._schedule()
def list(self): n = now() yield super(OutTimer, self) yield ("output", self.parent.name) yield ("start", self.started) yield ("end", self.end) yield ("next value", self.val)
def _list(self, args=(), **kw): c = get_collect(args, allow_collection=True) res = [] if c is None: for m in all_collect(skip=False): res.append(( m.name,)) elif isinstance(c,Collection): if args[-1] == "*": for n,m in c.items(): res.append(( n,m )) return for n,m in c.items(): try: m = m.info except AttributeError: m = m.name else: if callable(m): m = m() if isinstance(m,str): m = m.split("\n")[0].strip() if m is not None: res.append(( n,m )) else: res.append(( n, )) else: q = Queue(3) job = spawn(flatten,q,(c,)) job.link(lambda _:q.put(None)) for p,t in flatten((c,)): if isinstance(t,datetime): if moat.TESTING: if t.year != 2003: t = "%s" % (humandelta(t-now(t.year != 2003)),) else: t = "%s (%s)" % (humandelta(t-now(t.year != 2003)),t) ti = t.rfind('.') if ti>0 and len(t)-ti > 3 and len(t)-ti<9: # limit to msec t= t[:ti+3]+")" # otherwise transmit the datetime as-is elif not isinstance(t,(date,time,timedelta)): t = str(t) res.append(( p,t )) return res
def read(self): """Read an output, check range.""" res = self._read() res = self.repr(res) self.check(res) self.last_time = now() self.last_value = res return res
def weigth(self, mod=False): if self.value_tm is None: return None t = now() - self.value_tm nt = unixdelta(t) if nt == 0: ## called right after init'ing return 0 else: return 1 - (1 - self.p)**(nt / self.p_base)
def weigth(self, mod=False): if self.value_tm is None: return None t = now()-self.value_tm nt = unixdelta(t) if nt == 0: ## called right after init'ing return 0 else: return 1-(1-self.p)**(nt/self.p_base)
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 feed(self, value): self.prev_value = self.value if value is None: value = self.value if value is None: return self.value = value self.value_tm = now() self.total_samples += 1 self.avg = self._calc(True)
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 sleepUntil(force,delta): from moat.times import unixdelta,now,sleep if isinstance(delta,dt.datetime): delta = delta - now() if isinstance(delta,dt.timedelta): delta = unixdelta(delta) if delta < 0: # we're late delta = 0 # but let's hope not too late sleep(force,delta)
def report(self, verbose=False): if self.name: yield "WORK: "+self.name if self.id: yield "id: "+str(self.id) yield "call count: "+str(self.call_count) if self.last_call: yield "last call: %s (%s)" % (humandelta(now()-self.last_call),self.last_call) if self.last_args: for a,b in self.last_args.items(): yield "last %s: %s" % (a,b)
def __init__(self,parent,name,force,soft=None): self.ctx = parent.ctx self.start = now() self.force = force self.soft = soft self._lock = Semaphore() try: self.parent = parent.parent except AttributeError: pass super(Waiter,self).__init__(name)
def __init__(self, parent, name, force, soft=None): self.ctx = parent.ctx self.start = now() self.force = force self.soft = soft self._lock = Semaphore() try: self.parent = parent.parent except AttributeError: pass super(Waiter, self).__init__(name)
def out_one(c): for p,t in flatten((c,)): if isinstance(t,datetime): if TESTING and t.year != 2003: t = "%s" % (humandelta(t-now(t.year != 2003)),) else: t = "%s (%s)" % (humandelta(t-now(t.year != 2003)),t) if TESTING: lim = 3 else: lim = 4 ti = t.rfind('.') if ti>0 and len(t)-ti>lim and len(t)-ti<lim+6: # limit to msec t = t[:ti+lim]+")" elif isinstance(t,float): ft=float("%.4f"%t) if abs(ft-t)<0.00000001: t=ft print(p+u": "+six.text_type(t), file=self.ctx.out)
def sleepUntil(force, delta): from moat.times import unixdelta, now, sleep if isinstance(delta, dt.datetime): delta = delta - now() if isinstance(delta, dt.timedelta): delta = unixdelta(delta) if delta < 0: # we're late delta = 0 # but let's hope not too late sleep(force, delta)
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 report(self, verbose=False): if self.name: yield "WORK: " + self.name if self.id: yield "id: " + str(self.id) yield "call count: " + str(self.call_count) if self.last_call: yield "last call: %s (%s)" % (humandelta(now() - self.last_call), self.last_call) if self.last_args: for a, b in self.last_args.items(): yield "last %s: %s" % (a, b)
def list(self): yield super(Timeslot,self) yield ("run",self.running) if self.interval is not None: yield ("interval"," ".join(str(x) for x in self.interval)) yield ("duration",self.duration) if self.last is not None: yield ("last",self.last) if self.next is not None: yield ("next",self.next) if self.slotter is not None: yield ("slot",(unixdelta(self.next-now()))/self.duration)
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 weigth(self, mod=False): if self.value_tm is None: return None n = now() t = n-self.value_tm nt = self.total_tm+t nts = unixdelta(nt) if mod: self.total_tm = nt if nts == 0: ## called right after init'ing return 0 else: return unixdelta(t) / nts
def out_one(c): for p, t in flatten((c, )): if isinstance(t, datetime): if TESTING and t.year != 2003: t = "%s" % (humandelta(t - now(t.year != 2003)), ) else: t = "%s (%s)" % (humandelta(t - now(t.year != 2003)), t) if TESTING: lim = 3 else: lim = 4 ti = t.rfind('.') if ti > 0 and len(t) - ti > lim and len( t) - ti < lim + 6: # limit to msec t = t[:ti + lim] + ")" elif isinstance(t, float): ft = float("%.4f" % t) if abs(ft - t) < 0.00000001: t = ft print(p + u": " + six.text_type(t), file=self.ctx.out)
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 weigth(self, mod=False): if self.value_tm is None: return None n = now() t = n - self.value_tm nt = self.total_tm + t nts = unixdelta(nt) if mod: self.total_tm = nt if nts == 0: ## called right after init'ing return 0 else: return unixdelta(t) / nts
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 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 _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 process(self, event=None, **k): super(EventCallback, self).process(**k) # This is an event monitor. Failures will not be tolerated. try: msg = getattr(event.ctx, 'raw', None) codec = "application/binary" if msg is None: codec = json.CODEC for x, y in event.ctx: if x == 'event': continue if isinstance( y, six.string_types + six.integer_types + (bool, float, list, tuple)): d[x] = y elif hasattr(y, 'name'): d[x] = y.name if 'timestamp' not in d: d['timestamp'] = now() try: msg = json.encode(dict(event=list(event), **d)) except (TypeError, UnicodeDecodeError) as e: msg = json.encode( dict(data=repr(event) + "|" + repr(d) + "|" + repr(e))) elif isinstance(msg, six.integer_types + (float, )): msg = str(msg) codec = "text/plain" elif isinstance(msg, six.string_types): msg = msg.encode("utf-8") codec = "text/plain" global _mseq _mseq += 1 msg = amqp.Message(body=msg, content_type=codec, message_id=base_mseq + str(_mseq)) self.channel.basic_publish( msg=msg, exchange=self.exchange, routing_key=".".join( str(x) for x in self.prefix + tuple(event)[self.strip:])) except Exception as ex: fix_exception(ex) process_failure(ex) try: self.cancel() except Exception as ex: fix_exception(ex) process_failure(ex) raise TrySomethingElse
def feed(self, value): """Store the new value but calculate over the previous ones.""" self.prev_value = self.value self.total_samples += 1 if value is None: value = self.value if value is None: return if self.avg is None: self.avg = value self.total_tm = timedelta(0) else: self._calc(True) self.value = value self.value_tm = now()
def run(self,ctx,**k): event = self.params(ctx) if len(event) < 2: raise SyntaxError(u'Usage: set rrd ‹value› ‹name…›') s = RRDs[Name(*event[1:])] # Using "N:" may run into a RRD bug # if we're really close to the next minute try: rrdtool.update(s.upath, str("-t"),s.udataset, str(now().strftime("%s")+":"+six.text_type(event[0])).encode("utf-8")) except Exception as e: fix_exception(e) if "minimum one second step" in str(e): pass else: raise
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 list(self): n=now() yield super(CommonPM,self) yield ("type",self.type) if self.state is not None: yield ("state",self.names[self.state]) if self._value is not None: yield ("current",self._value) if self.last is not None: yield ("last",self.last) if self.next is not None: yield ("next",self.next) if self.t_off is not None: yield ("t_off",humandelta(self.t_off)) if self.t_on is not None: yield ("t_on",humandelta(self.t_on))
def set_value(self,val=None): if val is None: val = self._value assert 0<=val<=1, u"Value is '%s', not in 0…1" % (val,) do = self.t_on if self.state else self.t_off self.t_off,self.t_on = self.new_value(val) dn = self.t_on if self.state else self.t_off self._value = val if do != dn: if self.timer is not None: self.timer.cancel() if dn is not None: self.next = (self.last if self.last is not None else now()) + dt.timedelta(0,dn) self.timer = callLater(False,self.next,self.do_timed_switch)
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 run(self,ctx,**k): event = self.params(ctx) name = self.dest if name is None: val = (event[0],) name = Name(*event[1:]) else: val = list(event) name = Name(*name.apply(ctx)) rrdf = RRDfiles[name] rrdf.last_sent = val rrdf.last_sent_at = now() msg = RRDsendUpdate(rrdf,val) res = msg.result.get() if isinstance(res,Exception): reraise(res)
def run(self, ctx, **k): event = self.params(ctx) if len(event) < 2: raise SyntaxError(u'Usage: set rrd ‹value› ‹name…›') s = RRDs[Name(*event[1:])] # Using "N:" may run into a RRD bug # if we're really close to the next minute try: rrdtool.update( s.upath, str("-t"), s.udataset, str(now().strftime("%s") + ":" + six.text_type(event[0])).encode("utf-8")) except Exception as e: fix_exception(e) if "minimum one second step" in str(e): pass else: raise
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 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 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 __init__(self, ctx, *name): """\ Events have a context and at least one name. For example: Event(ctx, "startup") Event(ctx, "switch","toggle","sw12") Event(ctx, "switch","dim","livingroom","lamp12") Event(ctx, "timer","timeout","t123") """ self._name_check(name) #print("E_INIT",name,"with",ctx) self.name = Name(name) self.ctx = ctx if ctx is not None else Context() if "loglevel" in self.ctx: self.loglevel = ctx.loglevel self.timestamp = now() global event_id event_id += 1 self.id = event_id
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