def _decode_0x6F_record(self, p_controller_obj): """All-Link manage Record Response (12 bytes). See p 252(265) of 2009 developers guide. Modify the IM's All-Link Database (ALDB) with the All-Link data you send. Use caution with this command - the IM does not check the validity of the data you send. [0] = x02 [1] = 0x6F [2] = Control Code [3] = All-Link Record Flag [4] = All Lpink Grou [5-7] = ID [8] = Link Data 1 [9] = Link Data 2 [10] = Link Data 3 [11] = ACK/NAK """ l_message = p_controller_obj._Message l_code = l_message[2] l_flags = l_message[3] l_flag_control = l_flags & 0x40 l_group = l_message[4] l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) l_data = [l_message[8], l_message[9], l_message[10]] l_ack = utilDecode.get_ack_nak(l_message[11]) l_type = 'Responder' if l_flag_control != 0: l_type = 'Controller' l_message = "Manage All-Link response(6F)" l_message += " Group:{:#02X}, Name:{}, Flags:{:#02X}, Data:{}, CtlCode:{:#02x},".format(l_group, l_obj.Name, l_flags, l_data, l_code) l_message += " Ack:{}, Type:{}".format(l_ack, l_type) LOG.info("{}".format(l_message)) p_controller_obj.Ret = True return
def _decode_51_record(self, p_controller_obj): """ Insteon Extended Message Received (25 bytes). See p 247 of developers guide. """ l_message = p_controller_obj._Message l_obj_from = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_obj_to = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) l_flags = l_message[8] l_data = [l_message[9], l_message[10]] l_extended = "{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}".format( l_message[11], l_message[12], l_message[13], l_message[14], l_message[15], l_message[16], l_message[17], l_message[18], l_message[19], l_message[20], l_message[21], l_message[22], l_message[23], l_message[24]) # l_product_key = self._get_addr_from_message(l_message, 12) l_devcat = l_message[15] * 256 + l_message[16] LOG.info("51 Resp: Fm={}, To={}, Flags={:#x}, Data={} Extended={} ==". format(l_obj_from.Name, l_obj_to.Name, l_flags, l_data, l_extended)) # l_obj_from.ProductKey = l_product_key l_obj_from.DevCat = l_devcat l_ret = True return self.check_for_more_decoding(p_controller_obj, l_ret)
def decode_message(self, p_controller_obj): """Decode a message that was ACKed / NAked. see Insteon Developers Manual pages 238-241 Since a controller response may contain multiple messages and the last message may not be complete. This should be invoked every time we pick up more messages from the controller. It should loop and decode each message present and leave when done @return: a flag that is True for ACK and False for NAK/Invalid response. """ # LOG.info('Message = {}'.format(PrintBytes(p_controller_obj._Message))) while len(p_controller_obj._Message) >= 2: l_stx = p_controller_obj._Message[0] if l_stx == STX: # LOG.info("{}".format(PrintBytes(p_controller_obj._Message))) l_need_len = utilUtil.get_message_length( p_controller_obj._Message) l_cur_len = len(p_controller_obj._Message) if l_cur_len >= l_need_len: self._decode_dispatch(p_controller_obj) else: # LOG.warning('Message was too short - waiting for rest of message.') return else: utilDecode.drop_first_byte(p_controller_obj)
def test_01_Devcat(self): l_dev = b'\x02\x04' l_ret = utilDecode._devcat(l_dev, self.m_obj) self.assertEqual(self.m_obj.DevCat, 0x0204) # l_dev = MSG_50 # l_c = l_dev[5:7] # print(FormatBytes(l_c)) l_ret = utilDecode._devcat(l_dev[5:7], self.m_obj) self.assertEqual(self.m_obj.DevCat, 0x0204)
def decode_53(p_controller_obj): """Insteon All-Linking completed (10 bytes). See p 245(258) of 2007 developers guide. """ l_message = p_controller_obj._Message l_link_code = l_message[2] l_link_group = l_message[3] l_from_id = l_message[4:7] utilDecode._devcat(l_message[7:9], p_controller_obj) LOG.info('All-Linking completed {}, Group:{}, From:{} '.format(l_link_code, l_link_group, l_from_id)) return False
def test_01_Devcat(self): l_dev = b'\x02\x04' _l_ret = utilDecode._devcat(l_dev, self.m_obj) # print(PrettyFormatAny.form(_l_ret, 'D1-01-A - xxx')) self.assertEqual(self.m_obj.DevCat, 0x0204) # l_dev = MSG_50 # l_c = l_dev[5:7] # print(FormatBytes(l_c)) _l_ret = utilDecode._devcat(l_dev[5:7], self.m_obj) self.assertEqual(self.m_obj.DevCat, 0x0204)
def test_01_Button(self): """ """ result = utilDecode._find_addr_one_class(self.m_pyhouse_obj, self.m_pyhouse_obj.House.Lighting.Buttons, ADDR_BUTTON_0_INT) # print(PrettyFormatAny.form(result, 'B2-01-A - PyHouse')) # print((result)) self.assertEqual(result.InsteonAddress, ADDR_BUTTON_0_INT)
def test_01_Controller(self): """ """ result = utilDecode.find_address_all_classes(self.m_pyhouse_obj, ADDR_CONTROLLER_0_INT) # print(PrettyFormatAny.form(result, 'B3-01-A - PyHouse')) # print((result)) self.assertEqual(result.InsteonAddress, ADDR_CONTROLLER_0_INT)
def decode_0x57(p_pyhouse_obj, p_controller_obj): """All-Link Record Response (10 bytes). See p 251(264) of 2009 developers guide. [0] = 0x02 [1] = 0x57 [2] = AllLink Record Flags [3] = AllLink Group [4-6] = from address [7] = Link Data 1 [8] = Link Data 2 [9] = Link Data 3 """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(p_pyhouse_obj, l_message[4:7]) l_link_obj = LinkData() l_link_obj.Flag = l_flags = l_message[2] l_link_obj.Group = l_group = l_message[3] l_link_obj.InsteonAddess = l_obj.InsteonAddress l_link_obj.Data = l_data = [l_message[7], l_message[8], l_message[9]] l_flag_control = l_flags & 0x40 l_type = 'Responder' if l_flag_control != 0: l_type = 'Controller' l_link_obj.IsController = True LOG.info("All-Link response-0x57 - Group={:#02X}, Name={}, Flags={:#x}, Data={}, {}".format(l_group, l_obj.Name, l_flags, l_data, l_type)) return
def _decode_0x67_record(self, p_controller_obj): """Reset IM ACK response (3 bytes). See p 258 of developers guide. """ l_message = p_controller_obj._Message l_ack = utilDecode.get_ack_nak(l_message[2]) l_debug_msg = "Reset IM(PLM) {}".format(l_ack) LOG.info("{}".format(l_debug_msg)) return
def test_01_Button(self): """ """ result = utilDecode.find_address_all_classes(self.m_pyhouse_obj, ADDR_BUTTON_0_INT) # print(PrettyFormatAny.form(result, 'B3-01-A - PyHouse')) # print((result)) self.assertEqual(result.InsteonAddress, ADDR_BUTTON_0_INT) self.assertEqual(str(result.DeviceType), TESTING_LIGHTING_BUTTON_DEVICE_TYPE_0) self.assertEqual(str(result.DeviceSubType), TESTING_LIGHTING_BUTTON_DEVICE_SUBTYPE_0)
def _decode_67_record(self, p_controller_obj): """Reset IM ACK response (3 bytes). See p 258 of developers guide. """ l_message = p_controller_obj._Message l_ack = utilDecode.get_ack_nak(l_message[2]) l_debug_msg = "Reset IM(PLM) {}".format(l_ack) LOG.info("{}".format(l_debug_msg)) return self.check_for_more_decoding(p_controller_obj)
def test_01_GetObj(self): """ """ # print(PrettyFormatAny.form(self.m_pyhouse_obj.House.Lighting.Lights[0], 'E1-01-A - Lighting')) l_addr = INSTEON_0_MSG l_ret = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_addr) l_dotted = conversions.int2dotted_hex(l_ret.InsteonAddress, 3) # print(PrettyFormatAny.form(l_ret, 'E1-01-B - Lighting')) self.assertEqual(l_dotted, TESTING_INSTEON_ADDRESS_0)
def _decode_51_record(self, p_controller_obj): """ Insteon Extended Message Received (25 bytes). See p 247 of developers guide. """ l_message = p_controller_obj._Message l_obj_from = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_obj_to = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) l_flags = l_message[8] l_data = [l_message[9], l_message[10]] l_extended = "{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}".format( l_message[11], l_message[12], l_message[13], l_message[14], l_message[15], l_message[16], l_message[17], l_message[18], l_message[19], l_message[20], l_message[21], l_message[22], l_message[23], l_message[24]) # l_product_key = self._get_addr_from_message(l_message, 12) l_devcat = l_message[15] * 256 + l_message[16] LOG.info("51 Resp: Fm={}, To={}, Flags={:#x}, Data={} Extended={} ==".format(l_obj_from.Name, l_obj_to.Name, l_flags, l_data, l_extended)) # l_obj_from.ProductKey = l_product_key l_obj_from.DevCat = l_devcat l_ret = True return self.check_for_more_decoding(p_controller_obj, l_ret)
def decode_0x53(p_pyhouse_obj, p_controller_obj): """Insteon All-Linking completed (10 bytes). See p 247(260) of 2009 developers guide. [0] = 0x02 [1] = 0x53 [2] = LinkCode - 0=PLM is Responder, 1=PLM is Controller, FF=Deleted [3] = LinkGroup [4-6] = from address [7-8] = DevCat [9] = Firmwear Version """ l_message = p_controller_obj._Message l_msg = Insteon_utils.decode_link_code(l_message[2]) l_link_group = l_message[3] l_from_id = l_message[4:7] l_device_obj = utilDecode.get_obj_from_message(p_pyhouse_obj, l_from_id) utilDecode._devcat(l_message[7:9], p_controller_obj) _l_version = l_message[9] LOG.info('All-Linking completed - Link Code:{}, Group:{}, From:{} '.format(l_msg, l_link_group, l_device_obj.Name))
def test_02_PutController(self): """ """ _l_controller = self.m_pyhouse_obj.House.Lighting.Controllers[0] # print(PrettyFormatAny.form(l_controller, 'F1-02-A - Controller')) l_addr = INSTEON_1_MSG l_ret = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_addr) l_ret.Port = PORT_NAME Insteon_utils.update_insteon_obj(self.m_pyhouse_obj, l_ret) # print(PrettyFormatAny.form(l_controller, 'F1-02-B - l_ret')) self.assertEqual(self.m_pyhouse_obj.House.Lighting.Controllers[0].Port, PORT_NAME)
def _decode_6F_record(self, p_controller_obj): """All-Link manage Record Response (12 bytes). See p 267 of developers guide. """ l_message = p_controller_obj._Message l_code = l_message[2] l_flags = l_message[3] l_flag_control = l_flags & 0x40 l_group = l_message[4] l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) l_data = [l_message[8], l_message[9], l_message[10]] l_ack = utilDecode.get_ack_nak(l_message[11]) l_type = 'Responder' if l_flag_control != 0: l_type = 'Controller' l_message = "Manage All-Link response(6F)" l_message += " Group:{:#02X}, Name:{}, Flags:{:#02X}, Data:{}, CtlCode:{:#02x},".format(l_group, l_obj.Name, l_flags, l_data, l_code) l_message += " Ack:{}, Type:{}".format(l_ack, l_type) LOG.info("{}".format(l_message)) l_ret = True return self.check_for_more_decoding(p_controller_obj, l_ret)
def _decode_73_record(self, p_controller_obj): """Get the PLM response of 'get config' (6 bytes). See p 270 of developers guide. """ l_message = p_controller_obj._Message l_flags = l_message[2] l_spare1 = l_message[3] l_spare2 = l_message[4] l_ack = utilDecode.get_ack_nak(l_message[5]) LOG.info("== 73 Get IM configuration Flags={:#x}, Spare 1={:#x}, Spare 2={:#x} {} ".format( l_flags, l_spare1, l_spare2, l_ack)) return self.check_for_more_decoding(p_controller_obj)
def _decode_0x51(self, p_controller_obj): """ Insteon Extended Message Received (25 bytes). See p 234(247) of 2009 developers guide. """ l_message = p_controller_obj._Message l_obj_from = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) _l_obj_to = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) _l_flags = l_message[8] l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_extended = "{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}.{:X}".format( l_message[11], l_message[12], l_message[13], l_message[14], l_message[15], l_message[16], l_message[17], l_message[18], l_message[19], l_message[20], l_message[21], l_message[22], l_message[23], l_message[24]) if l_cmd1 == 0x03 and l_cmd2 == 0: # Product Data request response l_product_key = self._get_addr_from_message(l_message, 12) l_devcat = l_message[15] * 256 + l_message[16] LOG.info('ProdData Fm:"{}"; ProductID:"{}"; DevCat:"{}"; Data:"{}"'.format(l_obj_from.Name, l_product_key, l_devcat, l_extended)) l_obj_from.ProductKey = l_product_key l_obj_from.DevCat = l_devcat p_controller_obj.Ret = True Insteon_utils.update_insteon_obj(self.m_pyhouse_obj, l_obj_from) return
def _decode_62_record(self, p_controller_obj): """Get response to Send Insteon standard-length message (9 bytes). Basically, a response to the 62 command. See p 243 of developers guide. [0] = 0x02 [1] = 0x62 [2-4] = address [5] = message flags [6] = command 1 [7] = command 2 [8] = ACK/NAK This is an ack/nak of the command and generally is not very interesting by itself. Depending on the command sent, another response MAY follow this message with further data. """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) _l_msgflags = utilDecode._decode_message_flag(l_message[5]) l_ack = utilDecode.get_ack_nak(l_message[8]) l_debug_msg = "Device: {}, {}".format(l_obj.Name, l_ack) if l_ack == 'NAK': LOG.info("Got ACK(62); {}".format(l_debug_msg)) return self.check_for_more_decoding(p_controller_obj)
def _decode_73_record(self, p_controller_obj): """Get the PLM response of 'get config' (6 bytes). See p 270 of developers guide. """ l_message = p_controller_obj._Message l_flags = l_message[2] l_spare1 = l_message[3] l_spare2 = l_message[4] l_ack = utilDecode.get_ack_nak(l_message[5]) LOG.info( "== 73 Get IM configuration Flags={:#x}, Spare 1={:#x}, Spare 2={:#x} {} " .format(l_flags, l_spare1, l_spare2, l_ack)) return self.check_for_more_decoding(p_controller_obj)
def _decode_0x62_record(self, p_controller_obj): """Get response to Send Insteon standard-length message (9 bytes). Basically, a response to the 62 command. See p 230(243) of 2009 developers guide. [0] = 0x02 [1] = 0x62 [2-4] = address [5] = message flags [6] = command 1 [7] = command 2 [8] = ACK/NAK [8] = User Data 1 [9] = User Data 2 [10] = User Data 3 [11] = User Data 4 [12] = User Data 5 [13] = User Data 6 [14] = User Data 7 [15] = User Data 8 [16] = User Data 9 [17] = User Data 10 [18] = User Data 11 [19] = User Data 12 [20] = User Data 13 [21] = User Data 14 [22] = ACK/NAK This is an ack/nak of the command and generally is not very interesting by itself. Depending on the command sent, another response MAY follow this message with further data. """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) _l_msgflags = utilDecode._decode_message_flag(l_message[5]) l_ack = utilDecode.get_ack_nak(l_message[8]) l_debug_msg = "Device: {}, {}".format(l_obj.Name, l_ack) if l_ack == 'NAK': LOG.info("Got ACK(62); {}".format(l_debug_msg)) return
def _decode_6F_record(self, p_controller_obj): """All-Link manage Record Response (12 bytes). See p 267 of developers guide. """ l_message = p_controller_obj._Message l_code = l_message[2] l_flags = l_message[3] l_flag_control = l_flags & 0x40 l_group = l_message[4] l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[5:8]) l_data = [l_message[8], l_message[9], l_message[10]] l_ack = utilDecode.get_ack_nak(l_message[11]) l_type = 'Responder' if l_flag_control != 0: l_type = 'Controller' l_message = "Manage All-Link response(6F)" l_message += " Group:{:#02X}, Name:{}, Flags:{:#02X}, Data:{}, CtlCode:{:#02x},".format( l_group, l_obj.Name, l_flags, l_data, l_code) l_message += " Ack:{}, Type:{}".format(l_ack, l_type) LOG.info("{}".format(l_message)) l_ret = True return self.check_for_more_decoding(p_controller_obj, l_ret)
def _decode_6B_record(self, p_controller_obj): """Get set IM configuration (4 bytes). See p 271 of developers guide. """ l_message = p_controller_obj._Message l_flag = l_message[2] l_ack = utilDecode.get_ack_nak(l_message[3]) l_debug_msg = "Config flag from PLM:{} - ConfigFlag:{:#02X}, {}".format(p_controller_obj.Name, l_flag, l_ack) LOG.info("Received from {}".format(l_debug_msg)) if l_message[3] == ACK: l_ret = True else: LOG.error("== 6B - NAK/Unknown message type {:#x}".format(l_flag)) l_ret = False return self.check_for_more_decoding(p_controller_obj, l_ret)
def decode_message(self, p_controller_obj): """Decode a message that was ACKed / NAked. see Insteon Developers Manual pages 238-241 Since a controller response may contain multiple messages and the last message may not be complete. This should be invoked every time we pick up more messages from the controller. It should loop and decode each message present and leave when done @return: a flag that is True for ACK and False for NAK/Invalid response. """ # LOG.info('Message = {}'.format(PrintBytes(p_controller_obj._Message))) while len(p_controller_obj._Message) >= 2: l_stx = p_controller_obj._Message[0] if l_stx == STX: # LOG.info("{}".format(PrintBytes(p_controller_obj._Message))) l_need_len = utilUtil.get_message_length(p_controller_obj._Message) l_cur_len = len(p_controller_obj._Message) if l_cur_len >= l_need_len: self._decode_dispatch(p_controller_obj) else: # LOG.warning('Message was too short - waiting for rest of message.') return else: utilDecode.drop_first_byte(p_controller_obj)
def _decode_6B_record(self, p_controller_obj): """Get set IM configuration (4 bytes). See p 271 of developers guide. """ l_message = p_controller_obj._Message l_flag = l_message[2] l_ack = utilDecode.get_ack_nak(l_message[3]) l_debug_msg = "Config flag from PLM:{} - ConfigFlag:{:#02X}, {}".format( p_controller_obj.Name, l_flag, l_ack) LOG.info("Received from {}".format(l_debug_msg)) if l_message[3] == ACK: l_ret = True else: LOG.error("== 6B - NAK/Unknown message type {:#x}".format(l_flag)) l_ret = False return self.check_for_more_decoding(p_controller_obj, l_ret)
def _decode_60_record(self, p_controller_obj): """Get Insteon Modem Info (9 bytes). See p 273 of developers guide. """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_devcat = l_message[5] l_devsubcat = l_message[6] l_firmver = l_message[7] LOG.info("== 60 - Insteon Modem Info - DevCat={}, DevSubCat={}, Firmware={} - Name={}".format(l_devcat, l_devsubcat, l_firmver, l_obj.Name)) if l_message[8] == ACK: l_ret = True else: LOG.error("== 60 - No ACK - Got {:#x}".format(l_message[8])) l_ret = False return self.check_for_more_decoding(p_controller_obj, l_ret)
def _decode_0x73_record(self, p_controller_obj): """ Get the PLM response of 'get config' (6 bytes). See p 257(270) of the 2009 developers guide. [0] = x02 [1] = IM Control Flag [2] = Spare 1 [3] = Spare 2 [4] = ACK/NAK """ l_message = p_controller_obj._Message l_flags = l_message[2] l_spare1 = l_message[3] l_spare2 = l_message[4] l_ack = utilDecode.get_ack_nak(l_message[5]) LOG.info("== 0x73 Get IM configuration Flags={:#x}, Spare 1={:#x}, Spare 2={:#x} {} ".format( l_flags, l_spare1, l_spare2, l_ack)) return
def decode_57(p_pyhouse_obj, p_controller_obj): """All-Link Record Response (10 bytes). See p 249)(262 of 2007 developers guide. """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(p_pyhouse_obj, l_message[4:7]) l_link_obj = LinkData() l_link_obj.Flag = l_flags = l_message[2] l_link_obj.Group = l_group = l_message[3] l_link_obj.InsteonAddess = l_obj.InsteonAddress l_link_obj.Data = l_data = [l_message[7], l_message[8], l_message[9]] l_flag_control = l_flags & 0x40 l_type = 'Responder' if l_flag_control != 0: l_type = 'Controller' LOG.info("All-Link response-57 - Group={:#02X}, Name={}, Flags={:#x}, Data={}, {}".format(l_group, l_obj.Name, l_flags, l_data, l_type)) l_ret = True return l_ret
def _decode_60_record(self, p_controller_obj): """Get Insteon Modem Info (9 bytes). See p 273 of developers guide. """ l_message = p_controller_obj._Message l_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_devcat = l_message[5] l_devsubcat = l_message[6] l_firmver = l_message[7] LOG.info( "== 60 - Insteon Modem Info - DevCat={}, DevSubCat={}, Firmware={} - Name={}" .format(l_devcat, l_devsubcat, l_firmver, l_obj.Name)) if l_message[8] == ACK: l_ret = True else: LOG.error("== 60 - No ACK - Got {:#x}".format(l_message[8])) l_ret = False return self.check_for_more_decoding(p_controller_obj, l_ret)
def _decode_0x6B_record(self, p_controller_obj): """Get set IM configuration (4 bytes). See p 258(271) of 2009 developers guide. [0] = x02 [1] = 0x6B [2] = Flags [3] = ACK/NAK """ l_message = p_controller_obj._Message l_flag = l_message[2] l_ack = utilDecode.get_ack_nak(l_message[3]) l_debug_msg = "Config flag from PLM:{} - ConfigFlag:{:#02X}, {}".format(p_controller_obj.Name, l_flag, l_ack) LOG.info("Received from {}".format(l_debug_msg)) if l_message[3] == ACK: p_controller_obj.Ret = True else: LOG.error("== 6B - NAK/Unknown message type {:#x}".format(l_flag)) p_controller_obj.Ret = False return
def decode_0x50(self, p_pyhouse_obj, p_device_obj, p_controller_obj): """ @param p_device_obj: is the Device (light, thermostat...) we are decoding. A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to. See p 233(246) of 2009 developers guide. [0] = x02 [1] = 0x50 [2-4] = from address [5-7] = to address / group [8] = message flags [9] = command 1 [10] = command 2 """ l_mqtt_topic = 'hvac/{}'.format(p_device_obj.Name) l_mqtt_message = "thermostat: " l_message = p_controller_obj._Message l_firmware = l_message[7] l_flags = utilDecode._decode_message_flag(l_message[8]) l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_mqtt_message += ' Cmd1:{:#02X}/{:#02X}({:d})'.format(l_cmd1, l_cmd2, l_cmd2) l_debug_msg = 'Fm:"{}"; Flg:{}; C1:{:#x},{:#x}; '.format(p_device_obj.Name, l_flags, l_cmd1, l_cmd2) if l_cmd1 == MESSAGE_TYPES['assign_to_group']: # 0x01 l_mqtt_message += " assign_to_group:{}; ".format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['delete_from_group']: # 0x02 l_mqtt_message += " delete_from_group:{}; ".format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['cleanup_success']: # 0x06 l_mqtt_message += 'CleanupSuccess with {} failures; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['engine_version']: # 0x0d p_device_obj.EngineVersion = l_cmd2 l_mqtt_message += " EngineId:{}; ".format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['ping']: # 0x0f l_mqtt_message += " ping:{}; ".format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['id_request']: # 0x10 p_device_obj.FirmwareVersion = l_firmware l_mqtt_message += " id_request:{}; ".format(l_firmware) elif l_cmd1 == MESSAGE_TYPES['on']: # 0x11 p_device_obj.ThermostatStatus = 'On' l_mqtt_message += " On; " elif l_cmd1 == MESSAGE_TYPES['off']: # 0x13 p_device_obj.ThermostatStatus = 'Off' l_mqtt_message += " Off; " elif l_cmd1 == MESSAGE_TYPES['thermostat_temp_up']: # 0x68: # Set thermostat temperature up (half degrees) l_mqtt_topic += '/temperature' l_mqtt_message += ' temp UP = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_temp_down']: # 0x69: # Set Thermostat temperature down (half degrees) # p_device_obj.CurrentTemperature = l_cmd2 * HALF l_mqtt_topic += '/temperature' l_mqtt_message += ' temp DOWN = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_status']: # 0x6A: # Send request for thermostat status # p_device_obj.CurrentTemperature = l_cmd2 * HALF l_mqtt_topic += '/temperature' l_mqtt_message += ' Status = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_control']: # 0x6B: # Response for thermostat status p_device_obj.CurrentTemperature = l_cmd2 * HALF l_mqtt_topic += '/temperature' l_mqtt_message += ' temp = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_setpoint_cool']: # 0x6C: # Thermostat Set cool set point # p_device_obj.CurrentTemperature = l_cmd2 * HALF l_mqtt_topic += '/ThermostatSetCoolSetpointCommand' l_mqtt_message += ' cool set point = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_setpoint_heat']: # 0x6D: # Set heat set point # p_device_obj.CurrentTemperature = l_cmd2 * HALF l_mqtt_topic += '/ThermostatSetHeatSetpointCommand' l_mqtt_message += ' Heat set point = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_report_temperature']: # 0x6e: # Status report Temperature p_device_obj.CurrentTemperature = l_cmd2 * FACTOR l_mqtt_topic += '/ThermostatTemperatureReport' l_mqtt_message += ' Temperature = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_report_humidity']: # 0x6f: # Status Report Humidity l_mqtt_topic += '/ThermostatHumidityReport' l_mqtt_message += ' Humidity = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_report_mode']: # 0x70: # Status Report Mode / Fan Status l_mqtt_topic += '/ThermostatStatusReport' l_mqtt_message += ' StatusMode = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_report_cool_setpoint']: # 0x71: # Status Report Cool Set Point p_device_obj.CoolSetPoint = l_cmd2 * FACTOR l_mqtt_topic += '/ThermostatCoolSetPointReport' l_mqtt_message += ' CoolSetPoint = {}; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['thermostat_report_heat_setpoint']: # 0x72: # Status Report Heat Set Point p_device_obj.HeatSetPoint = l_cmd2 * FACTOR l_mqtt_topic += '/ThermostatHeatSetPointReport' l_mqtt_message += ' HeatSetPoint = {}; '.format(l_cmd2) else: pass LOG.info('HVAC {}'.format(l_mqtt_message)) p_pyhouse_obj.APIs.Computer.MqttAPI.MqttPublish(l_mqtt_topic, p_device_obj) # /temperature return
def test_01_GetObj(self): """ """ l_msg = MSG_50 # print(FormatBytes(l_msg), 'D2-01-A - Message') _l_ret = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_msg[2:5])
def _decode_0x50(self, p_controller_obj): """ Insteon Standard Message Received (11 bytes) A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to. See p 233(246) of 2009 developers guide. [0] = x02 [1] = 0x50 [2-4] = from address [5-7] = to address / group [8] = message flags [9] = command 1 [10] = command 2 """ l_mqtt = False l_message = p_controller_obj._Message l_device_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_device_obj.BrightnessPct = '?' if l_device_obj.DeviceType == 2: # HVAC Type DecodeHvac().decode_0x50(self.m_pyhouse_obj, l_device_obj, p_controller_obj) return if l_device_obj.DeviceType == 3: # Security Type DecodeSecurity().decode_0x50(self.m_pyhouse_obj, l_device_obj, p_controller_obj) return l_flags = utilDecode._decode_message_flag(l_message[8]) l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_data = [l_cmd1, l_cmd2] l_debug_msg = 'Fm:"{}"; Flg:{}; C1:{:#x},{:#x}; '.format(l_device_obj.Name, l_flags, l_cmd1, l_cmd2) # # Break down bits 7(msb), 6, 5 into message type # if l_message[8] & 0xE0 == 0x80: # 100 - SB [Broadcast] l_debug_msg += utilDecode._devcat(l_message[5:7], l_device_obj) elif l_message[8] & 0xE0 == 0xC0: # 110 - SA Broadcast = all link broadcast of group id l_group = l_message[7] l_debug_msg += 'A-L-brdcst-Gp:"{}","{}"; '.format(l_group, l_data) try: if l_cmd1 == MESSAGE_TYPES['product_data_request']: # 0x03 l_debug_msg += " Product-data-request." elif l_cmd1 == MESSAGE_TYPES['cleanup_success']: # 0x06 l_debug_msg += 'CleanupSuccess with {} failures; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['engine_version']: # 0x0D l_device_obj.EngineVersion = l_cmd2 l_debug_msg += 'Engine-version:"{}(i-{})"; '.format(l_cmd2, l_cmd2 + 1) elif l_cmd1 == MESSAGE_TYPES['id_request']: # 0x10 l_device_obj.FirmwareVersion = l_cmd2 l_debug_msg += 'Request-ID:"{}"; '.format(l_device_obj.FirmwareVersion) elif l_cmd1 == MESSAGE_TYPES['on']: # 0x11 l_device_obj.BrightnessPct = 100 l_mqtt = True l_debug_msg += 'Turn ON; '.format(l_device_obj.Name) elif l_cmd1 == MESSAGE_TYPES['off']: # 0x13 l_device_obj.BrightnessPct = 0 l_mqtt = True l_debug_msg += 'Turn OFF; '.format(l_device_obj.Name) elif l_cmd1 == MESSAGE_TYPES['status_request']: # 0x19 l_device_obj.BrightnessPct = l_level = utilDecode.decode_light_brightness(l_cmd2) l_debug_msg += 'Status of light:"{}"-level:"{}"; '.format(l_device_obj.Name, l_level) elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 0x01: l_debug_msg += ' Device-Set-Button-Pressed ' elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 0x02: l_debug_msg += ' Controller-Set-Button-Pressed ' else: l_debug_msg += '\n\tUnknown-type -"{}"; '.format(FormatBytes(l_message)) l_device_obj.BrightnessPct = utilDecode.decode_light_brightness(l_cmd2) l_mqtt = True except AttributeError as e_err: LOG.error('ERROR decoding 0x50 record {}'.format(e_err)) Insteon_utils.update_insteon_obj(self.m_pyhouse_obj, l_device_obj) p_controller_obj.Ret = True LOG.info('{}'.format(l_debug_msg)) if l_mqtt: self.m_pyhouse_obj.APIs.Computer.MqttAPI.MqttPublish('lighting/status/debug', l_device_obj) # /lig return
def _decode_50_record(self, p_controller_obj): """ Insteon Standard Message Received (11 bytes) A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to. See p 233(246) of developers guide. [0] = x02 [1] = 0x50 [2-4] = from address [5-7] = to address / group [8] = message flags [9] = command 1 [10] = command 2 """ l_message = p_controller_obj._Message l_device_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_flags = utilDecode._decode_message_flag(l_message[8]) l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_data = [l_cmd1, l_cmd2] # print(PrettyFormatAny.form(l_device_obj, 'Insteon_decoder 156 - Device')) if l_device_obj.DeviceType == 2: Insteon_HVAC.ihvac_utility().decode_50_record(self.m_pyhouse_obj, l_device_obj, p_controller_obj) return self.check_for_more_decoding(p_controller_obj, True) l_debug_msg = 'Std Msg fm: {}; Cmd1:{:#x}, Cmd2:{:#x}; '.format(l_device_obj.Name, l_cmd1, l_cmd2) # Break down bits 7(msb), 6, 5 into message type if l_message[8] & 0xE0 == 0x80: # Broadcast/NAK Message (100) l_debug_msg += utilDecode._devcat(l_message[5:7], l_device_obj) elif l_message[8] & 0xE0 == 0xC0: # (110) all link broadcast of group id l_group = l_message[7] l_debug_msg += "All-Link broadcast - Group:{}, Data:{}; ".format(l_group, l_data) LOG.info("== 50B All-link Broadcast Group:{}, Data:{} ==".format(l_group, l_data)) # try: if l_cmd1 == MESSAGE_TYPES['product_data_request']: # 0x03 l_debug_msg += " product data request. - Should never happen - S/B 51 response" elif l_cmd1 == MESSAGE_TYPES['engine_version']: # 0x0D l_engine_id = l_cmd2 l_device_obj.EngineVersion = l_engine_id l_debug_msg += "Engine version is: {}; ".format(l_engine_id) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['id_request']: # 0x10 l_debug_msg += "Request ID From: {}; ".format(l_device_obj.Name) # LOG.info("Got an ID request. Light:{}".format(l_device_obj.Name,)) elif l_cmd1 == MESSAGE_TYPES['on']: # 0x11 l_device_obj.CurLevel = 100 l_debug_msg += "Device:{} turned Full ON ; ".format(l_device_obj.Name) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['off']: # 0x13 l_device_obj.CurLevel = 0 l_debug_msg += "Light:{} turned Full OFF; ".format(l_device_obj.Name) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['status_request']: # 0x19 l_level = int(((l_cmd2 + 2) * 100) / 256) l_device_obj.CurLevel = l_level l_debug_msg += "Status of light:{} is level:{}; ".format(l_device_obj.Name, l_level) LOG.info("PLM:{} Got Light Status From:{}, Level is:{} ".format(p_controller_obj.Name, l_device_obj.Name, l_level)) elif l_cmd1 >= MESSAGE_TYPES['thermostat_temp_up'] and l_cmd1 <= MESSAGE_TYPES['thermostat_report']: # 0x6e _l_ret1 = Insteon_HVAC.ihvac_utility().decode_50_record(l_device_obj, l_cmd1, l_cmd2) pass elif l_cmd1 >= 0x68 and l_cmd1 <= 0x75: # 0x6e _l_ret1 = Insteon_HVAC.ihvac_utility().decode_50_record(l_device_obj, l_cmd1, l_cmd2) pass elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 01: l_debug_msg += ' Device Set Button Pressed ' elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 02: l_debug_msg += ' Controller Set Button Pressed ' else: l_debug_msg += "\n\tUnknown type - last command was {} - {}; ".format(l_device_obj._Command1, PrintBytes(l_message)) LOG.warn('Decoding 50 tyoe {}'.format(l_debug_msg)) except AttributeError as e_err: LOG.error('ERROR decoding 50 record {}'.format(e_err)) l_ret = True LOG.info('50 Resp; {}'.format(l_debug_msg)) return self.check_for_more_decoding(p_controller_obj, l_ret)
def decode_0x50(self, p_pyhouse_obj, p_device_obj, p_controller_obj): """ @param p_device_obj: is the Device (GDO, Motion...) we are decoding. A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to. See p 233(246) of 2009 developers guide. [0] = x02 [1] = 0x50 [2-4] = from address [5-7] = to address / group [8] = message flags [9] = command 1 [10] = command 2 """ l_device = SensorMessage(p_device_obj.Name, p_device_obj.RoomName, 'Generic ') l_mqtt_topic = 'security/' l_mqtt_msg = 'security ' if p_device_obj.DeviceSubType == 1: l_mqtt_msg += 'Garage Door: ' l_device.Type = 'Garage Door' l_mqtt_topic += 'garage_door' elif p_device_obj.DeviceSubType == 2: l_mqtt_msg += 'Motion Sensor: ' l_device.Type = 'Motion Sensor' l_mqtt_topic += 'motion_sensor' # l_message = p_controller_obj._Message l_firmware = l_message[7] l_flags = utilDecode._decode_message_flag(l_message[8]) l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_data = [l_cmd1, l_cmd2] l_mqtt_msg += 'Fm:"{}"; Flg:{}; C1:{:#x},{:#x}; '.format(p_device_obj.Name, l_flags, l_cmd1, l_cmd2) if l_message[8] & 0xE0 == 0x80: # 100 - SB [Broadcast] l_mqtt_msg += utilDecode._devcat(l_message[5:7], p_device_obj) elif l_message[8] & 0xE0 == 0xC0: # 110 - SA Broadcast = all link broadcast of group id l_group = l_message[7] l_mqtt_msg += 'A-L-brdcst-Gp:"{}","{}"; '.format(l_group, l_data) if l_cmd1 == MESSAGE_TYPES['cleanup_success']: # 0x06 l_mqtt_msg += 'CleanupSuccess with {} failures; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['engine_version']: # 0x0D p_device_obj.EngineVersion = l_cmd2 l_mqtt_msg += 'Engine-version:"{}"; '.format(l_cmd2) elif l_cmd1 == MESSAGE_TYPES['id_request']: # 0x10 p_device_obj.FirmwareVersion = l_firmware l_mqtt_msg += 'Request-ID-From:"{}"; '.format(p_device_obj.Name) elif l_cmd1 == MESSAGE_TYPES['on']: # 0x11 if p_device_obj.DeviceSubType == 1: # The status turns on when the Garage Door goes closed l_mqtt_msg += 'Garage Door Closed; '.format(p_device_obj.Name) p_device_obj.Status = 'Close' l_device.Status = 'Garage Door Closed.' elif p_device_obj.DeviceSubType == 2: l_mqtt_msg += 'Motion Detected; '.format(p_device_obj.Name) l_device.Status = 'Motion Detected.' else: l_mqtt_msg += 'Unknown SubType {} for Device; '.format(p_device_obj.DeviceSubType, p_device_obj.Name) if ((l_message[8] & 0xE0) >> 5) == 6: p_pyhouse_obj.APIs.Computer.MqttAPI.MqttPublish(l_mqtt_topic, l_device) # /security elif l_cmd1 == MESSAGE_TYPES['off']: # 0x13 if p_device_obj.DeviceSubType == 1: l_mqtt_msg += 'Garage Door Opened; '.format(p_device_obj.Name) p_device_obj.Status = 'Opened' l_device.Status = 'Garage Door Opened.' elif p_device_obj.DeviceSubType == 2: l_mqtt_msg += 'NO Motion; '.format(p_device_obj.Name) l_device.Status = 'Motion Stopped.' else: l_mqtt_msg += 'Unknown SubType {} for Device; '.format(p_device_obj.DeviceSubType, p_device_obj.Name) if ((l_message[8] & 0xE0) >> 5) == 6: p_pyhouse_obj.APIs.Computer.MqttAPI.MqttPublish(l_mqtt_topic, l_device) # /security LOG.info('Security {}'.format(l_mqtt_msg)) Insteon_utils.update_insteon_obj(p_pyhouse_obj, p_device_obj) return
def test_02_GetObj(self): """ """ l_msg = MSG_50 l_ret = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_msg) print(PrettyFormatAny.form(l_ret, 'Combined Dicts'))
def _decode_50_record(self, p_controller_obj): """ Insteon Standard Message Received (11 bytes) A Standard-length INSTEON message is received from either a Controller or Responder that you are ALL-Linked to. See p 233(246) of developers guide. [0] = x02 [1] = 0x50 [2-4] = from address [5-7] = to address / group [8] = message flags [9] = command 1 [10] = command 2 """ l_message = p_controller_obj._Message l_device_obj = utilDecode.get_obj_from_message(self.m_pyhouse_obj, l_message[2:5]) l_flags = utilDecode._decode_message_flag(l_message[8]) l_cmd1 = l_message[9] l_cmd2 = l_message[10] l_data = [l_cmd1, l_cmd2] # print(PrettyFormatAny.form(l_device_obj, 'Insteon_decoder 156 - Device')) if l_device_obj.DeviceType == 2: Insteon_HVAC.ihvac_utility().decode_50_record( self.m_pyhouse_obj, l_device_obj, p_controller_obj) return self.check_for_more_decoding(p_controller_obj, True) l_debug_msg = 'Std Msg fm: {}; Cmd1:{:#x}, Cmd2:{:#x}; '.format( l_device_obj.Name, l_cmd1, l_cmd2) # Break down bits 7(msb), 6, 5 into message type if l_message[8] & 0xE0 == 0x80: # Broadcast/NAK Message (100) l_debug_msg += utilDecode._devcat(l_message[5:7], l_device_obj) elif l_message[ 8] & 0xE0 == 0xC0: # (110) all link broadcast of group id l_group = l_message[7] l_debug_msg += "All-Link broadcast - Group:{}, Data:{}; ".format( l_group, l_data) LOG.info("== 50B All-link Broadcast Group:{}, Data:{} ==".format( l_group, l_data)) # try: if l_cmd1 == MESSAGE_TYPES['product_data_request']: # 0x03 l_debug_msg += " product data request. - Should never happen - S/B 51 response" elif l_cmd1 == MESSAGE_TYPES['engine_version']: # 0x0D l_engine_id = l_cmd2 l_device_obj.EngineVersion = l_engine_id l_debug_msg += "Engine version is: {}; ".format(l_engine_id) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['id_request']: # 0x10 l_debug_msg += "Request ID From: {}; ".format( l_device_obj.Name) # LOG.info("Got an ID request. Light:{}".format(l_device_obj.Name,)) elif l_cmd1 == MESSAGE_TYPES['on']: # 0x11 l_device_obj.CurLevel = 100 l_debug_msg += "Device:{} turned Full ON ; ".format( l_device_obj.Name) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['off']: # 0x13 l_device_obj.CurLevel = 0 l_debug_msg += "Light:{} turned Full OFF; ".format( l_device_obj.Name) self._publish(self.m_pyhouse_obj, l_device_obj) elif l_cmd1 == MESSAGE_TYPES['status_request']: # 0x19 l_level = int(((l_cmd2 + 2) * 100) / 256) l_device_obj.CurLevel = l_level l_debug_msg += "Status of light:{} is level:{}; ".format( l_device_obj.Name, l_level) LOG.info( "PLM:{} Got Light Status From:{}, Level is:{} ".format( p_controller_obj.Name, l_device_obj.Name, l_level)) elif l_cmd1 >= MESSAGE_TYPES[ 'thermostat_temp_up'] and l_cmd1 <= MESSAGE_TYPES[ 'thermostat_report']: # 0x6e _l_ret1 = Insteon_HVAC.ihvac_utility().decode_50_record( l_device_obj, l_cmd1, l_cmd2) pass elif l_cmd1 >= 0x68 and l_cmd1 <= 0x75: # 0x6e _l_ret1 = Insteon_HVAC.ihvac_utility().decode_50_record( l_device_obj, l_cmd1, l_cmd2) pass elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 01: l_debug_msg += ' Device Set Button Pressed ' elif l_message[8] & 0xE0 == 0x80 and l_cmd1 == 02: l_debug_msg += ' Controller Set Button Pressed ' else: l_debug_msg += "\n\tUnknown type - last command was {} - {}; ".format( l_device_obj._Command1, PrintBytes(l_message)) LOG.warn('Decoding 50 tyoe {}'.format(l_debug_msg)) except AttributeError as e_err: LOG.error('ERROR decoding 50 record {}'.format(e_err)) l_ret = True LOG.info('50 Resp; {}'.format(l_debug_msg)) return self.check_for_more_decoding(p_controller_obj, l_ret)