def read_xpl(self, message): switch = None device = None data = None if 'switch' in message.data: switch = message.data['switch'] if 'device' in message.data: device = message.data['device'] if 'data' in message.data: data = message.data['data'] print("Message XPL %s" %message) if (switch != None and device != None and data != None): r = self.ow.write(device, switch, data) mess = XplMessage() mess.set_type("xpl-trig") mess.set_schema("sensor.basic") mess.add_data({"device" : device}) mess.add_data({"command" : "switch"+switch}) self.myxpl.send(mess) print("Setting PIO "+switch+"="+data+" for device "+device) mess2 = XplMessage() mess2.set_type("xpl-trig") mess2.set_schema("sensor.basic") mess2.add_data({"device" : device}) mess2.add_data({"data"+switch : r }) mess2.add_data({"type" : "PIO_ALL"}) self.myxpl.send(mess2)
def send_dawndusk(self, state): """ Send a xPL message of the type DAWNDUSK.BASIC when the sun goes down or up. This function is called by the internal cron @param state : DAWN or DUSK """ self.log.debug("dawndusk.sendDawnDusk() : Start ...") mess = XplMessage() mess.set_type("xpl-trig") mess.set_schema("dawndusk.basic") mess.add_data({"type": "dawndusk"}) mess.add_data({"status": state}) self.myxpl.send(mess) self.add_next_event() for dev in self.devices: self.log.debug("sendMessages() : Send message to device %s" % dev) mess = XplMessage() mess.set_type(self.devices[dev]["xpltype"]) mess.set_schema(self.devices[dev]["schema"]) mess.add_data({self.devices[dev]["command"] : \ self.devices[dev][state]}) mess.add_data({self.devices[dev]["addname"]: dev}) self.myxpl.send(mess) self.log.info("dawndusk : send signal for %s" % state) self.log.debug("dawndusk.sendDawnDusk() : Done :-)")
def _command_cb(self, f): ''' Called by the plcbus library when a command has been sent. If the commands need an ack, this callback will be called only after the ACK has been received @param : plcbus frame as an array ''' if f["d_command"] == "GET_ALL_ID_PULSE": data = int("%s%s" % (f["d_data1"], f["d_data2"])) house = f["d_home_unit"][0] for i in range(0, 16): unit = data >> i & 1 code = "%s%s" % (house, i + 1) if unit and not code in self._probe_status: self._probe_status[code] = "" self.log.info("New device discovered : %s" % code) elif (not unit) and code in self._probe_status: del self._probe_status[code] elif f["d_command"] == "GET_ALL_ON_ID_PULSE": data = "%s%s" % (bin(f["d_data1"])[2:].zfill(8), bin( f["d_data2"])[2:].zfill(8)) print("f : %s" % f) print("data : %s" % data) house = f["d_home_unit"][0] item = 16 for c in data: unit = int(c) code = "%s%s" % (house, item) print("Etat : %s " % code, unit) if code in self._probe_status and (self._probe_status[code] != str(unit)): print('DEBUG in rentre dans le IF detection GET_ALL_ON') self._probe_status[code] = str(unit) if unit == 1: command = "ON" else: command = "OFF" mess = XplMessage() mess.set_type('xpl-trig') mess.set_schema('plcbus.basic') mess.add_data({ "usercode": f["d_user_code"], "device": code, "command": command }) self.myxpl.send(mess) item = item - 1 else: mess = XplMessage() mess.set_type('xpl-trig') mess.set_schema('plcbus.basic') mess.add_data({ "usercode": f["d_user_code"], "device": f["d_home_unit"], "command": f["d_command"], "data1": f["d_data1"], "data2": f["d_data2"] }) self.myxpl.send(mess)
def _set_config(self, plugin, hostname, key, value): ''' Send a config value message for an element's config item @param plugin : the plugin of the element @param hostname : hostname @param key : the key to set @param value : the value to set ''' try: self._db.set_plugin_config(technology, hostname, key, value) mess = XplMessage() mess.set_type('xpl-stat') mess.set_schema('domogik.config') mess.add_data({'plugin': plugin}) mess.add_data({'hostname': hostname}) mess.add_data({'key': key}) mess.add_data({'value': value}) self.myxpl.send(mess) except: traceback.print_exc() msg = "Error while setting h=%s, t=%s, k=%s, v=%s" % ( hostname, techno, key, value) print(msg) self.log.warn(msg) return "None"
def _send_config(self, plugin, hostname, key, value, element=None): ''' Send a config value message for an element's config item @param plugin : the plugin of the element @param hostname : hostname @param element : the name of the element @param key : the key or list of keys of the config tuple(s) to fetch @param value : the value or list of values corresponding to the key(s) ''' msg = "Response h=%s, t=%s, k=%s, v=%s" % (hostname, plugin, key, value) print(msg) self.log.debug(msg) mess = XplMessage() mess.set_type('xpl-stat') mess.set_schema('domogik.config') mess.add_data({'plugin': plugin}) mess.add_data({'hostname': hostname}) if element: mess.add_data({'element': element}) # If key/value are lists, then we add a key=value for each item if isinstance(key, list): for (_key, _val) in zip(key, value): mess.add_data({_key: _val}) else: mess.add_data({key: value}) # mess.set_conf_key('target', plugin) self.myxpl.send(mess)
def send_xpl(self, frame): ''' Send a frame from teleinfo device to xpl @param frame : a dictionnary mapping teleinfo informations ''' known_keys = [] # used to filter duplicate keys (it happens) my_temp_message = XplMessage() my_temp_message.set_type("xpl-stat") if "ADIR1" in frame: my_temp_message.set_schema("teleinfo.short") else: my_temp_message.set_schema("teleinfo.basic") try: key = None val = None for entry in frame: key = re.sub('[^\w\.]', '', entry["name"].lower()) val = re.sub('[^\w\.]', '', entry["value"].lower()) if key not in known_keys: my_temp_message.add_data({key: val}) known_keys.append(key) my_temp_message.add_data({"device": "teleinfo"}) except: self.log.error( u"Error while creating xpl message : {0} ; key : {1} ; val : {2}. Error is : {3}" .format(my_temp_message, key, val, traceback.formar_exc())) try: self.myxpl.send(my_temp_message) except XplMessageError: #We ignore the message if some values are not correct because it can happen with teleinfo ... self.log.debug( u"Bad xpl message to send. This may happen due to some invalid teleinfo data. Xpl message is : {0}" .format(str(my_temp_message))) pass
def halt_job(self, device, extkey="state"): """ Stop a job and delete the device. Job is permanently deleted. :param device: the device/job to halt :type device: str :param extkey: the message key to look for ("state" by default) :type extkey: str :return: the state sent by cron plugin : "started"|"stopped"|"halted" :rtype: str """ configmess = XplMessage() configmess.set_type("xpl-cmnd") configmess.set_schema("timer.basic") configmess.add_data({"action": "halt"}) configmess.add_data({"device": device}) try: res = self.query(device, configmess, extkey=extkey) #print res return res except: if self.log != None: self.log.error("cron_query : %s" % (traceback.format_exc())) return False
def start_date_job(self, device, nstmess, sdate): ''' Add and start a date job to the cron plugin :param device: the device/job to start :type device: str :param configmess: the XPL configuration message to send to the plugin :type configmess: XplMessage :param nstMess: the XPL message which will be sent by the cron job :type nstMess: XplMessage :param sdate: the date/time to run the job :type sdate: datetime :return: the state sent by cron plugin : "started"|"stopped"|"halted" :rtype: str ''' if sdate == None: return False configmess = XplMessage() configmess.set_type("xpl-cmnd") configmess.set_schema("timer.basic") configmess.add_data({"devicetype": "date"}) configmess.add_data({"device": device}) configmess.add_data({"action": "start"}) configmess.add_data({"date": date_to_xpl(sdate)}) return self.start_job(device, configmess, nstmess)
def sendxPL_trig(self, msgtrig): """Envoie un message trig sur le hub xPL""" mess = XplMessage() if 'info' in msgtrig: self.log.error ("Error : Node %s unreponsive" % msgtrig['node']) elif 'Find' in msgtrig: print("node enregistré : %s" % msgtrig['Find']) elif 'typexpl' in msgtrig: mess.set_type(msgtrig['typexpl']) mess.set_schema(msgtrig['schema']) if msgtrig['genre'] == 'actuator' : if msgtrig['level'] in [0, 'False', False] : cmd ="off" elif msgtrig['level'] in [255, 'True', True]: cmd ="on" else: cmd ='level' mess.add_data({'device' : msgtrig['device'], 'command' : cmd, 'level': msgtrig['level']}) if msgtrig.has_key('type'): mess.add_data({'type' : msgtrig['type'] }) elif msgtrig['genre'] == 'sensor' : # tout sensor if msgtrig['type'] =='status' : # gestion du sensor binary pour widget binary mess.add_data({'device' : msgtrig['device'], 'type' : msgtrig['type'] , 'current' : 'true' if msgtrig['value'] else 'false'}) else : mess.add_data({'device' : msgtrig['device'], 'type' : msgtrig['type'] , 'current' : msgtrig['value'] }) if msgtrig.has_key('units') and msgtrig['units'] !='' : mess.add_data({'units' : msgtrig['units'] }) print mess self.myxpl.send(mess) elif 'command' in msgtrig and msgtrig['command'] == 'Info': print("Home ID is %s" % msgtrig['Home ID'])
def cmnd_scninfo(self, myxpl, message): """ @param myxpl : The XPL sender @param message : The XPL message lighting.request This allows a sender to learn about capabilities, networks, devices and scene that can be controlled and addressed request=[gateinfo|netlist|netinfo|devlist|devinfo|devstate|scnlist|scninfo] [network=ID] [[device=ID]|[scene=ID]][channel=#] lighting.devinfo Provides detailed information about a specific device network=ID device=ID status=[ok|not-found] name=[device name, if known] report-on-manual=[true|false] [room=room name] [floor=floor name] [comment=comments] [manufacturer=id,name] [product=id,name] [firmware-version=x.y] channel-count=# primary-channel=# channel=#,is-dimmable (true/false),default-fade-rate,level(0-100) scene-count=# scene=sceneID,channel,level,fade-rate """ #print "scene info" mess = XplMessage() mess.set_type("xpl-stat") mess.set_schema("lighting.config") mess.add_data({"command": "scninfo"}) scene = None if 'scene' in message.data: scene = message.data['scene'] if 'client' in message.data: mess.add_data({"client": message.data['client']}) if not self.is_valid(scene): mess.add_data({"scene": scene}) mess.add_data({"status": "not-found"}) else: mess.add_data({"status": self._scenes[scene]["status"]}) mess.add_data({"scene": scene}) for field in self.fields: if field in self._scenes[scene] and \ self._scenes[scene][field] != None: mess.add_data({field: self._scenes[scene][field]}) mess.add_data({"device-count": self.device_count(scene)}) for dev in self._scenes[scene]["devices"]: infs = self.scene_device_info(scene, dev) for d in infs: mess.add_data({"device": d}) myxpl.send(mess)
def trig_scninfo(self, scene): """ Trig an update on a scene """ #print "scene info" mess = XplMessage() mess.set_type("xpl-trig") mess.set_schema("lighting.config") mess.add_data({"command": "scninfo"}) if not self.is_valid(scene): mess.add_data({"scene": scene}) mess.add_data({"status": "not-found"}) else: mess.add_data({"status": self._scenes[scene]["status"]}) mess.add_data({"scene": scene}) for field in self.fields: if field in self._scenes[scene] and \ self._scenes[scene][field] != None: mess.add_data({field: self._scenes[scene][field]}) mess.add_data({"device-count": self.device_count(scene)}) for dev in self._scenes[scene]["devices"]: infs = self.scene_device_info(scene, dev) for d in infs: mess.add_data({"device": d}) self._gateway.myxpl.send(mess)
def cmnd_register(self, myxpl, command, message): """ Register a client command=register client=name activate=activate deactivate=deactivate """ mess = XplMessage() mess.set_type("xpl-trig") mess.set_schema("lighting.config") mess.add_data({"command": command}) client = None if 'client' in message.data: client = message.data['client'] activate = None if 'activate' in message.data: activate = message.data['activate'] deactivate = None if 'deactivate' in message.data: deactivate = message.data['deactivate'] if client == None: self.log.error("Command = %s : Missing parameter _ client _." % (command)) mess.add_data({"error": "Missing parameter : client"}) elif not self.clients.is_valid(client): mess.add_data({"client": client}) mess.add_data({"error": "Client already registered : %s" % client}) self.log.error("Command = %s : Client _ %s _ already registered." % (command, client)) else: self.clients.add_client(client, activate, deactivate) mess.add_data({"client": client}) myxpl.send(mess)
def dawndusk_trig_cb(self, message): """ General callback for all command messages @param message : an XplMessage object """ self.log.debug("dawndusk.dawndusk_trig_cb() : Start ...") mtype = None if 'type' in message.data: mtype = message.data['type'] status = None if 'status' in message.data: status = message.data['status'] self.log.debug("dawndusk.dawndusk_trig_cb : type %s received \ with status %s" % (mtype, status)) if mtype == "dawndusk" and status != None: #We receive a trig indicating that the dawn or dus has occured. #We need to schedule the next one self.add_next_event() for dev in self.devices: self.log.debug("sendMessages() : Send message to device %s" % dev) mess = XplMessage() mess.set_type(self.devices[dev]["xpltype"]) mess.set_schema(self.devices[dev]["schema"]) mess.add_data({self.devices[dev]["command"] : \ self.devices[dev][status]}) mess.add_data({self.devices[dev]["addname"]: dev}) self.myxpl.send(mess) self.log.debug("dawndusk.dawndusk_trig_cb() : Done :)")
def send_xpl(self, teleinfo): """ send xPL on the network """ self.log.debug("Send xPL msg with a line of teleinfo data") #print "callback : receive frame is : \n\n" #print teleinfo #print "\n\n" # creation du message xPL msg = XplMessage() msg.set_type("xpl-stat") #msg.set_schema("sensor.basic") msg.set_schema("teleinfo.basic") #msg.add_data({"timestamp" : teleinfo["timestamp"]}) #msg.add_data({"recdate" : teleinfo["recdate"]}) #msg.add_data({"rectime" : teleinfo["rectime"]}) msg.add_data({"optarif" : teleinfo["optarif"]}) msg.add_data({"hchp" : teleinfo["hchp"]}) msg.add_data({"hchc" : teleinfo["hchc"]}) msg.add_data({"ptec" : teleinfo["ptec"]}) msg.add_data({"inst1" : teleinfo["inst1"]}) msg.add_data({"imax1" : teleinfo["imax1"]}) msg.add_data({"papp" : teleinfo["papp"]}) try: self.myxpl.send(msg) except XplMessageError: self.log.debug(u"Bad xpl message to send. Xpl message is : {0}".format(str(msg))) pass
def cmnd_scnlist(self, myxpl, message): """ Return the list of scenes @param myxpl : The XPL sender @param message : The XPL message lighting.request This allows a sender to learn about capabilities, networks, scenes and scene that can be controlled and addressed request=[gateinfo|netlist|netinfo|devlist|devinfo|devstate|scnlist|scninfo] [network=ID] [[scene=ID]|[scene=ID]][channel=#] lighting.devlist Enumerates the valid scenes on a network network=ID status=[ok|not-found] scene-count=# scene=ID,ID,ID,ID... """ #print "scene list" mess = XplMessage() mess.set_type("xpl-stat") mess.set_schema("lighting.config") if 'client' in message.data: mess.add_data({"client": message.data['client']}) mess.add_data({"command": "scnlist"}) mess.add_data({"scenes": self.scenes()}) mess.add_data({"scene-count": self.count()}) mess.add_data({"status": "ok"}) myxpl.send(mess)
def test_610_list_dawnalarm1(self): message = XplMessage() message.set_type("xpl-cmnd") message.set_schema("timer.basic") message.add_data({"action" : "list"}) keys = ['devices'] self.assertTrue(self.query("device", message, keys))
def cmnd_scndel(self, myxpl, message): """ Delete a scene @param myxpl : The XPL sender @param message : The XPL message lighting.config scene=ID device=ID name=scene name """ mess = XplMessage() mess.set_type("xpl-trig") mess.set_schema("lighting.config") mess.add_data({"command": "scndel"}) scene = None if 'scene' in message.data: scene = message.data['scene'] if not self.is_valid(scene): mess.add_data({"scene": scene}) mess.add_data({"status": "not-found"}) else: mess.add_data({"status": "ok"}) mess.add_data({"scene": scene}) self._scenes[scene]["devices"] = {} self.trig_scninfo(scene) self.remove(scene) myxpl.send(mess)
def start_timer_job(self, device, nstmess, frequence, duration=0): ''' Add and start a job to the cron plugin :param device: the device/job to start :type device: str :param configmess: the XPL configuration message to send to the plugin :type configmess: XplMessage :param nstMess: the XPL message which will be sent by the cron job :type nstMess: XplMessage :param frequence: int :type frequence: the frequence of the signal (in seconds). :param duration: the number of pulse to live. :type duration: int :return: the state sent by cron plugin : "started"|"stopped"|"halted" :rtype: str ''' if frequence == 0: return False configmess = XplMessage() configmess.set_type("xpl-cmnd") configmess.set_schema("timer.basic") configmess.add_data({"action": "start"}) configmess.add_data({"device": device}) configmess.add_data({"devicetype": "timer"}) configmess.add_data({"frequence": frequence}) if duration != 0: configmess.add_data({"duration": duration}) return self.start_job(device, configmess, nstmess)
def req_cmndinfo(self, myxpl, message, request): """ """ plugin = None if 'plugin' in message.data: plugin = message.data['plugin'] if plugin != self._parent._name: return False mess = XplMessage() mess.set_type("xpl-stat") mess.set_schema("helper.cmndinfo") mess.add_data({"plugin" : self._parent._name}) try: cmnd = None if 'command' in message.data: cmnd = message.data['command'] if not self.is_valid_cmnd(cmnd): mess.add_data({"command" : cmnd}) mess.add_data({"status" : "not-found"}) else: mess.add_data({"command" : cmnd}) if "param-list" in self._parent.helpers[cmnd] \ and self._parent.helpers[cmnd]["param-list"] != "": mess.add_data({"param-list" : self._parent.helpers[cmnd]["param-list"]}) for p in self._parent.helpers[cmnd]["param-list"].split(","): mess.add_data({p : self._parent.helpers[cmnd][p]}) mess.add_data({"status" : "ok"}) except: mess.add_data({"status" : "error"}) self._parent.log.error("" + traceback.format_exc()) myxpl.send(mess)
def stop_job(self, device, extkey="state"): """ Stop a job to the cron plugin. The cron job could be restarted via a resume command. :param device: the device/job to stop :type device: str :param extkey: the message key to look for ("state" by default) :type extkey: str :return: the state sent by cron plugin : "started"|"stopped"|"halted" :rtype: str """ configmess = XplMessage() configmess.set_type("xpl-cmnd") configmess.set_schema("timer.basic") configmess.add_data({"action": "stop"}) configmess.add_data({"device": device}) try: res = self.query(device, configmess, extkey=extkey) return res except: if self.log != None: self.log.error("cron_query : %s" % (traceback.format_exc())) return False
def req_gate_info(self, myxpl, message): """ Requests the sending of an mvhr.gateinfo message containing details of the xPL connector software. @param myxpl : The XPL sender @param message : The XPL message mvhr.request { request=gateinfo } mvhr.gateinfo { protocol=[X10|UPB|CBUS|ZWAVE|INSTEON] description= version= author= info-url= zone-count=# } """ mess = XplMessage() mess.set_type("xpl-stat") mess.set_schema("mvhr.gateinfo") mess.add_data({"protocol" : "MVHR"}) mess.add_data({"description" : "Manage an mvhr with xpl"}) mess.add_data({"version" : "0.1"}) mess.add_data({"author" : "Domogik Team"}) mess.add_data({"info-url" : "http://wiki.domogik.org/plugin_hvac_mvhr"}) mess.add_data({"request-list" : "mvhrinfo,mvhr"}) mess.add_data({"command-list" : "none"}) mess.add_data({"device-list" : self.mvhr_name}) myxpl.send(mess)
def send_xpl(self, frame): ''' Send a frame from teleinfo device to xpl @param frame : a dictionnary mapping teleinfo informations ''' my_temp_message = XplMessage() my_temp_message.set_type("xpl-stat") if "ADIR1" in frame: my_temp_message.set_schema("teleinfo.short") else: my_temp_message.set_schema("teleinfo.basic") try: key = None val = None for entry in frame: key = re.sub('[^\w\.]','',entry["name"].lower()) val = re.sub('[^\w\.]','',entry["value"].lower()) my_temp_message.add_data({ key : val }) my_temp_message.add_data({"device": "teleinfo"}) except : self.log.warn("Message ignored : %s ; last key : %s ; last val : %s" % (my_temp_message, key, val)) try: self.myxpl.send(my_temp_message) except XplMessageError: #We ignore the message if some values are not correct because it can happen with teleinfo ... pass
def cmd_fake(self, message): ### sub send an answer for fake device of scene plugin if message.data['number'] not in self.fake_stat: self.fake_stat[message.data['number']] = '' if message.data['command'] == "fake-true" or message.data[ 'command'] == "fake-false" and message.type == "xpl-cmnd": print("Réception xpl cmnd") msg = XplMessage() msg.set_schema('scene.basic') sender = "domogik-scene0.%s" % self.get_sanitized_hostname() msg.set_source(sender) if self.fake_stat[ message.data['number']] != message.data['command']: msg.set_type('xpl-trig') self.fake_stat[ message.data['number']] = message.data['command'] else: msg.set_type('xpl-stat') if message.data['command'] == "fake-true": msg.add_data({'stats': 'true'}) if message.data['command'] == "fake-false": msg.add_data({'stats': 'false'}) msg.add_data({'number': message.data['number']}) self.myxpl.send(msg)
def send_xpl_sensor(self, datas, id, xpltype): """ Send xpl-trig to give status change """ type = { 'tem': 'temp', 'hum': 'humidity', 'bat': 'battery', 'kwh': 'energy', 'kw': 'power', 'tra': 'raintotal', 'cra': 'rainrate', 'uvl': 'uv', 'awi': 'speed', 'drt': 'direction', 'temc': 'setpoint', 'sta': 'status', 'flag3': 'status' } for data in datas: elmt = data.split(':') if elmt[0] in type.keys(): msg = XplMessage() msg.set_type(xpltype) msg.set_schema('sensor.basic') msg.add_data({'device': id}) msg.add_data({'type': type[elmt[0]]}) msg.add_data({'current': elmt[1]}) self.hxpl.send(msg)
def forge_message(self): ''' Create the message based on script arguments ''' message = XplMessage() message.set_type(self.options.type) if self.options.source != None: print(u"Source forced : %s" % self.options.source) message.set_source(self.options.source) if self.options.target != None: print(u"Target forced : %s" % self.options.target) message.set_target(self.options.target) message.set_schema(self.options.schema) datas = self.options.message.split(',') for data in datas: if "=" not in data: self.log.error(u"Bad formatted commands. Must be key=value") self.usage() exit(4) else: message.add_data({ data.split("=", 1)[0].strip(): data.split("=", 1)[1].strip() }) return message
def send_xplStat(self, data): """ Send xPL cmd message on network """ msg = XplMessage() msg.set_type("xpl-stat") msg.set_schema("sensor.basic") msg.add_data(data) self.myxpl.send(msg)
def test_260_add_duplicate_testjob1(self): message = XplMessage() message.set_type("xpl-trig") message.set_schema("sensor.basic") message.add_data({"current": "high"}) message.add_data({"device": "tsjob1"}) self.assertFalse( self.cronquery.start_timer_job("testjob1", message, 45))
def _discover_hosts(self): """ Send a hbeat.request to discover managers """ mess = XplMessage() mess.set_type('xpl-cmnd') mess.set_target("*") mess.set_schema('hbeat.request') mess.add_data({'command': 'request'}) self.myxpl.send(mess)
def test_520_add_bad_date(self): self.cronquery.halt_job("testjob1") message = XplMessage() message.set_type("xpl-trig") message.set_schema("sensor.basic") message.add_data({"current": "high"}) message.add_data({"device": "tsjob1"}) self.assertTrue(self.cronquery.start_date_job("testjob1",message,\ datetime.datetime.today() - datetime.timedelta(seconds=120)) != True)
def test_420_add_bad_interval(self): self.cronquery.halt_job("testjob1") message = XplMessage() message.set_type("xpl-trig") message.set_schema("sensor.basic") message.add_data({"current": "high"}) message.add_data({"device": "tsjob1"}) self.assertTrue( self.cronquery.start_interval_job("testjob1", message) != True)