def test_recs(self): proto = None calls = [] def callback(success, msg, value): calls.append(msg) addr = IM.Address('0a.12.34') db = Mockdb(addr) handler = IM.handler.DeviceDbGet(db, callback) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) data = bytes([0x01, 0, 0, 0, 0, 0xFF, 0, 0x01, 0, 0, 0, 0, 0, 0]) msg = Msg.InpExtended(addr, addr, flags, 0x2f, 0x00, data) r = handler.msg_received(proto, msg) assert r == Msg.CONTINUE assert len(calls) == 0 msg.data = bytes(14) r = handler.msg_received(proto, msg) assert r == Msg.FINISHED assert len(calls) == 1 assert calls[0] == "Database received" # no match msg.cmd1 = 0x00 r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN
def test_handle_ext_flags(self, test_device): # Captured data from my own motion detector # 00 01 03 00 ff 0e 00 ff 0e 01 18 4f 00 d2 # set as a 2842 model test_device.db.set_info(0x10, 0x01, 0x00) modem_addr = IM.Address(0x01, 0xAA, 0xFF) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( test_device.addr, modem_addr, flags, 0x2e, 0x00, bytes([ 0x00, 0x01, 0x03, 0x00, 0xff, 0x0e, 0x00, 0xff, 0x0e, 0x01, 0x18, 0x4f, 0x00, 0xd2 ])) def on_done(success, *args): assert success with mock.patch.object(IM.Signal, 'emit') as mocked: test_device.handle_ext_flags(msg, on_done) assert test_device.led_on assert test_device.night_only assert test_device.on_only assert test_device.battery_voltage_time > 0 assert mocked.call_count == 1 # the emit call should be false assert not mocked.call_args.args[1]
def test_recs(self): proto = None calls = [] addr = IM.Address('0a.12.34') handler = IM.handler.DeviceGetDb(addr, calls.append) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) data = bytes([0x01, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0, 0, 0]) msg = Msg.InpExtended(addr, addr, flags, 0x2f, 0x00, data) r = handler.msg_received(proto, msg) assert r == Msg.CONTINUE assert len(calls) == 1 assert calls[0] == msg msg.data = bytes(14) r = handler.msg_received(proto, msg) assert r == Msg.FINISHED assert len(calls) == 2 assert calls[1] is None # no match msg.cmd1 = 0x00 r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN
def test_handle_ext_flags(self, test_device): from_addr = IM.Address(0x01, 0x02, 0x05) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) data = bytes([0x01, 0x01, 0x00, 0x00, 0x20, 0x20, 0x1c, 0x1c, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00]) msg = Msg.InpExtended(from_addr, test_device.addr, flags, Msg.CmdType.EXTENDED_SET_GET, 0x00, data) def on_done(success, *args): assert success test_device.handle_ext_flags(msg, on_done) assert test_device.get_on_level() == 0x1C
def test_handle_ext_flags3(self, test_device, caplog): # set as a 2844 model test_device.db.set_info(0x10, 0x16, 0x00) modem_addr = IM.Address(0x01, 0xAA, 0xFF) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended(test_device.addr, modem_addr, flags, 0x2e, 0x00, bytes([0x00, 0x01, 0x03, 0x00, 0xff, 0x0e, 0x00, 0xff, 0x0e, 0x01, 0x18, 0x8C, 0x00, 0xd2]) ) def on_done(success, *args): assert success with mock.patch.object(IM.Signal, 'emit') as mocked: test_device.handle_ext_flags(msg, on_done) assert test_device.led_on assert test_device.night_only assert test_device.on_only assert test_device.battery_voltage_time > 0 assert mocked.call_count == 1 # the emit call should be false, not a low battery for 2844 assert not mocked.call_args.args[1]
def test_handle_ext_flags2(self, test_device): # This should trigger low battery test_device.battery_low_voltage = 8.0 modem_addr = IM.Address(0x01, 0xAA, 0xFF) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended(test_device.addr, modem_addr, flags, 0x2e, 0x00, bytes([0x00, 0x01, 0x03, 0x00, 0xff, 0x0e, 0x00, 0xff, 0x0e, 0x01, 0x18, 0x4f, 0x00, 0xd2]) ) def on_done(success, *args): assert success with mock.patch.object(IM.Signal, 'emit') as mocked: test_device.handle_ext_flags(msg, on_done) assert test_device.led_on assert test_device.night_only assert test_device.on_only assert test_device.battery_voltage_time > 0 assert mocked.call_count == 1 # the emit call should be true assert mocked.call_args.args[1]
def test_basic(self): obj = IM.db.Device() assert len(obj) == 0 assert obj.is_current(0) is False obj.delta = 1 assert obj.is_current(1) is True obj.clear_delta() assert obj.is_current(1) is False addr = IM.Address(0x10, 0xab, 0x1c) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) db_flags = Msg.DbFlags(in_use=True, is_controller=True, last_record=False) data = bytes([0x01, 0x02, 0x03]) raw = [0x00, 0x01, 0xfe, 0x10, # mem_loc 0x00, db_flags.to_bytes()[0], 0x03, # group addr.ids[0], addr.ids[1], addr.ids[2], data[0], data[1], data[2], 0x06] msg = Msg.InpExtended(addr, addr, flags, 0x00, 0x00, bytes(raw)) obj.handle_db_rec(msg) # add same addr w/ different group raw[6] = 0x02 msg.data = raw obj.handle_db_rec(msg) # new addr, same group addr2 = IM.Address(0x10, 0xab, 0x1d) raw[9] = 0x1d msg.data = raw obj.handle_db_rec(msg) # responder - not in a group db_flags = Msg.DbFlags(in_use=True, is_controller=False, last_record=False) raw[5] = db_flags.to_bytes()[0] msg.data = raw obj.handle_db_rec(msg) # in use = False db_flags = Msg.DbFlags(in_use=False, is_controller=True, last_record=False) raw[5] = db_flags.to_bytes()[0] msg.data = raw obj.handle_db_rec(msg) assert len(obj.entries) == 4 assert len(obj.unused) == 1 assert len(obj.groups) == 2 grp = obj.find_group(0x02) assert len(grp) == 2 assert grp[0].addr == addr assert grp[1].addr == addr2 e = obj.find(addr, 0x02, 'CTRL') assert e.addr == addr assert e.group == 0x02 assert e.db_flags.is_controller is True e = obj.find(addr2, 0x02, 'RESP') assert e.addr == addr2 assert e.group == 0x02 assert e.db_flags.is_responder is True e = obj.find(addr, 0x05, 'RESP') assert e is None str(obj) j = obj.to_json() obj2 = IM.db.Device.from_json(j) assert len(obj2.entries) == 4 assert len(obj2.unused) == 1 assert len(obj2.groups) == 2 obj2.clear() assert len(obj2) == 0 assert len(obj2.entries) == 0 assert len(obj2.unused) == 0 assert len(obj2.groups) == 0
def test_basic(self): obj = IM.db.Device(IM.Address(0x01, 0x02, 0x03)) assert len(obj) == 0 assert obj.is_current(0) is False obj.delta = 1 assert obj.is_current(1) is True obj.set_delta(None) assert obj.is_current(1) is False assert obj.engine is None obj.set_engine(1) assert obj.engine == 1 assert obj.desc is None assert obj.firmware is None obj.set_info(1, 2, 3) assert obj.desc.dev_cat == 1 assert obj.desc.sub_cat == 2 assert obj.firmware == 3 addr = IM.Address(0x10, 0xab, 0x1c) flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) db_flags = Msg.DbFlags(in_use=True, is_controller=True, is_last_rec=False) data = bytes([0x01, 0x02, 0x03]) raw = [0x00, 0x01, 0xfe, 0x10, # mem_loc 0x00, db_flags.to_bytes()[0], 0x03, # group addr.ids[0], addr.ids[1], addr.ids[2], data[0], data[1], data[2], 0x06] msg = Msg.InpExtended(addr, addr, flags, 0x00, 0x00, bytes(raw)) entry = IM.db.DeviceEntry.from_bytes(msg.data) obj.add_entry(entry) # add same addr w/ different group raw[6] = 0x02 raw[3] = 0x11 # have to change memory location msg.data = raw entry = IM.db.DeviceEntry.from_bytes(msg.data) obj.add_entry(entry) # new addr, same group addr2 = IM.Address(0x10, 0xab, 0x1d) raw[9] = 0x1d raw[3] = 0x12 # have to change memory location msg.data = raw entry = IM.db.DeviceEntry.from_bytes(msg.data) obj.add_entry(entry) # responder - not in a group db_flags = Msg.DbFlags(in_use=True, is_controller=False, is_last_rec=False) raw[5] = db_flags.to_bytes()[0] raw[3] = 0x13 # have to change memory location msg.data = raw entry = IM.db.DeviceEntry.from_bytes(msg.data) obj.add_entry(entry) # in use = False db_flags = Msg.DbFlags(in_use=False, is_controller=True, is_last_rec=False) raw[5] = db_flags.to_bytes()[0] raw[3] = 0x14 # have to change memory location msg.data = raw entry = IM.db.DeviceEntry.from_bytes(msg.data) obj.add_entry(entry) assert len(obj.entries) == 4 assert len(obj.unused) == 1 assert len(obj.groups) == 2 grp = obj.find_group(0x02) assert len(grp) == 2 assert grp[0].addr == addr assert grp[1].addr == addr2 e = obj.find(addr, 0x02, True) assert e.addr == addr assert e.group == 0x02 assert e.db_flags.is_controller is True e = obj.find(addr2, 0x02, False) assert e.addr == addr2 assert e.group == 0x02 assert e.db_flags.is_controller is False e = obj.find(addr, 0x05, False) assert e is None str(obj) j = obj.to_json() obj2 = IM.db.Device.from_json(j, '', None) assert len(obj2.entries) == 4 assert len(obj2.unused) == 1 assert len(obj2.groups) == 2 obj2.clear() assert len(obj2) == 0 assert len(obj2.entries) == 0 assert len(obj2.unused) == 0 assert len(obj2.groups) == 0
def test_cmd_from_msg(self): # Tests matching the command from the outbound message. proto = MockProto() calls = [] def callback(msg, on_done=None): calls.append(msg) addr = IM.Address('0a.12.34') # sent message, match input command out = Msg.OutExtended.direct(addr, 0x2e, 0x00, bytes([0x00] * 2 + [0x01] + [0x00] * 11), crc_type="CRC") handler = IM.handler.ExtendedCmdResponse(out, callback) r = handler.msg_received(proto, "dummy") assert r == Msg.UNKNOWN # ack back. out.is_ack = False r = handler.msg_received(proto, out) assert r == Msg.CONTINUE # wrong cmd out.cmd1 = 0x13 r = handler.msg_received(proto, out) assert r == Msg.UNKNOWN # wrong addr out.cmd1 = 0x11 out.to_addr = IM.Address('0a.12.33') r = handler.msg_received(proto, out) assert r == Msg.UNKNOWN # Now pass in the input message. # expected input meesage flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x2e, 0x00) r = handler.msg_received(proto, msg) assert r == Msg.CONTINUE # wrong cmd msg.cmd1 = 0x13 r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN # wrong addr msg.cmd1 = 0x11 msg.from_addr = IM.Address('0a.12.33') r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN # direct NAK flags = Msg.Flags(Msg.Flags.Type.DIRECT_NAK, False) msg = Msg.InpStandard(addr, addr, flags, 0x2e, 0x00) r = handler.msg_received(proto, msg) assert r == Msg.FINISHED # unexpected flags = Msg.Flags(Msg.Flags.Type.BROADCAST, False) msg = Msg.InpStandard(addr, addr, flags, 0x2e, 0x00) r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN # Test receipt of extended payloads flags = Msg.Flags(Msg.Flags.Type.DIRECT, False) msg = Msg.InpExtended(addr, addr, flags, 0x2e, 0x00, bytes([0x00] * 14)) r = handler.msg_received(proto, msg) assert r == Msg.FINISHED assert len(calls) == 1 assert calls[0] == msg # Test receipt of bad payloads msg.from_addr = IM.Address('0a.12.33') r = handler.msg_received(proto, msg) assert r == Msg.UNKNOWN
def test_basic(self, tmpdir): protocol = MockProto() modem = MockModem(tmpdir) addr = IM.Address(0x01, 0x02, 0x03) thermo = Thermo(protocol, modem, addr) # setup signal tracking thermo.signal_ambient_temp_change.connect( self.handle_ambient_temp_change) thermo.signal_fan_mode_change.connect(self.handle_fan_mode_change) thermo.signal_mode_change.connect(self.handle_mode_change) thermo.signal_cool_sp_change.connect(self.handle_cool_sp_change) thermo.signal_heat_sp_change.connect(self.handle_heat_sp_change) thermo.signal_ambient_humid_change.connect( self.handle_ambient_humid_change) thermo.signal_status_change.connect(self.handle_status_change) thermo.signal_hold_change.connect(self.handle_hold_change) thermo.signal_energy_change.connect(self.handle_energy_change) # Lightly test pairing and I mean light. Most of this testing is # handled by other tests thermo.pair() msg = Msg.OutStandard.direct(addr, 0x19, 0x00) test_msg = protocol.msgs.pop(0) assert test_msg.to_bytes() == msg.to_bytes() # test get_status thermo.get_status() msg = Msg.OutExtended.direct(addr, 0x2e, 0x02, bytes([0x00] * 14), crc_type="CRC") test_msg = protocol.msgs.pop(0) assert test_msg.to_bytes() == msg.to_bytes() # test handling of get_status response CELSIUS flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( addr, addr, flags, 0x2e, 0x02, bytes([ 0x01, 0x04, 0x0a, 0x21, 0x05, 0x11, 0x1b, 0x1e, 0x00, 0xe0, 0x88, 0x0e, 0x0f, 0xde ])) thermo.handle_status(msg, on_done=self.done) assert self.status == Thermo.Status.OFF assert self.hold is False assert self.energy is False assert self.fan == Thermo.Fan.ON assert self.mode == Thermo.Mode.AUTO assert self.humid == 30 assert self.cool_sp == 27 assert self.heat_sp == 14 assert self.ambient == 22.4 assert thermo.units == Thermo.CELSIUS # Test FARENHEIT flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( addr, addr, flags, 0x2e, 0x02, bytes([ 0x01, 0x04, 0x0a, 0x21, 0x05, 0x11, 0x50, 0x1e, 0x00, 0xe0, 0x80, 0x39, 0x0f, 0xde ])) thermo.handle_status(msg, on_done=self.done) assert round(self.cool_sp, 0) == 27 assert round(self.heat_sp, 0) == 14 assert self.ambient, 1 == 22.4 assert thermo.units == Thermo.FARENHEIT # Test cooling w/ hold flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( addr, addr, flags, 0x2e, 0x02, bytes([ 0x01, 0x04, 0x0a, 0x21, 0x05, 0x11, 0x50, 0x1e, 0x00, 0xe0, 0x91, 0x39, 0x0f, 0xde ])) thermo.handle_status(msg, on_done=self.done) assert self.status == Thermo.Status.COOLING assert self.hold is True # Test heating w/ energy flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( addr, addr, flags, 0x2e, 0x02, bytes([ 0x01, 0x04, 0x0a, 0x21, 0x05, 0x11, 0x50, 0x1e, 0x00, 0xe0, 0x86, 0x39, 0x0f, 0xde ])) thermo.handle_status(msg, on_done=self.done) assert self.status == Thermo.Status.HEATING assert self.energy is True # Test bad status response flags = Msg.Flags(Msg.Flags.Type.DIRECT, True) msg = Msg.InpExtended( addr, addr, flags, 0x2e, 0x02, bytes([ 0x01, 0x04, 0x0a, 0x21, 0x05, 0xFF, 0x1b, 0x1e, 0x00, 0xe0, 0x88, 0x0e, 0x0f, 0xde ])) thermo.handle_status(msg, on_done=self.done) # force a bad fan command, currently no way for this to happen # in the code, so just fake it here thermo.set_fan_mode_state(2) assert self.fan == Thermo.Fan.ON # test humidity setpoints, not enabled in code yet so this is just a # shell msg = Msg.OutExtended.direct(addr, 0x2e, 0x00, bytes([0x00] * 2 + [0x01] + [0x00] * 11), crc_type="CRC") thermo.get_humidity_setpoints() assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() thermo.handle_humidity_setpoints(msg) # Test enabling broadcast messages msg = Msg.OutExtended.direct(addr, 0x2e, 0x00, bytes([0x00] + [0x08] + [0x00] * 12)) thermo.enable_broadcast() assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() thermo.handle_generic_ack(msg, on_done=self.done) # test thermo broadcast Messages flags = Msg.Flags(Msg.Flags.Type.ALL_LINK_BROADCAST, False) cool = IM.Address(0x00, 0x00, 0x01) msg = Msg.InpStandard(addr, cool, flags, 0x11, 0x00) thermo.handle_broadcast(msg) assert self.status == Thermo.Status.COOLING msg = Msg.InpStandard(addr, cool, flags, 0x13, 0x00) thermo.handle_broadcast(msg) assert self.status == Thermo.Status.OFF # test of bad group, shouldn't change status cool = IM.Address(0x00, 0x00, 0x07) msg = Msg.InpStandard(addr, cool, flags, 0x11, 0x00) thermo.handle_broadcast(msg) assert self.status == Thermo.Status.OFF # Test non-thermo broadcast cool = IM.Address(0x00, 0x00, 0x01) msg = Msg.InpStandard(addr, cool, flags, 0x20, 0x00) thermo.handle_broadcast(msg) # Test mode command msg = Msg.OutExtended.direct(addr, 0x6b, thermo.ModeCommands(0x04), bytes([0x00] * 14)) thermo.mode_command(thermo.ModeCommands.HEAT) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6b, thermo.ModeCommands.HEAT.value) thermo.handle_mode_command(msg, on_done=self.done) assert self.mode == thermo.ModeCommands.HEAT # Test bad ack msg = Msg.InpStandard(addr, addr, flags, 0x6c, thermo.ModeCommands.HEAT.value) thermo.handle_mode_command(msg, on_done=self.done) assert self.mode == thermo.ModeCommands.HEAT # Test fan command msg = Msg.OutExtended.direct(addr, 0x6b, thermo.FanCommands(0x07), bytes([0x00] * 14)) thermo.fan_command(thermo.FanCommands.ON) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6b, thermo.FanCommands.ON.value) thermo.handle_fan_command(msg, on_done=self.done) assert self.fan == thermo.FanCommands.ON # Test bad ack msg = Msg.InpStandard(addr, addr, flags, 0x6c, thermo.FanCommands.ON.value) thermo.handle_fan_command(msg, on_done=self.done) assert self.fan == thermo.FanCommands.ON # test heat setpoint command CELSIUS thermo.units = thermo.CELSIUS temp = 25 msg = Msg.OutExtended.direct(addr, 0x6d, int(temp * 2), bytes([0x00] * 14)) thermo.heat_sp_command(temp) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() # test response handler flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6d, int(temp * 2)) thermo.handle_heat_sp_command(msg, on_done=self.done) assert self.heat_sp == temp # Test FARENHEIT thermo.units = thermo.FARENHEIT temp_c = 25 temp = (temp_c * 9 / 5) + 32 msg = Msg.OutExtended.direct(addr, 0x6d, int(temp * 2), bytes([0x00] * 14)) thermo.heat_sp_command(temp_c) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() # test response handler flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6d, int(temp * 2)) thermo.handle_heat_sp_command(msg, on_done=self.done) assert self.heat_sp == temp_c # BAd Ack flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6a, int(temp * 2)) thermo.handle_heat_sp_command(msg, on_done=self.done) assert self.heat_sp == temp_c # test cool setpoint command CELSIUS thermo.units = thermo.CELSIUS temp = 25 msg = Msg.OutExtended.direct(addr, 0x6c, int(temp * 2), bytes([0x00] * 14)) thermo.cool_sp_command(temp) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() # test response handler flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6c, int(temp * 2)) thermo.handle_cool_sp_command(msg, on_done=self.done) assert self.cool_sp == temp # Test FARENHEIT thermo.units = thermo.FARENHEIT temp_c = 25 temp = (temp_c * 9 / 5) + 32 msg = Msg.OutExtended.direct(addr, 0x6c, int(temp * 2), bytes([0x00] * 14)) thermo.cool_sp_command(temp_c) assert msg.to_bytes() == protocol.msgs.pop(0).to_bytes() # test response handler flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6c, int(temp * 2)) thermo.handle_cool_sp_command(msg, on_done=self.done) assert self.cool_sp == temp_c # bad ack flags = Msg.Flags(Msg.Flags.Type.DIRECT_ACK, False) msg = Msg.InpStandard(addr, addr, flags, 0x6a, int(temp * 2)) thermo.handle_cool_sp_command(msg, on_done=self.done) assert self.cool_sp == temp_c