def main(): global isy, programs, syslogUse, syslogFacility, logfile # Setup syslog if requested if syslogUse: syslog.openlog(logoption=syslog.LOG_PID, facility=syslogFacilities[syslogFacility]) # Open logfile if requested if logfile: try: logfile = open(logfile, 'ab+') except IOError: usage('ERROR: Failed to open logfile! %s' % sys.exc_info()[1]) # Dump status on sigusr1 signal.signal(signal.SIGUSR1,status_dump) # Connect to ISY try: isy = Isy(addr=isyHost, userl=isyUser, userp=isyPass, debug=isyDebug) except: print "ERROR: Connection to ISY failed!" sys.exit(1) programs = get_proginfo(isy) # Get info about programs for trigger logging server = ISYEvent() server.subscribe(addr=isyHost, userl=isyUser, userp=isyPass, debug=isyDebug) server.set_process_func(parse_event, "") try: #print('Use Control-C to exit') server.events_loop() #no return except KeyboardInterrupt: print('Exiting')
def start_event_thread(self, mask=0): """ starts event stream update thread mask will eventually be used to "masking" events """ from threading import Thread # if thread already runing we should update mask if hasattr(self, 'event_thread') and isinstance(self.event_thread, Thread) : if self.event_thread.is_alive() : print "Thread already running ?" return #st = time.time() #print("start preload") self._preload(rload=0) #sp = time.time() #print("start complete") #print "load in ", ( sp - st ) self._isy_event = ISYEvent() self._isy_event.subscribe(self.addr) self._isy_event.set_process_func(self._read_event, self) self.event_thread = Thread(target=self._isy_event.events_loop, name="event_looper" ) self.event_thread.daemon = True self.event_thread.start() self.eventupdates = True
def Watcher(): config.watchstarttime = time.time() config.watchlist = ['init'] debugprint(config.dbgdaemon, "Watcher: ", config.watchstarttime, os.getpid()) server = ISYEvent() server.subscribe(addr=config.ISYaddr, userl=config.ISYuser, userp=config.ISYpassword) server.set_process_func(event_feed, "") server.events_loop()
def main(): server = ISYEvent(debug=0x0000) # you can subscribe to multiple devices # server.subscribe('10.1.1.25') server.subscribe(addr=os.getenv('ISY_ADDR', '10.1.1.36'), userl=os.getenv('ISY_USER', "admin"), userp=os.getenv('ISY_PASS', "admin")) server.set_process_func(_print_event, "") try: print('Use Control-C to exit') server.events_loop() #no return # for d in server.event_iter( ignorelist=["_0", "_11"] ): # server._print_event(d, "") except KeyboardInterrupt: print('Exiting')
def main() : server = ISYEvent() # you can subscribe to multiple devices # server.subscribe('10.1.1.25') server.subscribe( os.getenv('ISY_ADDR', '10.1.1.36')) server.set_process_func(ISYEvent.print_event, "") try: print('Use Control-C to exit') server.events_loop() #no return # for d in server.event_iter( ignorelist=["_0", "_11"] ): # server.print_event(d, "") except KeyboardInterrupt: print('Exiting')
def main() : config = ConfigParser.ConfigParser() config.read(os.path.expanduser('~/home.cfg')) server = ISYEvent() isy_addr = config.get('isy', 'addr') isy_user = config.get('isy', 'user') isy_pass = config.get('isy', 'pass') server.subscribe( addr=isy_addr, userl=isy_user, userp=isy_pass ) server.set_process_func(ISYEvent.print_event, "") try: print('Use Control-C to exit') server.events_loop() #no return except KeyboardInterrupt: print('Exiting')
def main(): server = ISYEvent(debug=0x0000) # you can subscribe to multiple devices # server.subscribe('10.1.1.25') server.subscribe( addr=os.getenv('ISY_ADDR', '10.1.1.36'), userl=os.getenv('ISY_USER', "admin"), userp=os.getenv('ISY_PASS', "admin") ) server.set_process_func(_print_event, "") try: print('Use Control-C to exit') server.events_loop() #no return # for d in server.event_iter( ignorelist=["_0", "_11"] ): # server._print_event(d, "") except KeyboardInterrupt: print('Exiting')
data = flatten_dict(arg[0]) event = [{ 'name': 'isy', 'columns': list(data.keys()), 'points': [list(data.values())] }] app.log.debug('Event data: %s' % event) handler.postEvent(event) # Setup ISY socket listener # Be aware: Even though we are able to update the config at runtime # we do not take down the web socket subscription once established server = ISYEvent() retries = 0 while True: try: server.subscribe(addr=app.config.get('isy', 'isy_addr'), userl=app.config.get('isy', 'isy_user'), userp=app.config.get('isy', 'isy_pass')) break except Exception as e: retries += 1 app.log.warn(e) app.log.warn('Cannot connect to ISY. Attempt %n of %n', retries, app.config.retries)
class Isy(IsyUtil): """ Obj class the represents the ISY device Keyword Args : addr : IP address of ISY userl/userp : User Login / Password debug : Debug flags (default 0) cachetime : cache experation time [NOT USED] (default 0) faststart : ( ignored if eventupdate is used ) 0=preload cache as startup 1=load cache on demand eventupdates: run a sub-thread and stream events updates from ISY same effect as calling Isy().start_event_thread() """ # import functions from ISY._isyclimate import load_clim, clim_get_val, clim_query, clim_iter from ISY._isyvar import load_vars, var_set_value, _var_set_value, \ var_get_value, var_addrs, get_var, _var_get_id, \ var_get_type, var_iter from ISY._isyprog import load_prog, get_prog, _prog_get_id, \ prog_iter, prog_comm, _prog_comm from ISY._isynode import load_nodes, _gen_member_list, _gen_folder_list, \ _gen_nodegroups, _gen_nodedict, node_names, scene_names, \ node_addrs, scene_addrs, get_node, _node_get_id, node_get_prop, \ node_set_prop, _node_send, node_comm, _updatenode, \ load_node_types, node_get_type, node_iter, _updatenode from ISY._isynet_resources import _load_networking, load_net_resource, \ _net_resource_get_id, net_resource_run, \ net_resource_names, net_resource_iter, \ load_net_wol, net_wol, _net_wol_get_id, net_wol_names, net_wol_iter ## set_var_value, _set_var_value, var_names if sys.hexversion < 0x3000000 : _password_mgr = URL.HTTPPasswordMgrWithDefaultRealm() _handler = URL.HTTPBasicAuthHandler(_password_mgr) _opener = URL.build_opener(_handler) # URL.HTTPHandler(debuglevel=1) else: _password_mgr = URL.request.HTTPPasswordMgrWithDefaultRealm() _handler = URL.request.HTTPBasicAuthHandler(_password_mgr) _opener = URL.request.build_opener(_handler) def __init__(self, **kwargs): # # Keyword args # self.userl = kwargs.get("userl", os.getenv('ISY_USER', "admin")) self.userp = kwargs.get("userp", os.getenv('ISY_PASS', "admin")) self.addr = kwargs.get("addr", os.getenv('ISY_ADDR', None)) # (self.userl, self.userp, self.addr) = authtuple # print "AUTH: ", self.addr, self.userl, self.userp self.debug = kwargs.get("debug", 0) self.cachetime = kwargs.get("cachetime", 0) self.faststart = kwargs.get("faststart", 1) self.eventupdates = kwargs.get("eventupdates", 0) self._isy_event = None self.error_str = "" self.callbacks = dict () self._is_pro = True # data dictionaries for ISY state self.controls = None self.name2control = None self._folderlist = None self._folder2addr = None self._progdict = None self._nodedict = None self._nodegroups = None self._groups2addr = None self._node2addr = None self._nodeCategory = None self._vardict = None self._wolinfo = None self._net_resource = None self.climateinfo = None if self.addr == None : from ISY.IsyDiscover import isy_discover units = isy_discover(count=1) for device in units.values() : self.addr = device['URLBase'][7:] self.baseurl = device['URLBase'] else : self.baseurl = "http://" + self.addr if self.addr == None : warn("No ISY address : guessing \"isy\"") self.addr = "isy" # print "\n\taddr", "=>", self.addr, "\n\n" # if ( not self.userl or not self.userp ) : # netrc_info = netrc.netrc() # login, account, password = netrc_info.authenticators(self.addr) # print "login", "=>", repr(login) # print "account", "=>", repr(account) # print "password", "=>", repr(password) # self.userl = "admin" # self.userp = "admin" if self.debug & 0x01 : print("class Isy __init__") print("debug ", self.debug) print("cachetime ", self.cachetime) print("faststart ", self.faststart) # parse ISY_AUTH as LOGIN:PASS # # general setup logic # Isy._handler.add_password(None, self.addr, self.userl, self.userp) # self._opener = URL.build_opener(Isy._handler, URL.HTTPHandler(debuglevel=1)) # self._opener = URL.build_opener(Isy._handler) if self.debug & 0x02: print("baseurl: " + self.baseurl + " : " + self.userl + " : " + self.userp) if self.faststart < 2 : try: self.load_conf() except URL.URLError as e: print("Unexpected error:", sys.exc_info()[0]) print 'Problem connecting with ISY device :', self.addr print e raise IsyCommunicationError(e) if not self.faststart : self.load_nodes() # There for id's to Node/Var/Prog objects self.nodeCdict = dict () self.varCdict = dict () self.progCdict = dict () self.folderCdict = dict () if self.eventupdates : self.start_event_thread() # # Event Subscription Code # Allows for treaded realtime node status updating # def start_event_thread(self, mask=0): """ starts event stream update thread mask will eventually be used to "masking" events """ from threading import Thread # if thread already runing we should update mask if hasattr(self, 'event_thread') and isinstance(self.event_thread, Thread) : if self.event_thread.is_alive() : print "Thread already running ?" return #st = time.time() #print("start preload") self._preload(rload=0) #sp = time.time() #print("start complete") #print "load in ", ( sp - st ) self._isy_event = ISYEvent() self._isy_event.subscribe(self.addr) self._isy_event.set_process_func(self._read_event, self) self.event_thread = Thread(target=self._isy_event.events_loop, name="event_looper" ) self.event_thread.daemon = True self.event_thread.start() self.eventupdates = True # print(self.event_thread) def stop_event_tread(self) : """ Stop update thread """ if hasattr(self._isy_event, "_shut_down") : self._isy_event._shut_down = 1 self.eventupdates = False # @staticmethod def _read_event(self, evnt_dat, *arg) : """ read event stream data and copy into internal state cache internal function call """ # print("_read_event") skip_default = ["_0", "_2", "_4", "_5", "_6", "_7", "_8", "_9", "_10", "_11", "_12", "_13", "_14", "_15", "_16", "_17", "_18", "_19", "_20", "DON", "DOF", ] skip = skip_default assert isinstance(evnt_dat, dict), "_read_event Arg must me dict" event_targ = None if evnt_dat["control"] in skip : return # # Status/property changed # if evnt_dat["control"] in ["ST", "RR", "OL"] : if evnt_dat["node"] in self._nodedict : # ADD LOCK ON NODE DATA # print("===evnt_dat :", evnt_dat) # print("===a :", ar) #print(self._nodedict[evnt_dat["node"]]) target_node = self._nodedict[evnt_dat["node"]] event_targ = evnt_dat["node"] # create property if we do not have it yet if not evnt_dat["control"] in target_node["property"] : target_node["property"][evnt_dat["control"]] = dict ( ) target_node["property"][evnt_dat["control"]]["value"] \ = evnt_dat["action"] target_node["property"][evnt_dat["control"]]["formatted"] \ = self._format_val( evnt_dat["action"] ) if ( self.debug & 0x10 ) : print("_read_event :", evnt_dat["node"], evnt_dat["control"], evnt_dat["action"]) print(">>>", self._nodedict[evnt_dat["node"]]["property"]) else : warn("Event for Unknown node : {0}".format(evnt_dat["node"]), \ RuntimeWarning) elif evnt_dat["control"] == "_3" : # Node Change/Updated Event print("Node Change/Updated Event : {0}".format(evnt_dat["node"])) print("evnt_dat : ", evnt_dat) # # handle VAR value change # elif evnt_dat["control"] == "_1" : # Var Status / Initialized if evnt_dat["action"] == "6" or evnt_dat["action"] == "7" : var_eventInfo = evnt_dat['eventInfo']['var'] vid = var_eventInfo['var-type'] + ":" + var_eventInfo['var-id'] # check if the event var exists in out world if vid in self._vardict : # ADD LOCK ON VAR DATA # copy var properties from event event_targ = vid self._vardict[vid].update(var_eventInfo) self._vardict[vid]["val"] = int(self._vardict[vid]["val"]) self._vardict[vid]["init"] = int(self._vardict[vid]["init"]) else : warn("Event for Unknown Var : {0}".format(vid), RuntimeWarning) else: print("evnt_dat :", evnt_dat) print("Event fall though : '{0}'".format(evnt_dat["node"])) if event_targ in self.callbacks : cb = self.callbacks[event_targ] if isinstance(cb[0], collections.Callable) : cb[0](evnt_dat, *cb[1]) else : warn("callback for {0} not callable, deleting callback".format(event_targ), RuntimeWarning) del self.callbacks[event_targ] return def _format_val(self, v) : try: v = int(v) except ValueError : return "0" else : if ( v == 0 ) : return "off" elif v == 255 : return "on" else : return str ( (int(v)*100) // 255) def node_rename(self, nid, nname) : """ rename Node args: id = Node ID name = new Node name calls SOAP RenameNode() """ nid = self._node_get_id(nid) return self.soapcomm("RenameNode", id=nid, name=nname) # def node_new(self, id, nname) : # """ create new Folder """ # return self.soapcomm("AddNode", id=1234, name=nname, type="T", flag="Y") ## scene def scene_rename(self, fid, fname) : """ rename Scene/Group args: id = a Scene/Group id name = new name calls SOAP RenameGroup() """ fid = self._node_get_id(fid) return self.soapcomm("RenameGroup", id=fid, name=fname) def scene_del(self, sid=None ) : """ delete Scene/Group args: id : Scene address, name or Folder Obj calls SOAP RemoveGroup() """ sceneid = self._node_get_id(sid) if sceneid == None : raise IsyValueError("no such Scene : " + str(sid) ) # # add code to update self._nodegroups # return self.soapcomm("RemoveGroup", id=sceneid) def scene_new(self, nid=0, sname=None) : """ new Scene/Group args: id = a unique (unused) Group ID name = name for new Scene/Group ***No error is given if Scene/Group ID is already in use*** calls SOAP AddGroup() """ if not isinstance(sname, str) or not len(sname) : raise IsyValueError("scene name must be non zero length string") if nid == 0 : iid = 30001 nid = str(iid) while nid in self._folderlist or nid in self._nodegroups : iid += 1 nid=str(iid) self.soapcomm("AddGroup", id=nid, name=sname) # # add code to update self._nodegroups # return nid def scene_add_node(self, groupid, nid, nflag=0x10) : """ add node to Scene/Group args: group = a unique (unused) scene_id ID node = id, name or Node Obj flag = set to 0x10 if node it a controler for Scene/Group Add new Node to Scene/Group calls SOAP MoveNode() """ nodeid = self._node_get_id(nid) if nodeid == None : raise IsyValueError("no such Node : " + str(nid) ) r = self.soapcomm("MoveNode", group=groupid, node=nodeid, flag=nflag) return r def scene_del_node(self, groupid, nid) : """ Remove Node from Scene/Group args: group = address, name or Scene Obj id = address, name or Node Obj calls SOAP RemoveFromGroup() """ nodeid = self._node_get_id(nid) if nodeid == None : raise IsyValueError("no such Node : " + str(nid) ) r = self.soapcomm("RemoveFromGroup", group=groupid, id=nodeid) return r ## folder def folder_rename(self, fid, fname) : """ rename Folder args: id = folder ID name = new folder name calls SOAP RenameFolder() """ fid = self._node_get_id(fid) r = self.soapcomm("RenameFolder", id=fid, name=fname) return r def folder_new(self, fid, fname) : """ create new Folder args: folder_id = a unique (unused) folder ID folder name = name for new folder returns error if folder ID is already in use calls SOAP AddFolder() """ if fid == 0 : iid = 50001 fid = str(iid) while fid in self._folderlist or fid in self._nodegroups : iid += 1 fid = str(iid) r = self.soapcomm("AddFolder", fid=1234, name=fname) if isinstance(r, tuple) and r[0] == '200' : self._folderlist[fid] = dict() self._folderlist[fid]['address'] = fid self._folderlist[fid]['folder-flag'] = '0' self._folderlist[fid]['name'] = 'fname' return r def folder_del(self,fid) : """ delete folder args: fid : folder address, name or Folder Obj calls SOAP RemoveFolder() """ fid = self._node_get_id(fid) if fid == None : raise IsyValueError("Unknown Folder : " + str(fid) ) r = self.soapcomm("RemoveFolder", id=fid) if isinstance(r, tuple) and r[0] == '200' : self._folderlist[fid] = dict() # SetParent(node, nodeType, parent, parentType ) def folder_add_node(self, nid, nodeType=1, parent="", parentType=3) : """ move node/scene from folder Named args: node nodeType parent parentType sets Parent for node/scene calls SOAP SetParent() """ nodeid = self._node_get_id(nid) if nodeid == None : raise IsyValueError("no such Node/Scene : " + str(nid) ) if parent != "" : fldid = self._node_get_id(parent) if fldid == None : raise IsyValueError("no such Folder : " + str(parent) ) parentid = fldid else : parentid = parent r = self.soapcomm("SetParent", node=nodeid, nodeType=nodeType, parent=parentid, parentType=parentType) return r def folder_del_node(self, nid, nodeType=1) : """ remove node from folder Named args: node nodeType remove node/scene from folder ( moves to default/main folder ) calls SOAP SetParent() """ return self.folder_add_node(nid, nodeType=nodeType, \ parent="", parentType=3) def reboot(self) : """ Reboot ISY Device args: none calls SOAP Reboot() """ return self.soapcomm("Reboot") # # User web commands # def user_fsstat(self) : """ ISY Filesystem Status calls SOAP GetFSStat() """ r = self.soapcomm("GetFSStat") return et2d( ET.fromstring(r)) def user_dir(self, name="", pattern="") : """ Get User Folder/Directory Listing Named args: name pattern call SOAP GetUserDirectory() """ r = self.soapcomm("GetUserDirectory", name=name, pattern=pattern) # print "GetUserDirectory : ", r return et2d( ET.fromstring(r)) def user_mkdir(self, name=None) : """ Make new User Folder/Directory Named args: name call SOAP MakeUserDirectory() """ if name == None : raise IsyValueError("user_mkdir : invalid dir name") if name[0] != "/" : name = "/USER/WEB/" + name r = self.soapcomm("MakeUserDirectory", name=name) return et2d( ET.fromstring(r)) def user_rmdir(self, name=None) : """ Remove User Folder/Directory Named args: name call SOAP RemoveUserDirectory() """ if name == None : raise IsyValueError("user_rmdir : invalid dir name") name = name.rstrip('/') if name[0] != "/" : name = "/USER/WEB/" + name r = self.soapcomm("RemoveUserDirectory", name=name) return et2d( ET.fromstring(r)) def user_mv(self, name=None, newName=None) : """ Move/Rename User Object (File or Directory) Named args: oldn newn call SOAP MoveUserObject() """ if name == None or newName == None : raise IsyValueError("user_mv : invalid name") if name[0] != "/" : name = "/USER/WEB/" + name if newName[0] != "/" : newName = "/USER/WEB/" + newName r = self.soapcomm("MoveUserObject", name=name, newName=newName) return r def user_rm(self, name=None) : """ Remove User File Named args: name call SOAP RemoveUserFile() """ if name == None : raise IsyValueError("user_mkdir : invalid name") if name[0] != "/" : name = "/USER/WEB/" + name r = self.soapcomm("RemoveUserFile", name=name) return(r) def user_getfile(self, name=None) : """ Get User File Named args: name call SOAP GetUserFile() """ if not len(name) : raise IsyValueError("user_getfile : invalid name") if name[0] != "/" : name = "/USER/WEB/" + name r = self.soapcomm("GetUserFile", name=name) return r def user_uploadfile(self, srcfile="", name=None, data="") : """ upload User File Named args: name : name of file after upload data : date to upload srcfile : file containing data to upload srcfile is use only if data is not set if both data & srcfile are not set then the file "name" is used calls /file/upload/... """ if name == None : raise IsyValueError("user_uploadfile : invalid name") r = self.sendfile(src=srcfile, filename=name, data=data) return r # # Util Funtions # def _preload(self, rload=0): """ Internal function preload all data tables from ISY device into cache normally this is done "on demand" as needed """ if rload or not hasattr(self, "controls") : self.load_conf() if rload or not hasattr(self, "_nodedict") : self.load_nodes() # self._gen_member_list() # if rload or not hasattr(self, "climateinfo") : # self.load_clim() if rload or not hasattr(self, "_vardict") : self.load_vars() if rload or not hasattr(self, "_progdict") : self.load_prog() # if rload or not hasattr(self, "_wolinfo") : #self.load_wol() if rload or not hasattr(self, "_nodeCategory") : self.load_node_types() def _savedict(self) : """ internal debug command """ self._preload() # self._writedict(self._wolinfo, "wolinfo.txt") self._writedict(self._nodedict, "nodedict.txt") self._writedict(self._nodegroups, "nodegroups.txt") self._writedict(self._folderlist, "folderlist.txt") self._writedict(self._vardict, "vardict.txt") # self._writedict(self.climateinfo, "climateinfo.txt") self._writedict(self.controls, "controls.txt") self._writedict(self._progdict, "progdict.txt") self._writedict(self._nodeCategory, "nodeCategory.txt") ## ## Load System config / info and command information ## def load_conf(self) : """ Load configuration of the system with permissible commands args : none internal function call """ if self.debug & 0x01 : print("load_conf pre _getXMLetree") configinfo = self._getXMLetree("/rest/config") # Isy._printXML(configinfo) # IsyCommunicationError self.name2control = dict ( ) self.controls = dict ( ) for ctl in configinfo.iter('control') : # self._printXML(ctl) # self._printinfo(ctl, "configinfo : ") cprop = dict ( ) for child in list(ctl): # print("child.tag " + str(child.tag) + "\t=" + str(child.text)) if child.tag == "actions" : adict = dict () for act in child.iter('action') : n = act.find('label').text v = act.find('name').text adict[n] = v cprop[child.tag] = adict else : # self._printinfo(child, "child") cprop[child.tag] = child.text for n, v in child.items() : cprop[n] = v # print("cprop ", cprop) if "name" in cprop : self.controls[cprop["name"].upper()] = cprop if "label" in cprop : self.name2control[cprop["label"].upper()] \ = cprop["name"].upper() self.config = dict () for v in ( "platform", "app_version", "driver_timestamp", "app", " build_timestamp" ): n = configinfo.find(v) if not n is None: if isinstance(n.text, str): self.config[v] = n.text xelm = configinfo.find("product/id") if not xelm is None: if hasattr(xelm, 'text') : self.config["product_id"] = xelm.text # print("self.controls : ", self.controls) #self._printdict(self.controls) #print("self.name2control : ", self.name2control) ## ## property ## def _get_platform(self) : """ name of ISY platform (readonly) """ return self.config["platform"] platform = property(_get_platform) def _get_app_version(self) : """ name of ISY app_version (readonly) """ return self.config["app_version"] app_version = property(_get_app_version) def _get_control_id(self, comm): """ command name to command ID """ if not self.controls : self.load_conf() c = comm.strip().upper() if c in self.controls : return c if c in self.name2control : return self.name2control[c] return None ## ## Logs ## def load_log_type(self): """ load log type tables args: None **not implemented ** """ pass def load_log_id(self): """ load log id tables **not implemented ** """ pass def log_reset(self, errorlog = 0 ): """ clear log lines in ISY args: errorlog = flag clear error """ self.log_query(errorlog, 1) def log_iter(self, error = 0 ): """ iterate though log lines args: error : return error logs or now returns : Return an iterator log enteries """ for l in self.log_query(error) : yield l def log_query(self, errorlog = 0, resetlog = 0 ): """ get log from ISY """ xurl = self.baseurl + "/rest/log" if errorlog : xurl += "/error" if resetlog : xurl += "?reset=true" if self.debug & 0x02 : print("xurl = " + xurl) req = URL.Request(xurl) res = self._opener.open(req) data = res.read() res.close() return data.splitlines() def log_format_line(self, line) : """ format a ISY log line into a more human readable form ** not implemented ** """ pass ## ## X10 Code ## _x10re = re.compile('([a-pA-P]\d{,2)') _x10comm = { 'alllightsoff' : 1, 'status off' : 2, 'on' : 3, 'Preset dim' : 4, 'alllightson' : 5, 'hail ack' : 6, 'bright' : 7, 'status on' : 8, 'extended code' : 9, 'status request' : 10, 'off' : 11, 'preset dim' : 12, 'alloff' : 13, 'Hail Req' : 14, 'dim' : 15, 'extended data' : 16 } def _get_x10_comm_id(self, comm) : """ X10 command name to id """ comm = str(comm).strip().lower() if comm.isdigit() : if int(comm) >= 1 and int(comm) <= 16 : return comm else : raise IsyValueError("bad x10 command digit : " + comm) if comm in self._x10comm : return self._x10comm[comm] else : raise IsyValueError("unknown x10 command : " + comm) def x10_comm(self, unit, cmd) : """ direct send x10 command """ xcmd = self._get_x10_comm_id(str(cmd)) unit = unit.strip().upper() if not re.match("[A-P]\d{,2}", unit) : raise IsyValueError("bad x10 unit name : " + unit) print("X10 sent : " + str(unit) + " : " + str(xcmd)) xurl = "/rest/X10/" + str(unit) + "/" + str(xcmd) if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) #self._printXML(resp) #self._printinfo(resp) if resp.attrib["succeeded"] != 'true' : raise IsyResponseError("X10 command error : unit=" + str(unit) + " cmd=" + str(cmd)) # /rest/time # Returns system time # #/rest/network # Returns network configuration # /rest/sys # returns system configuration # # /rest/subscriptions # Returns the state of subscriptions def subscriptions(self) : """ get event subscriptions list and states args: none Returns the state of subscriptions calls : /rest/subscriptions """ xurl = "/rest/subscriptions" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) self._printXML(resp) return et2d(resp) def network(self) : """ network configuration args: none Returns network configuration calls /rest/network """ xurl = "/rest/network" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) self._printXML(resp) return et2d(resp) def sys(self) : """ system configuration args: none calls : /rest/sys """ xurl = "/rest/sys" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) self._printXML(resp) return et2d(resp) def time(self) : """ system time of ISY args: none calls : /rest/time """ xurl = "/rest/time" resp = self._getXMLetree(xurl) self._printXML(resp) return et2d(resp) def batch( self, on=-1) : """ Batch mode args values: 1 = Turn Batch mode on 0 = Turn Batch mode off -1 or None = Return Batch mode status calls /rest/batteryPoweredWrites/ """ xurl = "/rest/batteryPoweredWrites/" if on == 0 : xurl += "/off" elif on == 1 : xurl += "/on" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) if resp == None : print 'The server couldn\'t fulfill the request.' raise IsyResponseError("Batch") else : self._printXML(resp) return resp #/rest/batterypoweredwrites def batterypoweredwrites(self, on=-1) : """ Battery Powered Writes args values: 1 = Turn Batch mode on 0 = Turn Batch mode off -1 or None = Return Batch mode status returns status of Battery Powered device operations calls /rest/batteryPoweredWrites/ """ xurl = "rest/batteryPoweredWrites/" if on == 0 : xurl += "/off" elif on == 1 : xurl += "/on" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) if resp != None : self._printXML(resp) return et2d(resp) def electricity(self): """ electricity status args: none Returns electricity module info, "Energy Monitor", "Open ADR" and "Flex Your Power" status Only applicable to 994 Z Series. calls: /rest/electricity """ xurl = "/rest/electricity" if self.debug & 0x02 : print("xurl = " + xurl) resp = self._getXMLetree(xurl) if resp != None : self._printXML(resp) return et2d(resp) ## ## Callback functions ## def callback_set(self, nid, func, *args): """set a callback function for a Node args: node id referance to a function * arg list Sets up a callback function that will be called whenever there is a change event for the specified node Only one callback per node is supported, If a callback funtion is already registared for node_id it will be replaced requires IsyClass option "eventupdates" to to set """ if not isinstance(func, collections.Callable) : raise IsyValueError("callback_set : Invalid Arg, function not callable") # func.__repr__() nodeid = self._node_get_id(nid) if nodeid == None : raise LookupError("no such Node : " + str(nodeid) ) self.callbacks[nodeid] = (func, args) def callback_get(self, nid): """get a callback funtion for a Nodes args: node id returns referance to registared callback function for a node no none exist then value "None" is returned """ nodeid = self._node_get_id(nid) if nodeid != None and nodeid in self.callbacks : return self.callbacks[nodeid] return None def callback_del(self, nid): """delete a callback funtion args: node id delete a callback funtion for a Node, if exists. no error is raised if callback does not exist """ nodeid = self._node_get_id(nid) if nodeid != None and nodeid in self.callbacks : del self.callbacks[nodeid] ## ## support functions ## def _printinfolist(self, uobj, ulabel="_printinfo"): print("\n\n" + ulabel + " : ") for attr in dir(uobj) : print(" obj.%s = %s" % (attr, getattr(uobj, attr))) print("\n\n") ## ## Special Methods ## # Design question : # __get/setitem__ returns a node obj ? def __getitem__(self, nodeaddr): """ access node obj line a dictionary entery """ if nodeaddr in self.nodeCdict : return self.nodeCdict[str(nodeaddr)] else : return self.get_node(nodeaddr) def __setitem__(self, nodeaddr, val): """ This allows you to set the status of a Node by addressing it as dictionary entery """ val = int(val) if val > 0 : self.node_comm(nodeaddr, "DON", val) else : self.node_comm(nodeaddr, "DOF") def __delitem__(self, nodeaddr): raise IsyPropertyError("__delitem__ : can't delete nodes : " + str(nodeaddr) ) def __iter__(self): """ iterate though Node Obj (see: node_iter() ) """ return self.node_iter() def __del__(self): if self.debug & 0x80 : print "__del__ ", self.__repr__() #if isinstance(self._isy_event, ISYEvent) : # #ISYEvent._stop_event_loop() if hasattr(self._isy_event, "_shut_down") : self._isy_event._shut_down = 1 self.nodeCdict.clear() self.varCdict.clear() self.progCdict.clear() self.folderCdict.clear() # the reasion for his is that #for k in self.nodeCdict.keys() : # del self.nodeCdict[k] #for k in self.varCdict.keys() : # del self.varCdict[k] #for k in self.progCdict.keys() : # del self.progCdict[k] #for k in self.folderCdict.keys() : # del self.folderCdict[k] def __repr__(self): return "<Isy %s at 0x%x>" % (self.addr, id(self)) # def debugerror(self) : # print("debugerror") # raise IsyPropertyError("debugerror : test IsyPropertyError ") def _printdict(self, dic): """ Pretty Print dictionary """ print("===START===") pprint.pprint(dic) print("===END===") def _writedict(self, d, filen): """ Pretty Print dict to file """ with open(filen, 'w') as fi: pprint.pprint(d, fi)
'Event.control']) event = [{ 'measurement': 'isy', 'tags': tags, 'fields': data }] app.log.debug('Event data: %s' % event) handler.postEvent(event) # Setup ISY socket listener # Be aware: Even though we are able to update the config at runtime # we do not take down the web socket subscription once established server = ISYEvent() retries = 0 while True: try: server.subscribe(addr=isy_addr, userl=isy_user, userp=isy_pass) break except Exception as e: retries += 1 app.log.warn(e) app.log.warn('Cannot connect to ISY. Attempt %n of %n', retries, app.config.retries)