def _create_set_property_msg(self, prop, cmd, val): """Create an extended message to set a property. Create an extended message with: cmd1: 0x2e cmd2: 0x00 flags: Direct Extended d1: group d2: cmd d3: val d4 - d14: 0x00 Parameters: prop: Property name to update cmd: Command value 0x02: on mask 0x03: off mask 0x04: x10 house code 0x05: ramp rate 0x06: on level 0x07: LED brightness 0x08: Non-Toggle mask 0x09: LED bit mask (Do not use in this class. Use LED class) 0x0a: X10 All bit mask 0x0c: Trigger group bit mask val: New property value """ user_data = Userdata({'d1': self.group, 'd2': cmd, 'd3': val}) msg = ExtendedSend(self._address, COMMAND_EXTENDED_GET_SET_0X2E_0X00, user_data) msg.set_checksum() self._set_sent_property(prop, val) return msg
def test_extended_ack(): """Test extended ack.""" callbacks = MockCallbacks() callbacks.callbackvalue1 = "Callback 1" callbacks.callbackvalue2 = "Callback 2" message_callbacks = MessageCallback() address = '1a2b3c' template_ext_ack = ExtendedSend.template(address, acknak=MESSAGE_ACK) template_std_ack = StandardSend.template(address, acknak=MESSAGE_ACK) message_callbacks.add(template_ext_ack, callbacks.callbackvalue1) message_callbacks.add(template_std_ack, callbacks.callbackvalue2) extmsg = ExtendedSend(address, COMMAND_LIGHT_ON_0X11_NONE, {'d1': 0x02}, cmd2=0xff, acknak=MESSAGE_ACK) stdmsg = StandardSend(address, COMMAND_LIGHT_ON_0X11_NONE, cmd2=0xff, acknak=MESSAGE_ACK) result1 = message_callbacks.get_callbacks_from_message(extmsg) result2 = message_callbacks.get_callbacks_from_message(stdmsg) assert result2 == [callbacks.callbackvalue2] assert result1 == [callbacks.callbackvalue1]
def off(self): """Turn off the fan.""" off_command = ExtendedSend(self._address, COMMAND_LIGHT_OFF_0X13_0X00, self._udata) off_command.set_checksum() self._send_method(off_command, self._off_message_received) _LOGGER.debug("Ending DimmableSwitch_Fan.off")
def set(self, mode): """Set the thermostat mode. Mode optons: OFF = 0x00, HEAT = 0x01, COOL = 0x02, AUTO = 0x03, FAN_AUTO = 0x04, FAN_ALWAYS_ON = 0x8 """ new_mode = None if mode == ThermostatMode.OFF: new_mode = COMMAND_THERMOSTAT_CONTROL_OFF_ALL_0X6B_0X09 elif mode == ThermostatMode.HEAT: new_mode = COMMAND_THERMOSTAT_CONTROL_ON_HEAT_0X6B_0X04 elif mode == ThermostatMode.COOL: new_mode = COMMAND_THERMOSTAT_CONTROL_ON_COOL_0X6B_0X05 elif mode == ThermostatMode.AUTO: new_mode = COMMAND_THERMOSTAT_CONTROL_ON_AUTO_0X6B_0X06 if new_mode: msg = ExtendedSend(address=self._address, commandtuple=new_mode, userdata=Userdata()) msg.set_checksum() self._send_method(msg, self._mode_change_ack)
def on(self): """Send an ON message to device group.""" on_command = ExtendedSend(self._address, COMMAND_LIGHT_ON_0X11_NONE, self._udata, cmd2=0xff) on_command.set_checksum() self._send_method(on_command, self._on_message_received)
def on(self): """Turn on the fan.""" on_command = ExtendedSend(self._address, COMMAND_LIGHT_ON_0X11_NONE, self._udata, cmd2=FAN_SPEED_MEDIUM) on_command.set_checksum() self._send_method(on_command, self._on_message_received)
def extended_status_request(self): """Send status request for group/button.""" self._status_received = False user_data = Userdata({'d1': self.group, 'd2': 0x00}) cmd = ExtendedSend(self._address, COMMAND_EXTENDED_GET_SET_0X2E_0X00, userdata=user_data) cmd.set_checksum() self._send_method(cmd, self._status_message_received, True)
def set(self, val): """Set the heat set point.""" msg = ExtendedSend( address=self._address, commandtuple=COMMAND_THERMOSTAT_SET_HEAT_SETPOINT_0X6D_NONE, cmd2=int(val * 2), userdata=Userdata()) msg.set_checksum() self._send_method(msg, self._set_heat_point_ack)
async def _send_led_on_off_request(self, group, val): _LOGGER.debug("OnOffKeypadLed._send_led_on_off_request was called") await self._send_led_change_lock self._new_value = set_bit(self._value, group, bool(val)) user_data = Userdata({'d1': 0x01, 'd2': 0x09, 'd3': self._new_value}) msg = ExtendedSend(self._address, COMMAND_EXTENDED_GET_SET_0X2E_0X00, user_data) msg.set_checksum() self._send_method(msg, self._on_off_ack_received, True)
def set_level(self, val): """Set the fan speed.""" speed = self._value_to_fan_speed(val) if val == 0: self.off() else: set_command = ExtendedSend(self._address, COMMAND_LIGHT_ON_0X11_NONE, self._udata, cmd2=speed) set_command.set_checksum() self._send_method(set_command, self._on_message_received)
def test_extendedSend(): """Test ExtendedSend.""" address = bytearray([0x11, 0x22, 0x33]) flags = 0x44 | 0x10 cmd1 = 0x55 cmd2 = 0x66 userdata = {} ack = 0x06 nak = 0x15 for i in range(1, 15): key = 'd' + str(i) val = 0xe0 + i userdata.update({key: val}) msg = ExtendedSend(address, { 'cmd1': cmd1, 'cmd2': cmd2 }, userdata, flags=flags) assert msg.hex == hexmsg(0x02, 0x62, Address(address), flags | 0x10, cmd1, cmd2, userdata) assert not msg.isack assert not msg.isnak assert len(msg.hex) / 2 == msg.sendSize msg = ExtendedSend(address, { 'cmd1': cmd1, 'cmd2': cmd2 }, userdata, flags=flags, acknak=ack) assert msg.hex == hexmsg(0x02, 0x62, Address(address), flags | 0x10, cmd1, cmd2, userdata, ack) assert msg.isack assert not msg.isnak assert len(msg.hex) / 2 == msg.receivedSize msg = ExtendedSend(address, { 'cmd1': cmd1, 'cmd2': cmd2 }, userdata, flags=flags, acknak=nak) assert msg.hex == hexmsg(0x02, 0x62, Address(address), flags | 0x10, cmd1, cmd2, userdata, nak) assert not msg.isack assert msg.isnak assert len(msg.hex) / 2 == msg.receivedSize
def async_refresh_state(self): """Request each state to provide status update.""" _LOGGER.debug('Setting up extended status') ext_status = ExtendedSend( address=self._address, commandtuple=COMMAND_EXTENDED_GET_SET_0X2E_0X00, cmd2=0x02, userdata=Userdata()) ext_status.set_crc() _LOGGER.debug('Sending ext status: %s', ext_status) self._send_msg(ext_status) _LOGGER.debug('Sending temp status request') self.temperature.async_refresh_state()
def scene_off(self): """Trigger group/scene to OFF level.""" user_data = Userdata({ 'd1': self._group, 'd2': 0x00, 'd3': 0x00, 'd4': 0x13, 'd5': 0x00, 'd6': 0x00 }) self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0x00) cmd = ExtendedSend(self._address, COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00, user_data) cmd.set_checksum() self._send_method(cmd, self._received_scene_triggered)
def scene_on(self): """Trigger group/scene to ON level.""" user_data = Userdata({ "d1": self._group, "d2": 0x00, "d3": 0x00, "d4": 0x11, "d5": 0xFF, "d6": 0x00, }) self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0xFF) cmd = ExtendedSend(self._address, COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00, user_data) cmd.set_checksum() _LOGGER.debug("Calling scene_on and sending response to " "_received_scene_triggered") self._send_method(cmd, self._received_scene_triggered)
def scene_on(self): """Trigger group/scene to ON level.""" user_data = Userdata({ 'd1': self._group, 'd2': 0x00, 'd3': 0x00, 'd4': 0x11, 'd5': 0xff, 'd6': 0x00 }) self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, 0xff) cmd = ExtendedSend(self._address, COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00, user_data) cmd.set_checksum() _LOGGER.debug('Calling scene_on and sending response to ' '_received_scene_triggered') self._send_method(cmd, self._received_scene_triggered)
def scene_level(self, level): """Trigger group/scene to input level.""" if level == 0: self.scene_off() else: user_data = Userdata({ "d1": self._group, "d2": 0x00, "d3": 0x00, "d4": 0x11, "d5": level, "d6": 0x00, }) self._set_sent_property(DIMMABLE_KEYPAD_SCENE_ON_LEVEL, level) cmd = ExtendedSend(self._address, COMMAND_EXTENDED_TRIGGER_ALL_LINK_0X30_0X00, user_data) cmd.set_checksum() self._send_method(cmd, self._received_scene_triggered)
def from_raw_message(cls, rawmessage): """Create a message from a raw byte stream.""" if (rawmessage[5] & MESSAGE_FLAG_EXTENDED_0X10) == MESSAGE_FLAG_EXTENDED_0X10: if len(rawmessage) >= ExtendedSend.receivedSize: msg = ExtendedSend.from_raw_message(rawmessage) else: msg = None else: msg = StandardSend(rawmessage[2:5], {'cmd1': rawmessage[6], 'cmd2': rawmessage[7]}, flags=rawmessage[5], acknak=rawmessage[8:9]) return msg
def write_record(self, mem_addr: int, mode: str, group: int, target, data1=0x00, data2=0x00, data3=0x00): """Write an All-Link database record.""" if not (self._have_first_record() and self._have_last_record()): self.log.error('Must load the ALDB before writing to it') else: self._prior_status = self._status self._status = ALDBStatus.LOADING mem_hi = mem_addr >> 8 mem_lo = mem_addr & 0xff controller = True if mode == 'c' else False control_flag = ControlFlags(True, controller, True, False, False) addr = Address(target) addr_lo = addr.bytes[0] addr_mid = addr.bytes[1] addr_hi = addr.bytes[2] chksum = 0xff - ( (0x2f + 0x02 + mem_hi + mem_lo + 0x08 + control_flag.byte + addr_lo + addr_mid + addr_hi + group + data1 + data2 + data3) & 0xff) + 1 userdata = Userdata({ 'd1': 0, 'd2': 0x02, 'd3': mem_hi, 'd4': mem_lo, 'd5': 0x08, 'd6': control_flag.byte, 'd7': group, 'd8': addr_lo, 'd9': addr_mid, 'd10': addr_hi, 'd11': data1, 'd12': data2, 'd13': data3, 'd14': chksum }) msg = ExtendedSend(self._address, COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00, userdata=userdata) self.log.info('writing message %s', msg) self._send_method(msg, self._handle_write_aldb_ack, True) self._load_action = LoadAction(mem_addr, 1, 0)
def load(self, mem_addr=0x0000, rec_count=0, retry=0): """Read the device database and load.""" if self._version == ALDBVersion.Null: self._status = ALDBStatus.LOADED self.log.debug('Device has no ALDB') else: self._status = ALDBStatus.LOADING self.log.debug('Tring to lock from load') yield from self._rec_mgr_lock self.log.debug('load yielded lock') mem_hi = mem_addr >> 8 mem_lo = mem_addr & 0xff log_output = 'ALDB read' max_retries = 0 if rec_count: max_retries = ALDB_RECORD_RETRIES if mem_addr == 0x0000: log_output = '{:s} first record'.format(log_output) else: log_output = '{:s} record {:04x}'.format( log_output, mem_addr) else: max_retries = ALDB_ALL_RECORD_RETRIES log_output = '{:s} all records'.format(log_output) if retry: log_output = '{:s} retry {:d} of {:d}'.format( log_output, retry, max_retries) self.log.info(log_output) chksum = 0xff - ((0x2f + mem_hi + mem_lo + 1) & 0xff) + 1 userdata = Userdata({ 'd1': 0, 'd2': 0, 'd3': mem_hi, 'd4': mem_lo, 'd5': rec_count, 'd14': chksum }) msg = ExtendedSend(self._address, COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00, userdata=userdata) self._send_method(msg, self._handle_read_aldb_ack, True) if not self._load_action: self._set_load_action(mem_addr, rec_count, -1, False)
def del_record(self, mem_addr: int): """Write an All-Link database record.""" record = self._records.get(mem_addr) if not record: self.log.error('Must load the ALDB record before deleting it') else: self._prior_status = self._status self._status = ALDBStatus.LOADING mem_hi = mem_addr >> 8 mem_lo = mem_addr & 0xff controller = record.control_flags.is_controller control_flag = ControlFlags(False, controller, True, False, False) addr = record.address addr_lo = addr.bytes[0] addr_mid = addr.bytes[1] addr_hi = addr.bytes[2] group = record.group data1 = record.data1 data2 = record.data2 data3 = record.data3 chksum = 0xff - ( (0x2f + 0x02 + mem_hi + mem_lo + 0x08 + control_flag.byte + addr_lo + addr_mid + addr_hi + group + data1 + data2 + data3) & 0xff) + 1 userdata = Userdata({ 'd1': 0, 'd2': 0x02, 'd3': mem_hi, 'd4': mem_lo, 'd5': 0x08, 'd6': control_flag.byte, 'd7': group, 'd8': addr_lo, 'd9': addr_mid, 'd10': addr_hi, 'd11': data1, 'd12': data2, 'd13': data3, 'd14': chksum }) msg = ExtendedSend(self._address, COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00, userdata=userdata) self.log.info('writing message %s', msg) self._send_method(msg, self._handle_write_aldb_ack, True) self._load_action = LoadAction(mem_addr, 1, 0)
def off(self): """Send an OFF message to device group.""" off_command = ExtendedSend(self._address, COMMAND_LIGHT_OFF_0X13_0X00, self._udata) off_command.set_checksum() self._send_method(off_command, self._off_message_received)
def off(self): """Turn off the fan.""" off_command = ExtendedSend(self._address, COMMAND_LIGHT_OFF_0X13_0X00, self._udata) self._send_method(off_command, self._off_message_received) self.log.debug('Ending DimmableSwitch_Fan.off')
async def run_test(loop): """Asyncio test method.""" plm = MockPLM(loop) callbacks = MockCallbacks() address = '1a2b3c' target = '4d5e6f' cat = 0x02 subcat = 0x0d product_key = None description = 'ToggleLinc Relay' model = '2466S' device = SwitchedLightingControl_2663_222(plm, address, cat, subcat, product_key, description, model) plm.devices[address] = device assert device.address.hex == address assert device.cat == cat assert device.subcat == subcat assert device.product_key == 0x00 # Product key should not be None assert device.description == description assert device.model == model assert device.id == address device.states[0x01].register_updates(callbacks.callbackmethod1) device.states[0x02].register_updates(callbacks.callbackmethod2) device.states[0x01].on() await asyncio.sleep(.1, loop=loop) sentmsg = StandardSend(address, COMMAND_LIGHT_ON_0X11_NONE, cmd2=0xff) assert plm.sentmessage == sentmsg.hex receivedmsg = StandardSend(address, COMMAND_LIGHT_ON_0X11_NONE, cmd2=0xff, acknak=MESSAGE_ACK) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) receivedmsg = StandardReceive(address, target, { 'cmd1': 0x09, 'cmd2': 0xff }, flags=MessageFlags.create( MESSAGE_TYPE_DIRECT_MESSAGE_ACK, 0, 2, 3)) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) assert callbacks.callbackvalue1 == 0xff device.states[0x02].on() await asyncio.sleep(.1, loop=loop) receivedmsg = ExtendedSend(address, COMMAND_LIGHT_ON_0X11_NONE, {'d1': 0x02}, cmd2=0xff, acknak=MESSAGE_ACK) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) receivedmsg = StandardReceive(address, target, { 'cmd1': 0x09, 'cmd2': 0xff }, flags=MessageFlags.create( MESSAGE_TYPE_DIRECT_MESSAGE_ACK, 0, 2, 3)) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) sentmsg = ExtendedSend(address, COMMAND_LIGHT_ON_0X11_NONE, {'d1': 0x02}, cmd2=0xff) sentmsg.set_checksum() assert plm.sentmessage == sentmsg.hex assert callbacks.callbackvalue2 == 0xff device.states[0x01].off() await asyncio.sleep(.1, loop=loop) sentmsg = StandardSend(address, COMMAND_LIGHT_OFF_0X13_0X00) assert plm.sentmessage == sentmsg.hex receivedmsg = StandardSend(address, COMMAND_LIGHT_OFF_0X13_0X00, acknak=MESSAGE_ACK) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) receivedmsg = StandardReceive(address, target, { 'cmd1': 0x09, 'cmd2': 0x00 }, flags=MessageFlags.create( MESSAGE_TYPE_DIRECT_MESSAGE_ACK, 0, 2, 3)) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) sentmsg = StandardSend(address, COMMAND_LIGHT_OFF_0X13_0X00) assert plm.sentmessage == sentmsg.hex assert callbacks.callbackvalue1 == 0x00 device.states[0x02].off() await asyncio.sleep(.1, loop=loop) receivedmsg = ExtendedSend(address, COMMAND_LIGHT_OFF_0X13_0X00, {'d1': 0x02}, acknak=MESSAGE_ACK) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) receivedmsg = StandardReceive(address, target, { 'cmd1': 0x09, 'cmd2': 0x00 }, flags=MessageFlags.create( MESSAGE_TYPE_DIRECT_MESSAGE_ACK, 0, 2, 3)) plm.message_received(receivedmsg) await asyncio.sleep(.1, loop=loop) sentmsg = ExtendedSend(address, COMMAND_LIGHT_OFF_0X13_0X00, {'d1': 0x02}) sentmsg.set_checksum() assert plm.sentmessage == sentmsg.hex assert callbacks.callbackvalue2 == 0x00
async def run_test(loop): mockPLM = MockPLM(loop) linkcode = 0x01 group = 0x00 address = '112233' cat = 0x02 subcat = 0x39 firmware = 0x44 # Create OutletLinc device = insteonplm.devices.create(mockPLM, address, cat, subcat, firmware) # Start the process with an All-Link complete message with # the IM as a controller of Group 0x00 msg = AllLinkComplete(linkcode, group, address, cat, subcat, firmware) device.receive_message(msg) await asyncio.sleep(.1, loop=loop) # The device should start linking based on the groups in # self.states assert mockPLM.sentmessage == StandardSend( device.address, COMMAND_ENTER_LINKING_MODE_0X09_NONE, cmd2=0x01).hex msg = StandardSend(device.address, COMMAND_ENTER_LINKING_MODE_0X09_NONE, cmd2=0x01, acknak=MESSAGE_ACK) device.receive_message(msg) await asyncio.sleep(.1, loop=loop) # Confirm that the link attempt to group 0x01 completed msg = AllLinkComplete(0x00, 0x01, address, cat, subcat, firmware) device.receive_message(msg) await asyncio.sleep(.1, loop=loop) # The device should then start linking to group 0x02 assert mockPLM.sentmessage == StandardSend( device.address, COMMAND_ENTER_LINKING_MODE_0X09_NONE, cmd2=0x02).hex await asyncio.sleep(1, loop=loop) # Confirm that the link attempt to group 0x02 completed msg = AllLinkComplete(0x00, 0x01, address, cat, subcat, firmware) device.receive_message(msg) await asyncio.sleep(.1, loop=loop) # The device will now attempt to read the ALDB msg = ExtendedSend(address, COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00, userdata=Userdata()) msg.set_checksum() assert mockPLM.sentmessage == msg.hex # Send a dummy ALDB record as a high water mark to end the process msg = ExtendedReceive( address, '111111', commandtuple=COMMAND_EXTENDED_READ_WRITE_ALDB_0X2F_0X00, userdata=Userdata({ 'd1': 0, 'd2': 0x01, 'd3': 0xff, 'd4': 0x77, 'd5': 0, 'd6': 0, 'd7': 0, 'd8': 0, 'd9': 0, 'd10': 0, 'd11': 0, 'd12': 0, 'd13': 0, 'd14': 0x3b })) device.receive_message(msg) await asyncio.sleep(1, loop=loop)