diff --git a/insteon_mqtt/Scenes.py b/insteon_mqtt/Scenes.py index 34a4ba6b..d90d9ef6 100644 --- a/insteon_mqtt/Scenes.py +++ b/insteon_mqtt/Scenes.py @@ -124,7 +124,7 @@ def compress_controllers(self): controllers are merged. This is a companion to compress_responders and compress_n_way. These - are seperate functions to that they can be called seperately using + are seperate functions so that they can be called seperately using Stacks. This function only processes the scenes in a single pass. If it runs @@ -164,7 +164,7 @@ def compress_responders(self): merged. This is a companion to compress_controllers and compress_n_way. - These are seperate functions to that they can be called seperately + These are seperate functions so that they can be called seperately using Stacks. This function only processes the scenes in a single pass. If it runs @@ -205,7 +205,7 @@ def compress_n_way(self): definition.. This is a companion to compress_responders and compress_controllers. - These are seperate functions to that they can be called seperately + These are seperate functions so that they can be called seperately using Stacks. This function only processes the scenes in a single pass. If it runs @@ -522,7 +522,7 @@ def from_link_entry(scene_manager, device, entry): if not found_ctrl: # We know nothing about the controller so set to default values # the link-data may be wrong, but it doesn't seem to matter - if entry.group > 0x01: + if entry.group != 0x01: scene['controllers'].append({entry_addr: entry.group}) else: scene['controllers'].append(entry_addr) @@ -731,16 +731,13 @@ def __eq__(self, other): primarily by the compress_* functions ''' ret = False - self_group = self.group if self.group > 0x00 else 0x01 - other_group = other.group if other.group > 0x00 else 0x01 - if (self.addr == other.addr and self_group == other_group and + if (self.addr == other.addr and self.group == other.group and self.link_data == other.link_data): ret = True return ret def __str__(self): - self_group = self.group if self.group > 0x00 else 0x01 - subs = (self.addr, self_group, self.link_data) + subs = (self.addr, self.group, self.link_data) return 'Dev Addr: %s Group: %s Data1-3: %s' % subs def __hash__(self): @@ -822,20 +819,20 @@ def group(self, value): Args: value: (int)The group value """ - if self.style == 0 and value > 0x01: + if self.style == 0 and value != 0x01: if ('group' not in self._yaml_data[self.label] or self._yaml_data[self.label]['group'] != value): self._yaml_data[self.label]['group'] = value - if self.style == 1 and value > 0x01: + if self.style == 1 and value != 0x01: self._yaml_data[self.label] = value - if self.style == 2 and value > 0x01: + if self.style == 2 and value != 0x01: self._yaml_data = {self.label: value} - # Remove group entry in yaml_data if default value of 0x00 or 0x01 + # Remove group entry in yaml_data if default value of 0x01 if (self.style == 0 and 'group' in self._yaml_data[self.label] and - value <= 0x01): + value == 0x01): del self._yaml_data[self.label]['group'] - elif self.style == 1 and value <= 0x01: + elif self.style == 1 and value == 0x01: self._yaml_data = self.label self.update_device() @@ -891,7 +888,7 @@ def link_data(self): # Group is a bit special and gets added to link_data # a few responders (kpl) need to know group to set data_3 link_dict = self._yaml_data[self.label].copy() - if self.group > 0x01: + if self.group != 0x01: link_dict['group'] = self.group # Convert data values from human readable form pretty_data = self.device.link_data_from_pretty( diff --git a/insteon_mqtt/db/Device.py b/insteon_mqtt/db/Device.py index 445a5c0f..f77780ad 100644 --- a/insteon_mqtt/db/Device.py +++ b/insteon_mqtt/db/Device.py @@ -558,7 +558,8 @@ def diff(self, rhs): delta = DbDiff(self.addr) for entry in self.entries.values(): - rhsEntry = rhs.find(entry.addr, entry.group, entry.is_controller) + rhsEntry = rhs.find(entry.addr, entry.group, entry.is_controller, + entry.data[2]) # RHS is missing this entry or has different data bytes we need # to update. diff --git a/insteon_mqtt/device/Dimmer.py b/insteon_mqtt/device/Dimmer.py index 5287a3fe..7ccad070 100644 --- a/insteon_mqtt/device/Dimmer.py +++ b/insteon_mqtt/device/Dimmer.py @@ -447,10 +447,10 @@ def link_data_from_pretty(self, is_controller, data): if 'data_3' in data: data_3 = data['data_3'] if not is_controller: - if 'ramp' in data: + if 'ramp_rate' in data: data_2 = 0x1f for ramp_key, ramp_value in self.ramp_pretty.items(): - if data['ramp'] >= ramp_value: + if data['ramp_rate'] >= ramp_value: data_2 = ramp_key break if 'on_level' in data: diff --git a/insteon_mqtt/device/FanLinc.py b/insteon_mqtt/device/FanLinc.py index 8a85a7de..1a61d9f6 100644 --- a/insteon_mqtt/device/FanLinc.py +++ b/insteon_mqtt/device/FanLinc.py @@ -498,11 +498,12 @@ def link_data_from_pretty(self, is_controller, data): if not is_controller: if 'group' in data: data_3 = data['group'] - if 'ramp' in data and data['group'] <= 0x01: - data_2 = 0x1f - for ramp_key, ramp_value in Dimmer.ramp_pretty: - if data['ramp'] >= ramp_value: - data_2 = ramp_key + if 'ramp_rate' in data and (data_3 is None or data_3 <= 0x01): + data_2 = 0x1f + for ramp_key, ramp_value in Dimmer.ramp_pretty.items(): + if data['ramp_rate'] >= ramp_value: + data_2 = ramp_key + break if 'on_level' in data: data_1 = int(data['on_level'] * 2.55 + .5) return [data_1, data_2, data_3] diff --git a/insteon_mqtt/device/KeypadLinc.py b/insteon_mqtt/device/KeypadLinc.py index 32e66479..8b5cfdf5 100644 --- a/insteon_mqtt/device/KeypadLinc.py +++ b/insteon_mqtt/device/KeypadLinc.py @@ -636,11 +636,12 @@ def link_data_from_pretty(self, is_controller, data): if 'group' in data: data_3 = data['group'] if not is_controller and self.is_dimmer: - if 'ramp' in data: + if 'ramp_rate' in data: data_2 = 0x1f - for ramp_key, ramp_value in Dimmer.ramp_pretty: - if data['ramp'] >= ramp_value: + for ramp_key, ramp_value in Dimmer.ramp_pretty.items(): + if data['ramp_rate'] >= ramp_value: data_2 = ramp_key + break if 'on_level' in data: data_1 = int(data['on_level'] * 2.55 + .5) return [data_1, data_2, data_3] diff --git a/insteon_mqtt/device/Remote.py b/insteon_mqtt/device/Remote.py index a511fe3b..aa89860c 100644 --- a/insteon_mqtt/device/Remote.py +++ b/insteon_mqtt/device/Remote.py @@ -196,9 +196,8 @@ def link_data(self, is_controller, group, data=None): Returns: bytes[3]: Returns a list of 3 bytes to use as D1,D2,D3. """ - # Most of this is from looking through Misterhouse bug reports. if is_controller: - defaults = [0x03, 0x00, group] + defaults = [0x03, 0x00, 0x00] # Responder data is always link dependent. Since nothing was given, # assume the user wants to turn the device on (0xff). @@ -224,7 +223,7 @@ def link_data_to_pretty(self, is_controller, data): Returns: list[3]: list, containing a dict of the human readable values """ - ret = [{'data_1': data[0]}, {'data_2': data[1]}, {'group': data[2]}] + ret = [{'data_1': data[0]}, {'data_2': data[1]}, {'data_3': data[2]}] return ret #----------------------------------------------------------------------- @@ -251,8 +250,6 @@ def link_data_from_pretty(self, is_controller, data): data_3 = None if 'data_3' in data: data_3 = data['data_3'] - if 'group' in data: - data_3 = data['group'] return [data_1, data_2, data_3] #----------------------------------------------------------------------- diff --git a/tests/test_Scenes.py b/tests/test_Scenes.py index fd24a324..8348b9bf 100644 --- a/tests/test_Scenes.py +++ b/tests/test_Scenes.py @@ -8,9 +8,15 @@ import insteon_mqtt as IM import insteon_mqtt.Scenes as Scenes import insteon_mqtt.Address as Address +import insteon_mqtt.CommandSeq as CommandSeq +import insteon_mqtt.db.Device as Device import insteon_mqtt.db.DeviceEntry as DeviceEntry import insteon_mqtt.db.Modem as ModemDB import insteon_mqtt.device.Base as Base +import insteon_mqtt.device.Dimmer as Dimmer +import insteon_mqtt.device.FanLinc as FanLinc +import insteon_mqtt.device.KeypadLinc as KeypadLinc +import insteon_mqtt.device.Remote as Remote class Test_Scenes: @@ -168,6 +174,488 @@ def test_set_group(self): scenes.entries[0].controllers[0].group = 2 assert scenes.data[0]['controllers'][0]['dev - a1.b1.c1']['group'] == 2 + def test_Dimmer_scenes_same_ramp_rate(self): + modem = MockModem() + dimmer = Dimmer(modem.protocol, modem, Address("11.22.33"), "Dimmer") + modem.devices[str(dimmer.addr)] = dimmer + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 0]}) + scenes.add_or_update(dimmer, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 0]}) + scenes.add_or_update(dimmer, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with a single scene with: + # - 2 controller entries: aa.bb.cc, group 22, group 23 + # - 1 responder entry: 11.22.33, ramp_rate 19 seconds + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 2 + assert len(scenes.data[0]['responders']) == 1 + assert scenes.data[0]['responders'][0]['Dimmer']['ramp_rate'] == 19 + + def test_Dimmer_scenes_different_ramp_rates(self): + modem = MockModem() + dimmer = Dimmer(modem.protocol, modem, Address("11.22.33"), "Dimmer") + modem.devices[str(dimmer.addr)] = dimmer + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 0]}) + scenes.add_or_update(dimmer, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 13, 0]}) + scenes.add_or_update(dimmer, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with 2 scenes: + # - Controller aa.bb.cc, group 22 -> Dimmer w/ 19 second ramp_rate + # - Controller aa.bb.cc, group 33 -> Dimmer w/ 47 second ramp_rate + # (Just checking # of scenes should be adequate for this test.) + assert len(scenes.entries) == 2 + + def test_FanLinc_scenes_same_ramp_rate(self): + modem = MockModem() + fanlinc = FanLinc(modem.protocol, modem, Address("11.22.33"), "FanLinc") + modem.devices[str(fanlinc.addr)] = fanlinc + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(fanlinc, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(fanlinc, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with a single scene with: + # - 2 controller entries: aa.bb.cc, group 22, group 23 + # - 1 responder entry: 11.22.33, ramp_rate 19 seconds + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 2 + assert len(scenes.data[0]['responders']) == 1 + assert scenes.data[0]['responders'][0]['FanLinc']['ramp_rate'] == 19 + + def test_FanLinc_scenes_different_ramp_rates(self): + modem = MockModem() + fanlinc = FanLinc(modem.protocol, modem, Address("11.22.33"), "FanLinc") + modem.devices[str(fanlinc.addr)] = fanlinc + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(fanlinc, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 13, 1]}) + scenes.add_or_update(fanlinc, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with 2 scenes: + # - Controller aa.bb.cc, group 22 -> FanLinc w/ 19 second ramp_rate + # - Controller aa.bb.cc, group 33 -> FanLinc w/ 47 second ramp_rate + # (Just checking # of scenes should be adequate for this test.) + assert len(scenes.entries) == 2 + + def test_KeypadLinc_scenes_same_ramp_rate(self): + modem = MockModem() + keypadlinc = KeypadLinc(modem.protocol, modem, Address("11.22.33"), + "KeypadLinc") + modem.devices[str(keypadlinc.addr)] = keypadlinc + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(keypadlinc, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(keypadlinc, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with a single scene with: + # - 2 controller entries: aa.bb.cc, group 22, group 23 + # - 1 responder entry: 11.22.33, ramp_rate 19 seconds + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 2 + assert len(scenes.data[0]['responders']) == 1 + assert scenes.data[0]['responders'][0]['KeypadLinc']['ramp_rate'] == 19 + + def test_KeypadLinc_scenes_different_ramp_rates(self): + modem = MockModem() + keypadlinc = KeypadLinc(modem.protocol, modem, Address("11.22.33"), + "KeypadLinc") + modem.devices[str(keypadlinc.addr)] = keypadlinc + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'aa.bb.cc': {'group': 22}}], + 'responders': ['11.22.33']}, + {'controllers': [{'aa.bb.cc': {'group': 33}}], + 'responders': ['11.22.33']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}) + scenes.add_or_update(keypadlinc, entry1) + entry2 = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 33, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 13, 1]}) + scenes.add_or_update(keypadlinc, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # We should end up with 2 scenes: + # - Controller aa.bb.cc, group 22 -> KeypadLinc w/ 19 second ramp_rate + # - Controller aa.bb.cc, group 33 -> KeypadLinc w/ 47 second ramp_rate + # (Just checking # of scenes should be adequate for this test.) + assert len(scenes.entries) == 2 + + def test_foreign_hub_group_0(self): + modem = MockModem() + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # We'll build the following via DeviceEntrys: + #scenes.data = [{'controllers': [{'aa.bb.cc': 0}], + # 'responders': ['cc.bb.22', 'cc.bb.aa']}] + scenes._init_scene_entries() + entry = DeviceEntry.from_json({"data": [3, 0, 239], + "mem_loc" : 8119, + "group": 0, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "addr": "aa.bb.cc"}) + device = modem.find("cc.bb.22") + scenes.add_or_update(device, entry) + device = modem.find("cc.bb.aa") + scenes.add_or_update(device, entry) + print(str(scenes.data)) + # Check that group == 0 + assert scenes.entries[0].controllers[0].group == 0 + assert scenes.entries[0].controllers[0].style == 1 + assert scenes.data[0]['controllers'][0]['dev - aa.bb.cc'] == 0 + + def test_foreign_hub_set_group_0(self): + modem = MockModem() + scenes = Scenes.SceneManager(modem, None) + scenes.data = [{'controllers': [{'a1.b1.c1': {'data_1': 0}}], + 'responders': ['cc.bb.22'], + 'name': 'test'}] + scenes._init_scene_entries() + scenes.entries[0].controllers[0].group = 0 + print(str(scenes.data)) + assert scenes.data[0]['controllers'][0]['dev - a1.b1.c1']['group'] == 0 + + def test_foreign_hub_group_0_and_1(self): + modem = MockModem() + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # We'll build the following via DeviceEntrys: + #scenes.data = [{'controllers': [{'aa.bb.cc': 0}, 'aa.bb.cc'], + # 'responders': ['cc.bb.aa']}] + scenes._init_scene_entries() + entry1 = DeviceEntry.from_json({"data": [3, 0, 239], + "mem_loc" : 8119, + "group": 1, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "addr": "aa.bb.cc"}) + device = modem.find("cc.bb.aa") + scenes.add_or_update(device, entry1) + entry2 = DeviceEntry.from_json({"data": [3, 0, 239], + "mem_loc" : 8119, + "group": 0, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "addr": "aa.bb.cc"}) + device = modem.find("cc.bb.aa") + scenes.add_or_update(device, entry2) + scenes.compress_controllers() + print(str(scenes.data)) + # Check that we have two controller entries & 1 responder + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 2 + assert len(scenes.data[0]['responders']) == 1 + + def test_mini_remote_button_config_no_data3(self): + modem = MockModem() + remote = Remote(modem.protocol, modem, Address("11.22.33"), "Remote", 4) + modem.devices[str(remote.addr)] = remote + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # We'll build the following via DeviceEntrys: + #scenes.data = [{'controllers': [{'11.22.33': 2}], + # 'responders': ['aa.bb.cc']}] + scenes._init_scene_entries() + # The following data values are taken from an actual Mini Remote + entry = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 2, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": True}, + "data": [3, 0, 0]}) + scenes.add_or_update(remote, entry) + print(str(scenes.data)) + # We should end up with a single scene with: + # - 1 controller entry: 11.22.33, group 2 (no data_3 value) + # - 1 responder entry: aa.bb.cc + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 1 + assert len(scenes.data[0]['responders']) == 1 + assert scenes.entries[0].controllers[0].group == 2 + assert scenes.entries[0].controllers[0].link_data == [3, 0, 0] + assert scenes.entries[0].controllers[0].style == 1 + + def test_mini_remote_button_config_with_data3(self): + modem = MockModem() + remote = Remote(modem.protocol, modem, Address("11.22.33"), "Remote", 4) + modem.devices[str(remote.addr)] = remote + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # We'll build the following via DeviceEntrys: + #scenes.data = [{'controllers': [{'11.22.33': {group: 2, data_3: 2}], + # 'responders': ['aa.bb.cc']}] + scenes._init_scene_entries() + # Preserve data_3 values if present + entry = DeviceEntry.from_json({"addr": "aa.bb.cc", + "group": 2, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": True}, + "data": [3, 0, 2]}) + scenes.add_or_update(remote, entry) + print(str(scenes.data)) + # We should end up with a single scene with: + # - 1 controller entry: 11.22.33, group 2, data_3 = 2 + # - 1 responder entry: aa.bb.cc + assert len(scenes.entries) == 1 + assert len(scenes.data[0]['controllers']) == 1 + assert len(scenes.data[0]['responders']) == 1 + assert scenes.entries[0].controllers[0].group == 2 + assert scenes.entries[0].controllers[0].link_data == [3, 0, 2] + assert scenes.entries[0].controllers[0].style == 0 + assert scenes.data[0]['controllers'][0]['Remote']['group'] == 2 + assert scenes.data[0]['controllers'][0]['Remote']['data_3'] == 2 + + def test_foreign_hub_keypad_button_backlights_scene(self): + modem = MockModem() + keypad = KeypadLinc(modem.protocol, modem, Address("11.22.33"), + "Keypad") + modem.devices[str(keypad.addr)] = keypad + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # Define multiple KeypadLinc scenes and matching DB entries + scenes.data = [ + {'controllers': [{'aa.bb.cc': 19}], + 'responders': [{'11.22.33': 3}, + {'11.22.33': {'group': 4, 'on_level': 0.0}}, + {'11.22.33': {'group': 5, 'on_level': 0.0}}, + {'11.22.33': {'group': 6, 'on_level': 0.0}}]}] + keypad_db = Device.from_json( + { "address": "11.22.33", + "delta": 0, + "engine": None, + "dev_cat": 1, + "sub_cat": 66, + "firmware": 69, + "used":[ + {"addr": "aa.bb.cc", + "group": 19, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 0x1f, 3]}, + {"addr": "aa.bb.cc", + "group": 19, + "mem_loc" : 8219, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [0, 0x1f, 4]}, + {"addr": "aa.bb.cc", + "group": 19, + "mem_loc" : 8319, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [0, 0x1f, 5]}, + {"addr": "aa.bb.cc", + "group": 19, + "mem_loc" : 8419, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [0, 0x1f, 6]}], + "unused": [], + "last": {"addr": "00.00.00", + "group": 0, + "mem_loc": 8519, + "db_flags": {"is_last_rec": True, + "in_use": False, + "is_controller": False}, + "data": [0, 0, 0]}, + "meta": {} }, None, keypad) + keypad.db = keypad_db + scenes._init_scene_entries() + scenes.populate_scenes() + print(str(scenes.data)) + # Compute if any DB changes needed to implement scenes + seq = CommandSeq(modem.protocol, "Sync complete") + keypad.sync(dry_run=True, refresh=False, sequence=seq) + # Uncomment the next two lines to see what sequence would do: + #IM.log.initialize() + #seq.run() + # No changes to DB should be needed + assert len(seq.calls) == 0 + + def test_fanlinc_dimmer_ramp_rate_scene(self): + modem = MockModem() + fanlinc = FanLinc(modem.protocol, modem, Address("11.22.33"), "FanLinc") + modem.devices[str(fanlinc.addr)] = fanlinc + device = modem.find(Address("aa.bb.cc")) + modem.devices[device.label] = device + scenes = Scenes.SceneManager(modem, None) + # Define a FanLinc scene with ramp rate and a matching DB entry + scenes.data = [ + {'controllers': [{'aa.bb.cc': 22}], + 'responders': [{'11.22.33': {'ramp_rate': 19, 'group': 1}}]}] + fanlinc_db = Device.from_json( + { "address": "11.22.33", + "delta": 0, + "engine": None, + "dev_cat": 1, + "sub_cat": 46, + "firmware": 69, + "used":[ + {"addr": "aa.bb.cc", + "group": 22, + "mem_loc" : 8119, + "db_flags": {"is_last_rec": False, + "in_use": True, + "is_controller": False}, + "data": [255, 23, 1]}], + "unused": [], + "last": {"addr": "00.00.00", + "group": 0, + "mem_loc": 8519, + "db_flags": {"is_last_rec": True, + "in_use": False, + "is_controller": False}, + "data": [0, 0, 0]}, + "meta": {} }, None, fanlinc) + fanlinc.db = fanlinc_db + scenes._init_scene_entries() + scenes.populate_scenes() + print(str(scenes.data)) + # Make sure link data matches scene config & DB entry: + assert scenes.entries[0].responders[0].link_data == [255, 23, 1] + # Compute if any DB changes needed to implement scenes + seq = CommandSeq(modem.protocol, "Sync complete") + fanlinc.sync(dry_run=True, refresh=False, sequence=seq) + # Uncomment the next two lines to see what sequence would do: + #IM.log.initialize() + #seq.run() + # No changes to DB should be needed + assert len(seq.calls) == 0 + class MockModem(): def __init__(self): self.save_path = ''