def test(): from src import messagebus succeed = [0] def f(m, v): succeed[0] = 1 messagebus.subscribe("/system/selftest", f) messagebus.postMessage("/system/selftest", "Test") time.sleep(0.2) if not succeed[0]: time.sleep(2) if succeed[0]: raise RuntimeError( "Message not delivered within 0.2 second. This may happen occasionally if CPU load is high but otherwise should not occur." ) else: raise RuntimeError("Message not delivered within 2 seconds") f2 = weakref.ref(f) del f succeed[0] = 0 time.sleep(1) messagebus.postMessage("/system/selftest", "Test") time.sleep(3) if succeed[0]: if f2(): logging.error("selftest: f still exists " + str(f2())) raise RuntimeError("Garbage collection fails to unsubscribe")
def _onClear(self): if self.priority in ("error", "critical", "warning"): messagebus.postMessage( "/system/notifications", "Alarm " + self.name + " condition cleared, waiting for ACK") logger.info("Alarm " + self.name + " cleared") api.send(['shouldRefresh'])
def _onKeyPress(self, key, fromUI=None): if fromUI or not self.testMode: #Synchronous must be true, no out of order messages allowed messagebus.postMessage("/devices/" + self.name + "/keypress", key, synchronous=True) self.onKeyPress(key) else: self.print(key, "keypress[IGNORED]")
def runtest(): try: theTest() except: messagebus.postMessage("/system/notifications/errors", traceback.format_exc(6)) finally: newevt.removeOneEvent('testevt', 'testevt') newevt.removeOneEvent('TEST1', 'TEST1') newevt.removeOneEvent('TEST2', 'TEST2')
def acknowledge(self, by="unknown", notes=""): notes = notes[:64] if notes.strip(): notes = ':\n' + notes else: notes = '' self.sm.event("acknowledge") if not by == "<DELETED>": logger.info("Alarm " + self.name + " acknowledged by" + by + notes) if self.priority in ("error", "critical", "warning"): messagebus.postMessage( "/system/notifications", "Alarm " + self.name + " acknowledged by " + by + notes)
def run_with_except_hook(*args, **kw): try: messagebus.postMessage("/system/threads/start",self.name) run_old(*args, **kw) messagebus.postMessage("/system/threads/stop",self.name) except Exception as e: messagebus.postMessage("/system/notifications/errors","Exception in thread %s, thread stopped. More details in logs."%self.name) messagebus.postMessage("/system/threads/errors","Exception in thread %s:\n%s"%(self.name, traceback.format_exc(6))) raise e
def _onNormal(self): "Mostly defensivem but also cleans up if the autoclear occurs and we skio the acknowledged state" global unacknowledged, active if self.priority in ("info", "warning", "error", "critical"): messagebus.postMessage( "/system/notifications", "Alarm " + self.name + " returned to normal") with lock: cleanup() if self.id in _unacknowledged: del _unacknowledged[self.id] unacknowledged = _unacknowledged.copy() if self.id in _active: del _active[self.id] active = _active.copy() calcNextBeep() api.send(['shouldRefresh'])
def _onActive(self): global unacknowledged global active with lock: cleanup() _unacknowledged[self.id] = weakref.ref(self) unacknowledged = _unacknowledged.copy() _active[self.id] = weakref.ref(self) active = _active.copy() s = calcNextBeep() if s: sound.playSound(s,handle="kaithem_sys_main_alarm") if self.priority in ("error, critical"): logger.error("Alarm "+self.name +" ACTIVE") messagebus.postMessage("/system/notifications/errors", "Alarm "+self.name+" is active") if self.priority in ("warning"): logger.warning("Alarm "+self.name +" ACTIVE") else: logger.info("Alarm "+self.name +" active")
def run_with_except_hook(*args, **kw): if self.name.startswith("nostartstoplog."): try: run_old(*args, **kw) except Exception as e: threadlogger.exception( "Thread stopping due to exception: "+self.name) raise e else: try: threadlogger.info("Thread starting: "+self.name) run_old(*args, **kw) threadlogger.info("Thread stopping: "+self.name) except Exception as e: threadlogger.exception( "Thread stopping due to exception: "+self.name) from src import messagebus messagebus.postMessage("/system/notifications/errors","Thread: "+self.name +" stopped due to exception ") raise e
def checkPiFlags(): global undervoltageDuringBootPosted global overTempDuringBootPosted try: # This is a trusted system util! Eval is fine here! x = subprocess.check_output(["vcgencmd", "get_throttled"]) x = eval(x.decode('utf8').split("=")[1]) # https://github.com/raspberrypi/documentation/blob/JamesH65-patch-vcgencmd-vcdbg-docs/raspbian/applications/vcgencmd.md if x & (2**0): undervoltageTagClaim.set(1) else: undervoltageTagClaim.set(0) if x & (2**3): overtemperatureTagClaim.set(1) else: overtemperatureTagClaim.set(0) # These are persistent flags. We check to see if something happened before Kaithem started, # But we don't actually need to do repeatedly spam the message if x & (2**16): if not undervoltageDuringBootPosted: messagebus.postMessage( "/system/notifications/errors", "A low input voltage condition has occurred at some point on this system" ) undervoltageDuringBootPosted = True if x & (2**19): if not overTempDuringBootPosted: messagebus.postMessage( "/system/notifications/errors", "An overtemperature condition has occurred at some point on this system" ) overTempDuringBootPosted = True except Exception: logging.exception("err")
def f(): try: import hardline from . import config hardline.setP2PPort(config.config['drayer-p2p-port']) # Ensure stopped hardline.stop() #Start at the standard port on localhost. This doesn't need to be configured, #If there is a system instance running we just won't start the local port part and use theirs. hardline.start(7009) # Unload them at exit for i in hardline.loadedServices: hardline.loadedServices[i].close() except: logging.exception("Fail to lauuch Hardline/Drayer") from src import messagebus messagebus.postMessage( "/system/notifications/errors/", "Error loading DrayerDB/HardlineP2P, these features are disabled." )
def on_message(self, bus, message, userdata): s = message.get_structure() if not s: return True msgtype = s.get_name() # Speech recognition, forward it on to the message bus. if msgtype == 'pocketsphinx': if message.get_structure().get_value('hypothesis'): messagebus.postMessage( "/devices/" + self.name + "/hypothesis", (message.get_structure().get_value('hypothesis'), )) if message.get_structure().get_value('final'): self.controller().print( str((message.get_structure().get_value('hypothesis'), message.get_structure().get_value('confidence')))) messagebus.postMessage( "/devices/" + self.name + "/final", (message.get_structure().get_value('hypothesis'), message.get_structure().get_value('confidence'))) return True
def _onActive(self): global unacknowledged global active with lock: cleanup() _unacknowledged[self.id] = weakref.ref(self) unacknowledged = _unacknowledged.copy() _active[self.id] = weakref.ref(self) active = _active.copy() s = calcNextBeep() if s: # Sound drivers can actually use tagpoints, this was causing a # deadlock with the tag's lock in the __del__ function GCing some # other tag. I don't quite understand it but this should break the loop def f(): # Ondemand to avoid circular import from . import sound beepDevice = file['all']['soundcard'] sound.playSound(s, handle="kaithem_sys_main_alarm", output=beepDevice) api.send(['shouldRefresh']) workers.do(f) if self.priority in ("error", "critical"): logger.error("Alarm " + self.name + " ACTIVE") messagebus.postMessage("/system/notifications/errors", "Alarm " + self.name + " is active") if self.priority in ("warning"): messagebus.postMessage("/system/notifications/warnings", "Alarm " + self.name + " is active") logger.warning("Alarm " + self.name + " ACTIVE") else: logger.info("Alarm " + self.name + " active") if self.priority in ("info"): messagebus.postMessage("/system/notifications", "Alarm " + self.name + " is active")
else: file = {} # Legacy registry stuff. lat = registry.get("system/location/lat", None) lon = registry.get("system/location/lon", None) if 'default' in file: lat = file['default'].get('lat', None) lon = file['default'].get('lon', None) if not lat or not lon: try: l = ip_geolocate() messagebus.postMessage( "/system/notifications/important", "Got server location by IP geolocation. You can change this in settings." ) file['default'] = l except: # The location called "default" is to be the main one. file['default'] = {'lat': lat, 'lon': lon, 'city': ''} else: # The location called "default" is to be the main one. file['default'] = {'lat': lat, 'lon': lon, 'city': ''} try: persist.save(file, fn, private=True) except: logging.exception("Save fail")
def theTest(): running_tests.append(1) modules_state.scopes['x'] = {} #Create an event that sets y to 0 if it is 1 with newevt._event_list_lock: x = newevt.Event("y==1", "global y\ny=0", locals(), setup="y=0") x.module = x.resource = "testevt" newevt.EventReferences[x.module, x.resource] = x #Register event with polling. x.register() #Set y to 1 x.pymodule.y = 1 time.sleep(2) try: #y should immediately be set back to 0 at the next polling cycle if x.pymodule.y == 1: raise RuntimeError("Edge-Triggered Event did nothing") except: print(x.pymodule.__dict__) raise finally: x.unregister() x.pymodule.y = 1 if not x.pymodule.y == 1: raise RuntimeError( "Edge-Triggered Event did not go away when unregistered") blah = [False] def f(): return blah[0] def g(): blah[0] = False newevt.when(f, g) time.sleep(0.5) blah[0] = True time.sleep(0.5) if blah[0]: time.sleep(2) if blah[0]: raise RuntimeError("One time event did not trigger") blah[0] = True time.sleep(1) if not blah[0]: raise RuntimeError("One time event did not delete itself properly") newevt.after(1, g) blah[0] = True time.sleep(1.5) if blah[0]: raise RuntimeError("Time delay event did not trigger") blah[0] = True time.sleep(2) if not blah[0]: raise RuntimeError( "Time delay event did not delete itself properly") with newevt._event_list_lock: #Same exact thing exept we use the onchange x = newevt.Event("!onchange y", "global y\ny=5") #Give it a value to change from x.pymodule.y = 0 x.module = x.resource = "TEST1" newevt.EventReferences[x.module, x.resource] = x #Register event with polling. x.register() #Let it notice the old value time.sleep(1) #Set y to 1 x.pymodule.y = 1 time.sleep(1) #y should immediately be set back to 0 at the next polling cycle x.unregister() if x.pymodule.y == 1: raise RuntimeError("Onchange Event did nothing") x.pymodule.y = 1 if not x.pymodule.y == 1: raise RuntimeError( "Onchange Event did not go away when unregistered") #There is a weird old feature where message events don't work if not in EventReferences #It was an old thing to caths a circular reference bug. with newevt._event_list_lock: #Now we test the message bus event x = newevt.Event("!onmsg /test", "global y\ny='test'") x.module = x.resource = 'TEST2' #Make sure nobody is iterating the eventlist #Add new event x.register() #Update index newevt.EventReferences[x.module, x.resource] = x time.sleep(0.25) #Give it a value to change from messagebus.postMessage("/test", 'foo') #Let it notice the old value time.sleep(0.25) x.unregister() #y should immediately be set back to 0 at the next polling cycle if not hasattr(x.pymodule, 'y'): time.sleep(5) if not hasattr(x.pymodule, 'y'): raise RuntimeError( "Message Event did nothing or took longer than 5s") else: raise RuntimeError( "Message Event had slow performance, delivery took more than 0.25s" ) try: x.pymodule.y = 1 except: #This might fail if the implementatino makes pymodule not exist anymore pass messagebus.postMessage('foo', "/test") #If there is no y or pymodule, this test won't work but we can probably assume it unregistered correctly. #Maybe we should add a real test that works either way? if hasattr(x, 'pymodule') and hasattr(x.pymodule, 'y'): if x.pymodule.y == 'test': raise RuntimeError( "Message Event did not go away when unregistered") print("Success in testing event system") running_tests.pop()
cherrypy.tree.mount(root,config=cnf) #As far as I can tell, this second server inherits everything from the "implicit" server #except what we override. server2 = cherrypy._cpserver.Server() server2.socket_port= config['http-port'] server2._socket_host= bindto server2.thread_pool=config['http-thread-pool'] server2.subscribe() if time.time() < 1420070400: messagebus.postMessage('/system/notifications/errors',"System Clock is wrong, some features may not work properly.") if time.time() < util.min_time: messagebus.postMessage('/system/notifications/errors',"System Clock may be wrong, or time has been set backwards at some point. If system clock is correct and this error does not go away, you can fix it manually be correcting folder name timestamps in the var dir.") sys.modules['kaithem'] = sys.modules['__main__'] from src import kaithemobj kaithemobj.kaithem.misc.version = __version__ kaithemobj.kaithem.misc.version_info = __version_info__ cherrypy.engine.start() #If configured that way on unix, check if we are root and drop root. util.drop_perms(config['run-as-user'], config['run-as-group']) messagebus.postMessage('/system/startup','System Initialized') messagebus.postMessage('/system/notifications/important','System Initialized') cherrypy.engine.block()
def dataCallback(self, db, record, signature): messagebus.postMessage("/devices/" + self.name + "/record", record)
#Plugin that manages TP-Link Kasa devices. from src import devices,alerts, scheduling,tagpoints,messagebus import os,mako,time,threading,logging try: from pyHS100 import SmartPlug, SmartBulb except: logger.exception() messagebus.postMessage("/system/notifications/errors","Problem loading Kasa support") from src import widgets logger = logging.Logger("plugins.kasa") from mako.lookup import TemplateLookup templateGetter = TemplateLookup(os.path.dirname(__file__)) lookup={} lastRefreshed = 0 lock = threading.Lock() def maybeRefresh(t=30): global lastRefreshed if lastRefreshed<time.time()-t: refresh() elif lastRefreshed<time.time()-5: refresh(1)
if x.pymodule.y == 1: common.fail("Onchange Event did nothing") #Unregister event and make sure it really goes away x.unregister() x.pymodule.y = 1 if not x.pymodule.y == 1: common.fail("Onchange Event did not go away when unregistered") #Now we test the message bus event x = newevt.Event("!onmsg /test", "global y\ny='test'", locals()) #Register event with polling. x.register() #Give it a value to change from messagebus.postMessage("/test", 'poo') #Let it notice the old value time.sleep(0.25) #y should immediately be set back to 0 at the next polling cycle if not x.pymodule.y == 'test': common.fail("Message Event did nothing") #Unregister event and make sure it really goes away x.unregister() x.pymodule.y = 1 messagebus.postMessage('poo', "/test") if x.pymodule.y == 'test': common.fail("Message Event did not go away when unregistered")
x.unregister() x.pymodule.y =1 if not x.pymodule.y == 1: common.fail("Onchange Event did not go away when unregistered") #Now we test the message bus event x = newevt.Event("!onmsg /test","global y\ny='test'",locals()) #Register event with polling. x.register() #Give it a value to change from messagebus.postMessage("/test",'poo') #Let it notice the old value time.sleep(0.25) #y should immediately be set back to 0 at the next polling cycle if not x.pymodule.y == 'test': common.fail("Message Event did nothing") #Unregister event and make sure it really goes away x.unregister() x.pymodule.y =1 messagebus.postMessage('poo',"/test") if x.pymodule.y == 'test': common.fail("Message Event did not go away when unregistered")
def acknowledge(self,by="unknown"): self.sm.event("acknowledge") logger.info("Alarm "+self.name +" acknowledged by" + by) if self.priority in ("error, critical","warnings"): messagebus.postMessage("/system/notifications", "Alarm "+self.name+" acknowledged by "+ by)
# inserting into the old list . Note that here we consider very rarely losing a record # to be better than bad performace for i in range(30): time.sleep(0.001) self.history = sqlite3.Connection(self.filename) with self.history: if needsGC: for i in self.children: x = self.children[i]() if x: with x.lock: x.clearOldData(force) for i in pending: self.history.execute('INSERT INTO record VALUES (?,?,?)', i) self.history.close() try: historian = TagHistorian(newHistoryDBFile) ramHistorian = TagHistorian(ramdbfile) os.chmod(ramdbfile, 0o750) except Exception: messagebus.postMessage( "/system/notifications/errors", "Failed to create tag historian, logging will not work." + "\n" + traceback.format_exc())
cherrypy.config.update(site_config) cherrypy.tools.pageloadnotify = cherrypy.Tool('on_start_resource', pageloadnotify) cherrypy.config['tools.pageloadnotify.on'] = True cherrypy.tools.addheader = cherrypy.Tool('before_finalize', addheader) if hasattr(cherrypy.engine, 'signal_handler'): cherrypy.engine.signal_handler.subscribe() cherrypy.tree.mount(root, config=cnf) #As far as I can tell, this second server inherits everything from the "implicit" server #except what we override. server2 = cherrypy._cpserver.Server() server2.socket_port = config['http-port'] server2._socket_host = bindto server2.thread_pool = config['http-thread-pool'] server2.subscribe() messagebus.postMessage('/system/startup', 'System Initialized') messagebus.postMessage('/system/notifications', 'System Initialized') if time.time() < 1420070400: messagebus.postMessage( '/system/notifications/errors', "System Clock probably wrong, some features may not work properly.") cherrypy.engine.start() cherrypy.engine.block()