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 _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 _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 query(self, plugin, key, element="", nb_test=QUERY_CONFIG_NUM_TRY): """ Ask the config system for the value. Calling this function will make your program wait until it got an answer @param plugin : the plugin of the item requesting the value, must exists in the config database @param element : the name of the element which requests config, None if it's a technolgy global parameter @param key : the key to fetch corresponding value, if it's an empty string, all the config items for this plugin will be fetched """ if nb_test == 0: raise RuntimeError("Maximum tries to get config reached") msg = "QC : ask > h=%s, t=%s, k=%s" % (self.__myxpl.p.get_sanitized_hostname(), plugin, key) print (msg) self.log.debug(msg) l = Listener( self._query_cb, self.__myxpl, { "schema": "domogik.config", "xpltype": "xpl-stat", "plugin": plugin, "hostname": self.__myxpl.p.get_sanitized_hostname(), }, ) self._keys[key] = Event() self._l[key] = l mess = XplMessage() mess.set_type("xpl-cmnd") mess.set_target(self.target) mess.set_schema("domogik.config") mess.add_data({"plugin": plugin}) mess.add_data({"hostname": self.__myxpl.p.get_sanitized_hostname()}) if element: mess.add_data({"element": element}) mess.add_data({"key": key}) try: self.__myxpl.send(mess) self._keys[key].wait(self.query_timeout) if not self._keys[key].is_set(): msg = "No answer received for t = %s, k = %s, check your xpl setup" % (plugin, key) self.log.error(msg) # raise RuntimeError(msg) self.query(plugin, key, element, nb_test - 1) except KeyError: pass if self._result[key] != "None": return self._result[key] else: return None
def query(self, plugin, key, element='', nb_test=QUERY_CONFIG_NUM_TRY): ''' Ask the config system for the value. Calling this function will make your program wait until it got an answer @param plugin : the plugin of the item requesting the value, must exists in the config database @param element : the name of the element which requests config, None if it's a technolgy global parameter @param key : the key to fetch corresponding value, if it's an empty string, all the config items for this plugin will be fetched ''' if nb_test == 0: raise RuntimeError("Maximum tries to get config reached") msg = "QC : ask > h=%s, t=%s, k=%s" % \ (self.__myxpl.p.get_sanitized_hostname(), plugin, key) print(msg) self.log.debug(msg) l = Listener( self._query_cb, self.__myxpl, { 'schema': 'domogik.config', 'xpltype': 'xpl-stat', 'plugin': plugin, 'hostname': self.__myxpl.p.get_sanitized_hostname() }) self._keys[key] = Event() self._l[key] = l mess = XplMessage() mess.set_type('xpl-cmnd') mess.set_target(self.target) mess.set_schema('domogik.config') mess.add_data({'plugin': plugin}) mess.add_data({'hostname': self.__myxpl.p.get_sanitized_hostname()}) if element: mess.add_data({'element': element}) mess.add_data({'key': key}) try: self.__myxpl.send(mess) self._keys[key].wait(self.query_timeout) if not self._keys[key].is_set(): msg = "No answer received for t = %s, k = %s, check your xpl setup" % \ (plugin, key) self.log.error(msg) #raise RuntimeError(msg) self.query(plugin, key, element, nb_test - 1) except KeyError: pass if self._result[key] != "None": return self._result[key] else: return None
def query(self, technology, key, element = '', nb_test = QUERY_CONFIG_NUM_TRY): ''' Ask the config system for the value. Calling this function will make your program wait until it got an answer @param technology : the technology of the item requesting the value, must exists in the config database @param element : the name of the element which requests config, None if it's a technolgy global parameter @param key : the key to fetch corresponding value, if it's an empty string, all the config items for this technology will be fetched ''' if nb_test == 0: raise RuntimeError("Maximum tries to get config reached") msg = "QC : ask > h=%s, t=%s, k=%s" % \ (self.__myxpl.p.get_sanitized_hostname(), technology, key) print(msg) self.log.debug(msg) l = Listener(self._query_cb, self.__myxpl, {'schema': 'domogik.config', 'xpltype': 'xpl-stat', 'technology': technology, 'hostname' : self.__myxpl.p.get_sanitized_hostname()}) self._keys[key] = Event() self._l[key] = l mess = XplMessage() mess.set_type('xpl-cmnd') mess.set_target(self.target) mess.set_schema('domogik.config') mess.add_data({'technology': technology}) mess.add_data({'hostname': self.__myxpl.p.get_sanitized_hostname()}) if element: mess.add_data({'element': element}) mess.add_data({'key': key}) try: self.__myxpl.send(mess) self._keys[key].wait(self.query_timeout) if not self._keys[key].is_set(): msg = "No answer received for t = %s, k = %s, check your xpl setup" % \ (technology, key) self.log.error(msg) #raise RuntimeError(msg) self.query(technology, key, element, nb_test - 1) except KeyError: pass if self._result[key] != "None": return self._result[key] else: return None
def set(self, technology, key, value): ''' Send a xpl message to set value for a param @param technology : the technology of the item @param key : the key to set corresponding value, @param value : the value to set ''' mess = XplMessage() mess.set_type('xpl-cmnd') mess.set_target(self.target) mess.set_schema('domogik.config') mess.add_data({'technology': technology}) mess.add_data({'hostname': self.__myxpl.p.get_sanitized_hostname()}) mess.add_data({'key': key}) mess.add_data({'value': value}) self.__myxpl.send(mess)
def set(self, plugin, key, value): ''' Send a xpl message to set value for a param @param plugin : the plugin of the item @param key : the key to set corresponding value, @param value : the value to set ''' mess = XplMessage() mess.set_type('xpl-cmnd') mess.set_target(self.target) mess.set_schema('domogik.config') mess.add_data({'plugin': plugin}) mess.add_data({'hostname': self.__myxpl.p.get_sanitized_hostname()}) mess.add_data({'key': key}) mess.add_data({'value': value}) self.__myxpl.send(mess)
def set(self, plugin, key, value): """ Send a xpl message to set value for a param @param plugin : the plugin of the item @param key : the key to set corresponding value, @param value : the value to set """ mess = XplMessage() mess.set_type("xpl-cmnd") mess.set_target(self.target) mess.set_schema("domogik.config") mess.add_data({"plugin": plugin}) mess.add_data({"hostname": self.__myxpl.p.get_sanitized_hostname()}) mess.add_data({"key": key}) mess.add_data({"value": value}) self.__myxpl.send(mess)
def _SendHeartbeat(self, target="*", test="", schema="hbeat.app"): """ Send heartbeat message in broadcast on the network, on the bus port (3865) This make the application able to be discovered by the hub This method is not called by childs, so no need to protect it. """ self._lock_status.acquire() self.p.log.debug("send hbeat") mesg = XplMessage() mesg.set_type("xpl-stat") mesg.set_hop_count(1) mesg.set_source(self._source) mesg.set_target(target) mesg.set_schema(schema) mesg.add_single_data("interval", "5") mesg.add_single_data("port", self.port) mesg.add_single_data("remote-ip", self._ip) if schema != "hbeat.end": if self._status == 0: msg = ( "HUB discovery > looking for the hub. I hope there is one hub, Domogik won't work without the hub!" ) self.p.log.info(msg) print(msg) elif self._status == 1: msg = "HUB discovery > hub found, configuration in progress" self.p.log.info(msg) print(msg) elif self._status == 2: pass else: msg = ( "Oops! Wrong status for the hbeat message : %s. Please create a bug report for this!" % self._status ) self.p.log.warning(msg) print(msg) mesg.add_single_data("status", self._status) if self is not None: self.send(mesg) self._lock_status.release()
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 _SendHeartbeat(self, target='*', test="", schema="hbeat.app"): """ Send heartbeat message in broadcast on the network, on the bus port (3865) This make the application able to be discovered by the hub This method is not called by childs, so no need to protect it. """ self._lock_status.acquire() self.p.log.debug("send hbeat") mesg = XplMessage() mesg.set_type("xpl-stat") mesg.set_hop_count(1) mesg.set_source(self._source) mesg.set_target(target) mesg.set_schema(schema) mesg.add_single_data("interval", "5") mesg.add_single_data("port", self.port) mesg.add_single_data("remote-ip", self._ip) if schema != 'hbeat.end': if self._status == 0: msg = "HUB discovery > looking for the hub. I hope there is one hub, Domogik won't work without the hub!" self.p.log.info(msg) print(msg) elif self._status == 1: msg = "HUB discovery > hub found, configuration in progress" self.p.log.info(msg) print(msg) elif self._status == 2: pass else: msg = "Oops! Wrong status for the hbeat message : %s. Please create a bug report for this!" % self._status self.p.log.warning(msg) print(msg) mesg.add_single_data("status", self._status) if self is not None: self.send(mesg) self._lock_status.release()
def _send_xpl_command(self, data): """ Reply to config.get MQ req @param data : MQ req message Needed info in data: - cmdid => command id to send - cmdparams => key/value pair of all params needed for this command """ with self._db.session_scope(): self.log.info(u"Received new cmd request: {0}".format(data)) failed = False request = data.get_data() if 'cmdid' not in request: failed = "cmdid not in message data" if 'cmdparams' not in request: failed = "cmdparams not in message data" if not failed: # get the command cmd = self._db.get_command(request['cmdid']) if cmd is not None: if cmd.xpl_command is not None: xplcmd = cmd.xpl_command xplstat = self._db.get_xpl_stat(xplcmd.stat_id) if xplstat is not None: # get the device from the db dev = self._db.get_device(int(cmd.device_id)) msg = XplMessage() if not dev['client_id'] in self.client_xpl_map.keys(): self._load_client_to_xpl_target() if not dev['client_id'] in self.client_xpl_map.keys(): failed = "Can not fincd xpl source for {0} client_id".format(dev['client_id']) else: msg.set_target(self.client_xpl_map[dev['client_id']]) msg.set_source(self.myxpl.get_source()) msg.set_type("xpl-cmnd") msg.set_schema(xplcmd.schema) # static paramsw for par in xplcmd.params: msg.add_data({par.key : par.value}) # dynamic params for par in cmd.params: if par.key in request['cmdparams']: value = request['cmdparams'][par.key] # chieck if we need a conversion if par.conversion is not None and par.conversion != '': if dev['client_id'] in self.client_conversion_map: if par.conversion in self.client_conversion_map[dev['client_id']]: exec(self.client_conversion_map[dev['client_id']][par.conversion]) value = locals()[par.conversion](value) msg.add_data({par.key : value}) else: failed = "Parameter ({0}) for device command msg is not provided in the mq message".format(par.key) if not failed: # send out the msg self.log.debug(u"Sending xplmessage: {0}".format(msg)) self.myxpl.send(msg) xplstat = self._db.detach(xplstat) # generate an uuid for the matching answer published messages if xplstat != None: resp_uuid = uuid4() self._cmd_lock_d.acquire() self._cmd_dict[str(resp_uuid)] = xplstat self._cmd_lock_d.release() else: resp_uuid = None # send the response reply_msg = MQMessage() reply_msg.set_action('cmd.send.result') reply_msg.add_data('uuid', str(resp_uuid)) reply_msg.add_data('status', True) reply_msg.add_data('reason', None) self.log.debug(u"mq reply (success) : {0}".format(reply_msg.get())) self.reply(reply_msg.get()) if failed: self.log.error(failed) reply_msg = MQMessage() reply_msg.set_action('cmd.send.result') reply_msg.add_data('uuid', None) reply_msg.add_data('status', False) reply_msg.add_data('reason', failed) self.log.debug(u"mq reply (failed) : {0}".format(reply_msg.get())) self.reply(reply_msg.get())
def _send_xpl_command(self, data): """ Reply to config.get MQ req @param data : MQ req message Needed info in data: - cmdid => command id to send - cmdparams => key/value pair of all params needed for this command """ with self._db.session_scope(): self.log.info(u"Received new cmd request: {0}".format(data)) failed = False request = data.get_data() if 'cmdid' not in request: failed = "cmdid not in message data" if 'cmdparams' not in request: failed = "cmdparams not in message data" if not failed: # get the command cmd = self._db.get_command(request['cmdid']) if cmd is not None: if cmd.xpl_command is not None: xplcmd = cmd.xpl_command xplstat = self._db.get_xpl_stat(xplcmd.stat_id) if xplstat is not None: # get the device from the db dev = self._db.get_device(int(cmd.device_id)) msg = XplMessage() if not dev['client_id'] in self.client_xpl_map.keys(): self._load_client_to_xpl_target() if not dev['client_id'] in self.client_xpl_map.keys(): failed = "Can not fincd xpl source for {0} client_id".format(dev['client_id']) else: msg.set_target(self.client_xpl_map[dev['client_id']]) msg.set_source(self.myxpl.get_source()) msg.set_type("xpl-cmnd") msg.set_schema( xplcmd.schema) # static params for p in xplcmd.params: msg.add_data({p.key : p.value}) # dynamic params for p in cmd.params: if p.key in request['cmdparams']: value = request['cmdparams'][p.key] # chieck if we need a conversion if p.conversion is not None and p.conversion != '': if dev['client_id'] in self.client_conversion_map: if p.conversion in self.client_conversion_map[dev['client_id']]: exec(self.client_conversion_map[dev['client_id']][p.conversion]) value = locals()[p.conversion](value) msg.add_data({p.key : value}) else: failed = "Parameter ({0}) for device command msg is not provided in the mq message".format(p.key) if not failed: # send out the msg self.log.debug(u"sending xplmessage: {0}".format(msg)) self.myxpl.send(msg) ### Wait for answer stat_received = 0 if xplstat != None: # get xpl message from queue self.log.debug(u"Command : wait for answer...") sub = MQSyncSub( self.zmq, 'xplgw-command', ['device-stats'] ) stat = sub.wait_for_event() if stat is not None: reply = json.loads(stat['content']) reply_msg = MQMessage() reply_msg.set_action('cmd.send.result') reply_msg.add_data('stat', reply) reply_msg.add_data('status', True) reply_msg.add_data('reason', None) self.log.debug(u"mq reply".format(reply_msg.get())) self.reply(reply_msg.get()) if failed: self.log.error(failed) reply_msg = MQMessage() reply_msg.set_action('cmd.send.result') reply_msg.add_data('status', False) reply_msg.add_data('reason', failed) self.log.debug(u"mq reply".format(reply_msg.get())) self.reply(reply_msg.get())
class XplMessageTest(unittest.TestCase): """ Test XplMessage class. """ def setUp(self): """ Setup context. The context is setup before each call to a test method. """ self.__xpl_message = XplMessage() def tearDown(self): """ clean context. The context is cleaned after each call of a test method. """ del self.__xpl_message def test_set_type(self): """ Test XplMessage.set_type() method. """ self.assertRaises(XplMessageError, self.__xpl_message.set_type, 'dummy') for type_ in ('xpl-cmnd', 'xpl-trig', 'xpl-stat'): self.__xpl_message.set_type(type_) self.assertEqual(self.__xpl_message.type, type_) def test_set_hop_count(self): """ Test XplMessage.set_hop_count() method. """ self.assertRaises(XplMessageError, self.__xpl_message.set_hop_count, 0) for i in xrange(1, 10): self.__xpl_message.set_hop_count(i) self.assertEqual(self.__xpl_message.hop_count, i) self.assertRaises(XplMessageError, self.__xpl_message.set_hop_count, 10) def test_inc_hop_count(self): """ Test XplMessage.inc_hop_count() method. """ for i in xrange(8): self.__xpl_message.inc_hop_count() self.assertRaises(XplMessageError, self.__xpl_message.inc_hop_count) def test_set_source(self): """ Test XplMessage.set_source() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_source, "xxxxxxxxx-x.x") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "x-xxxxxxxxx.x") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "x-x.xxxxxxxxxxxxxxxxx") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_source, "dummy") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "xPL-hal.myhouse") self.__xpl_message.set_source("xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source, "xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source_vendor_id, "xpl") self.assertEqual(self.__xpl_message.source_device_id, "xplhal") self.assertEqual(self.__xpl_message.source_instance_id, "myhouse") def test_set_target(self): """ Test XplMessage.set_target() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxxxxxxxx-xxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxx-xxxxxxxxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxx-xxx.xxxxxxxxxxxxxxxxx") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_target, "dummy") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xPL-hal.myhouse") self.__xpl_message.set_target("acme-cm12.server") self.assertEqual(self.__xpl_message.target, "acme-cm12.server") self.assertEqual(self.__xpl_message.target_vendor_id, "acme") self.assertEqual(self.__xpl_message.target_device_id, "cm12") self.assertEqual(self.__xpl_message.target_instance_id, "server") self.__xpl_message.set_target('*') self.assertEqual(self.__xpl_message.target, '*') self.assertEqual(self.__xpl_message.target_vendor_id, None) self.assertEqual(self.__xpl_message.target_device_id, None) self.assertEqual(self.__xpl_message.target_instance_id, None) def test_set_schema(self): """ Test XplMessage.set_schema() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "xxxxxxxxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "xxx.xxxxxxxxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "x10-basic") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "dummy") self.__xpl_message.set_schema("x10.basic") self.assertEqual(self.__xpl_message.schema, "x10.basic") self.assertEqual(self.__xpl_message.schema_class, "x10") self.assertEqual(self.__xpl_message.schema_type, "basic") def test_add_single_data(self): """ Test XplMessage.test_add_single_data() method. """ # check lengths name = 'x' * 17 value = "xxx" self.assertRaises(XplMessageError, self.__xpl_message.add_single_data, name, value) name = "xxx" value = 'x' * 129 #self.assertRaises(XplMessageError, self.__xpl_message.add_single_data, name, value) # def test_set_data(self): """ Test XplMessage.set_data() method. """ self.__xpl_message.set_data({ "command": "dim", "device": "a1", "level": "75" }) self.assertEqual( self.__xpl_message.data, OrderedDict({ "command": "dim", "device": "a1", "level": "75" })) # Check if correctly remove previous data self.__xpl_message.set_data({ "command2": "dim", "device2": "a1", "level2": "75" }) self.assertEqual( self.__xpl_message.data, OrderedDict({ "command2": "dim", "device2": "a1", "level2": "75" })) def test_from_packet(self): """ Test the XplMessage.from_packet() method. """ wrong_packet = \ """xpl-cmnd { target=acme-cm12.server } { command=dim device=a1 level=75 } """ self.assertRaises(XplMessageError, self.__xpl_message.from_packet, wrong_packet) packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.__xpl_message.from_packet(packet) self.assertEqual(self.__xpl_message.type, 'xpl-cmnd') self.assertEqual(self.__xpl_message.hop_count, 1) self.assertEqual(self.__xpl_message.source, "xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source_vendor_id, "xpl") self.assertEqual(self.__xpl_message.source_device_id, "xplhal") self.assertEqual(self.__xpl_message.source_instance_id, "myhouse") self.assertEqual(self.__xpl_message.target, "acme-cm12.server") self.assertEqual(self.__xpl_message.target_vendor_id, "acme") self.assertEqual(self.__xpl_message.target_device_id, "cm12") self.assertEqual(self.__xpl_message.target_instance_id, "server") self.assertEqual(self.__xpl_message.schema, "x10.basic") self.assertEqual(self.__xpl_message.schema_class, "x10") self.assertEqual(self.__xpl_message.schema_type, "basic") self.assertEqual( self.__xpl_message.data, OrderedDict({ "command": "dim", "device": "a1", "level": "75" })) def testto_packet(self): """ Test XplMessage.to_packet() method. """ packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.__xpl_message.from_packet(packet) self.assertEquals(self.__xpl_message.to_packet(), packet) def test_is_valid(self): """ Test XplMessage.is_valid() method. """ packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.assertEquals(self.__xpl_message.is_valid(), False) self.__xpl_message.from_packet(packet) self.assertEquals(self.__xpl_message.is_valid(), True)
def _send_xpl_command(self, cmd, request): """ Reply to config.get MQ req @param data : MQ req message Needed info in data: - cmdid => command id to send - cmdparams => key/value pair of all params needed for this command """ self.log.debug(u" => Generating XPL message to plugin") failed = False xplcmd = cmd['xpl_command'] #xplstat = self._db.get_xpl_stat(xplcmd['stat_id']) xplstat = self.all_xpl_stats[str(xplcmd['stat_id'])] if xplstat is not None: # get the device from the db dev = self.all_devices[str(cmd['device_id'])] msg = XplMessage() if not dev['client_id'] in self.client_xpl_map.keys(): self._load_client_to_xpl_target() if not dev['client_id'] in self.client_xpl_map.keys(): failed = "Can not fincd xpl source for {0} client_id".format(dev['client_id']) else: ### Fix bug #349 # I am not totally sure why before we used the xpl_source from the client list. # Indeed for domogik xpl plugins it helps to target the appropriate plugin but # for xpl messages for outside of domogik, this is a blocking point ! # As xpl plugins are starting to be deprecated as the 'common plugin format', it # should not be an issue to retarget xpl messages to '*' for now and later on if # there is a real need to target on a dedicated target, implement a bette way to # handle this # -- Fritz -- oct 2016 #msg.set_target(self.client_xpl_map[dev['client_id']]) msg.set_target("*") ### End of fix msg.set_source(self.myxpl.get_source()) msg.set_type("xpl-cmnd") msg.set_schema(xplcmd['schema']) # static paramsw for par in xplcmd['params']: msg.add_data({par['key'] : par['value']}) # dynamic params for par in cmd['params']: if par['key'] in request['cmdparams']: value = request['cmdparams'][par['key']] # check if we need a conversion if par['conversion'] is not None and par['conversion'] != '': if dev['client_id'] in self.client_conversion_map: if par['conversion'] in self.client_conversion_map[dev['client_id']]: self.log.debug( \ u" => Calling conversion {0}".format(par['conversion'])) exec(self.client_conversion_map[dev['client_id']][par['conversion']]) value = locals()[par['conversion']](value) self.log.debug( \ u" => Command parameter after conversion {0} = {1}".format(par['key'], value)) msg.add_data({par['key'] : value}) else: failed = "Parameter ({0}) for device command msg is not provided in the mq message".format(par['key']) if not failed: # send out the msg self.log.debug(u" => Sending xplmessage: {0}".format(msg)) try: self.myxpl.send(msg) except XplMessageError as msg: failed = msg #xplstat = self._db.detach(xplstat) # generate an uuid for the matching answer published messages if xplstat != None: resp_uuid = uuid4() self._cmd_lock_d.acquire() self._cmd_dict[str(resp_uuid)] = xplstat self._cmd_lock_d.release() else: resp_uuid = None return True, resp_uuid, None if failed: self.log.error(failed) return False, None, failed
class XplMessageTest(unittest.TestCase): """ Test XplMessage class. """ def setUp(self): """ Setup context. The context is setup before each call to a test method. """ self.__xpl_message = XplMessage() def tearDown(self): """ clean context. The context is cleaned after each call of a test method. """ del self.__xpl_message def test_set_type(self): """ Test XplMessage.set_type() method. """ self.assertRaises(XplMessageError, self.__xpl_message.set_type, 'dummy') for type_ in ('xpl-cmnd', 'xpl-trig', 'xpl-stat'): self.__xpl_message.set_type(type_) self.assertEqual(self.__xpl_message.type, type_) def test_set_hop_count(self): """ Test XplMessage.set_hop_count() method. """ self.assertRaises(XplMessageError, self.__xpl_message.set_hop_count, 0) for i in xrange(1, 10): self.__xpl_message.set_hop_count(i) self.assertEqual(self.__xpl_message.hop_count, i) self.assertRaises(XplMessageError, self.__xpl_message.set_hop_count, 10) def test_inc_hop_count(self): """ Test XplMessage.inc_hop_count() method. """ for i in xrange(8): self.__xpl_message.inc_hop_count() self.assertRaises(XplMessageError, self.__xpl_message.inc_hop_count) def test_set_source(self): """ Test XplMessage.set_source() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_source, "xxxxxxxxx-x.x") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "x-xxxxxxxxx.x") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "x-x.xxxxxxxxxxxxxxxxx") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_source, "dummy") self.assertRaises(XplMessageError, self.__xpl_message.set_source, "xPL-hal.myhouse") self.__xpl_message.set_source("xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source, "xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source_vendor_id, "xpl") self.assertEqual(self.__xpl_message.source_device_id, "xplhal") self.assertEqual(self.__xpl_message.source_instance_id, "myhouse") def test_set_target(self): """ Test XplMessage.set_target() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxxxxxxxx-xxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxx-xxxxxxxxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xxx-xxx.xxxxxxxxxxxxxxxxx") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_target, "dummy") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "xPL-hal.myhouse") self.__xpl_message.set_target("acme-cm12.server") self.assertEqual(self.__xpl_message.target, "acme-cm12.server") self.assertEqual(self.__xpl_message.target_vendor_id, "acme") self.assertEqual(self.__xpl_message.target_device_id, "cm12") self.assertEqual(self.__xpl_message.target_instance_id, "server") self.__xpl_message.set_target('*') self.assertEqual(self.__xpl_message.target, '*') self.assertEqual(self.__xpl_message.target_vendor_id, None) self.assertEqual(self.__xpl_message.target_device_id, None) self.assertEqual(self.__xpl_message.target_instance_id, None) def test_set_schema(self): """ Test XplMessage.set_schema() method. """ # Check length self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "xxxxxxxxx.xxx") self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "xxx.xxxxxxxxx") self.assertRaises(XplMessageError, self.__xpl_message.set_target, "x10-basic") # Check format self.assertRaises(XplMessageError, self.__xpl_message.set_schema, "dummy") self.__xpl_message.set_schema("x10.basic") self.assertEqual(self.__xpl_message.schema, "x10.basic") self.assertEqual(self.__xpl_message.schema_class, "x10") self.assertEqual(self.__xpl_message.schema_type, "basic") def test_add_single_data(self): """ Test XplMessage.test_add_single_data() method. """ # check lengths name = 'x' * 17 value = "xxx" self.assertRaises(XplMessageError, self.__xpl_message.add_single_data, name, value) name = "xxx" value = 'x' * 129 #self.assertRaises(XplMessageError, self.__xpl_message.add_single_data, name, value) # def test_set_data(self): """ Test XplMessage.set_data() method. """ self.__xpl_message.set_data({"command": "dim", "device": "a1", "level": "75"}) self.assertEqual(self.__xpl_message.data, OrderedDict({"command": "dim", "device": "a1", "level": "75"})) # Check if correctly remove previous data self.__xpl_message.set_data({"command2": "dim", "device2": "a1", "level2": "75"}) self.assertEqual(self.__xpl_message.data, OrderedDict({"command2": "dim", "device2": "a1", "level2": "75"})) def test_from_packet(self): """ Test the XplMessage.from_packet() method. """ wrong_packet = \ """xpl-cmnd { target=acme-cm12.server } { command=dim device=a1 level=75 } """ self.assertRaises(XplMessageError, self.__xpl_message.from_packet, wrong_packet) packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.__xpl_message.from_packet(packet) self.assertEqual(self.__xpl_message.type, 'xpl-cmnd') self.assertEqual(self.__xpl_message.hop_count, 1) self.assertEqual(self.__xpl_message.source, "xpl-xplhal.myhouse") self.assertEqual(self.__xpl_message.source_vendor_id, "xpl") self.assertEqual(self.__xpl_message.source_device_id, "xplhal") self.assertEqual(self.__xpl_message.source_instance_id, "myhouse") self.assertEqual(self.__xpl_message.target, "acme-cm12.server") self.assertEqual(self.__xpl_message.target_vendor_id, "acme") self.assertEqual(self.__xpl_message.target_device_id, "cm12") self.assertEqual(self.__xpl_message.target_instance_id, "server") self.assertEqual(self.__xpl_message.schema, "x10.basic") self.assertEqual(self.__xpl_message.schema_class, "x10") self.assertEqual(self.__xpl_message.schema_type, "basic") self.assertEqual(self.__xpl_message.data, OrderedDict({"command": "dim", "device": "a1", "level": "75"})) def testto_packet(self): """ Test XplMessage.to_packet() method. """ packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.__xpl_message.from_packet(packet) self.assertEquals(self.__xpl_message.to_packet(), packet) def test_is_valid(self): """ Test XplMessage.is_valid() method. """ packet = \ """xpl-cmnd { hop=1 source=xpl-xplhal.myhouse target=acme-cm12.server } x10.basic { command=dim device=a1 level=75 } """ self.assertEquals(self.__xpl_message.is_valid(), False) self.__xpl_message.from_packet(packet) self.assertEquals(self.__xpl_message.is_valid(), True)
def _send_xpl_command(self, cmd, request): """ Reply to config.get MQ req @param data : MQ req message Needed info in data: - cmdid => command id to send - cmdparams => key/value pair of all params needed for this command """ self.log.debug(u" => Generating XPL message to plugin") failed = False xplcmd = cmd['xpl_command'] #xplstat = self._db.get_xpl_stat(xplcmd['stat_id']) xplstat = self.all_xpl_stats[str(xplcmd['stat_id'])] if xplstat is not None: # get the device from the db dev = self.all_devices[str(cmd['device_id'])] msg = XplMessage() if not dev['client_id'] in self.client_xpl_map.keys(): self._load_client_to_xpl_target() if not dev['client_id'] in self.client_xpl_map.keys(): failed = "Can not fincd xpl source for {0} client_id".format( dev['client_id']) else: ### Fix bug #349 # I am not totally sure why before we used the xpl_source from the client list. # Indeed for domogik xpl plugins it helps to target the appropriate plugin but # for xpl messages for outside of domogik, this is a blocking point ! # As xpl plugins are starting to be deprecated as the 'common plugin format', it # should not be an issue to retarget xpl messages to '*' for now and later on if # there is a real need to target on a dedicated target, implement a bette way to # handle this # -- Fritz -- oct 2016 #msg.set_target(self.client_xpl_map[dev['client_id']]) msg.set_target("*") ### End of fix msg.set_source(self.myxpl.get_source()) msg.set_type("xpl-cmnd") msg.set_schema(xplcmd['schema']) # static paramsw for par in xplcmd['params']: msg.add_data({par['key']: par['value']}) # dynamic params for par in cmd['params']: if par['key'] in request['cmdparams']: value = request['cmdparams'][par['key']] # check if we need a conversion if par['conversion'] is not None and par[ 'conversion'] != '': if dev['client_id'] in self.client_conversion_map: if par['conversion'] in self.client_conversion_map[ dev['client_id']]: self.log.debug( \ u" => Calling conversion {0}".format(par['conversion'])) exec(self.client_conversion_map[ dev['client_id']][par['conversion']]) value = locals()[par['conversion']](value) self.log.debug( \ u" => Command parameter after conversion {0} = {1}".format(par['key'], value)) msg.add_data({par['key']: value}) else: failed = "Parameter ({0}) for device command msg is not provided in the mq message".format( par['key']) if not failed: # send out the msg self.log.debug(u" => Sending xplmessage: {0}".format(msg)) try: self.myxpl.send(msg) except XplMessageError as msg: failed = msg #xplstat = self._db.detach(xplstat) # generate an uuid for the matching answer published messages if xplstat != None: resp_uuid = uuid4() self._cmd_lock_d.acquire() self._cmd_dict[str(resp_uuid)] = xplstat self._cmd_lock_d.release() else: resp_uuid = None return True, resp_uuid, None if failed: self.log.error(failed) return False, None, failed