From 34e44e7f3a5cb5fb22200f05cbefce5e7bc785a5 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Wed, 18 Mar 2020 21:20:40 +0000 Subject: [PATCH] Add support for homekit valve accessories to homekit_controller (#32937) --- .../components/homekit_controller/const.py | 1 + .../components/homekit_controller/switch.py | 98 +- .../test_rainmachine_pro_8.py | 65 + .../homekit_controller/test_switch.py | 67 +- .../homekit_controller/rainmachine-pro-8.json | 1137 +++++++++++++++++ 5 files changed, 1351 insertions(+), 17 deletions(-) create mode 100644 tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py create mode 100644 tests/fixtures/homekit_controller/rainmachine-pro-8.json diff --git a/homeassistant/components/homekit_controller/const.py b/homeassistant/components/homekit_controller/const.py index f5ae6cbd644..a13ad22df51 100644 --- a/homeassistant/components/homekit_controller/const.py +++ b/homeassistant/components/homekit_controller/const.py @@ -32,4 +32,5 @@ HOMEKIT_ACCESSORY_DISPATCH = { "air-quality": "air_quality", "occupancy": "binary_sensor", "television": "media_player", + "valve": "switch", } diff --git a/homeassistant/components/homekit_controller/switch.py b/homeassistant/components/homekit_controller/switch.py index 5897bbb7b3f..61595b504ca 100644 --- a/homeassistant/components/homekit_controller/switch.py +++ b/homeassistant/components/homekit_controller/switch.py @@ -1,7 +1,11 @@ """Support for Homekit switches.""" import logging -from aiohomekit.model.characteristics import CharacteristicsTypes +from aiohomekit.model.characteristics import ( + CharacteristicsTypes, + InUseValues, + IsConfiguredValues, +) from homeassistant.components.switch import SwitchDevice from homeassistant.core import callback @@ -12,21 +16,9 @@ OUTLET_IN_USE = "outlet_in_use" _LOGGER = logging.getLogger(__name__) - -async def async_setup_entry(hass, config_entry, async_add_entities): - """Set up Homekit lock.""" - hkid = config_entry.data["AccessoryPairingID"] - conn = hass.data[KNOWN_DEVICES][hkid] - - @callback - def async_add_service(aid, service): - if service["stype"] not in ("switch", "outlet"): - return False - info = {"aid": aid, "iid": service["iid"]} - async_add_entities([HomeKitSwitch(conn, info)], True) - return True - - conn.add_listener(async_add_service) +ATTR_IN_USE = "in_use" +ATTR_IS_CONFIGURED = "is_configured" +ATTR_REMAINING_DURATION = "remaining_duration" class HomeKitSwitch(HomeKitEntity, SwitchDevice): @@ -55,3 +47,77 @@ class HomeKitSwitch(HomeKitEntity, SwitchDevice): outlet_in_use = self.service.value(CharacteristicsTypes.OUTLET_IN_USE) if outlet_in_use is not None: return {OUTLET_IN_USE: outlet_in_use} + + +class HomeKitValve(HomeKitEntity, SwitchDevice): + """Represents a valve in an irrigation system.""" + + def get_characteristic_types(self): + """Define the homekit characteristics the entity cares about.""" + return [ + CharacteristicsTypes.ACTIVE, + CharacteristicsTypes.IN_USE, + CharacteristicsTypes.IS_CONFIGURED, + CharacteristicsTypes.REMAINING_DURATION, + ] + + async def async_turn_on(self, **kwargs): + """Turn the specified valve on.""" + await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: True}) + + async def async_turn_off(self, **kwargs): + """Turn the specified valve off.""" + await self.async_put_characteristics({CharacteristicsTypes.ACTIVE: False}) + + @property + def icon(self) -> str: + """Return the icon.""" + return "mdi:water" + + @property + def is_on(self): + """Return true if device is on.""" + return self.service.value(CharacteristicsTypes.ACTIVE) + + @property + def device_state_attributes(self): + """Return the optional state attributes.""" + attrs = {} + + in_use = self.service.value(CharacteristicsTypes.IN_USE) + if in_use is not None: + attrs[ATTR_IN_USE] = in_use == InUseValues.IN_USE + + is_configured = self.service.value(CharacteristicsTypes.IS_CONFIGURED) + if is_configured is not None: + attrs[ATTR_IS_CONFIGURED] = is_configured == IsConfiguredValues.CONFIGURED + + remaining = self.service.value(CharacteristicsTypes.REMAINING_DURATION) + if remaining is not None: + attrs[ATTR_REMAINING_DURATION] = remaining + + return attrs + + +ENTITY_TYPES = { + "switch": HomeKitSwitch, + "outlet": HomeKitSwitch, + "valve": HomeKitValve, +} + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up Homekit switches.""" + hkid = config_entry.data["AccessoryPairingID"] + conn = hass.data[KNOWN_DEVICES][hkid] + + @callback + def async_add_service(aid, service): + entity_class = ENTITY_TYPES.get(service["stype"]) + if not entity_class: + return False + info = {"aid": aid, "iid": service["iid"]} + async_add_entities([entity_class(conn, info)], True) + return True + + conn.add_listener(async_add_service) diff --git a/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py b/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py new file mode 100644 index 00000000000..fd95ef98c09 --- /dev/null +++ b/tests/components/homekit_controller/specific_devices/test_rainmachine_pro_8.py @@ -0,0 +1,65 @@ +""" +Make sure that existing RainMachine support isn't broken. + +https://github.com/home-assistant/core/issues/31745 +""" + +from tests.components.homekit_controller.common import ( + Helper, + setup_accessories_from_file, + setup_test_accessories, +) + + +async def test_rainmachine_pro_8_setup(hass): + """Test that a RainMachine can be correctly setup in HA.""" + accessories = await setup_accessories_from_file(hass, "rainmachine-pro-8.json") + config_entry, pairing = await setup_test_accessories(hass, accessories) + + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + # Assert that the entity is correctly added to the entity registry + entry = entity_registry.async_get("switch.rainmachine_00ce4a") + assert entry.unique_id == "homekit-00aa0000aa0a-512" + + helper = Helper( + hass, "switch.rainmachine_00ce4a", pairing, accessories[0], config_entry + ) + state = await helper.poll_and_get_state() + + # Assert that the friendly name is detected correctly + assert state.attributes["friendly_name"] == "RainMachine-00ce4a" + + device_registry = await hass.helpers.device_registry.async_get_registry() + + device = device_registry.async_get(entry.device_id) + assert device.manufacturer == "Green Electronics LLC" + assert device.name == "RainMachine-00ce4a" + assert device.model == "SPK5 Pro" + assert device.sw_version == "1.0.4" + assert device.via_device_id is None + + # The device is made up of multiple valves - make sure we have enumerated them all + entry = entity_registry.async_get("switch.rainmachine_00ce4a_2") + assert entry.unique_id == "homekit-00aa0000aa0a-768" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_3") + assert entry.unique_id == "homekit-00aa0000aa0a-1024" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_4") + assert entry.unique_id == "homekit-00aa0000aa0a-1280" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_5") + assert entry.unique_id == "homekit-00aa0000aa0a-1536" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_6") + assert entry.unique_id == "homekit-00aa0000aa0a-1792" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_7") + assert entry.unique_id == "homekit-00aa0000aa0a-2048" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_8") + assert entry.unique_id == "homekit-00aa0000aa0a-2304" + + entry = entity_registry.async_get("switch.rainmachine_00ce4a_9") + assert entry is None diff --git a/tests/components/homekit_controller/test_switch.py b/tests/components/homekit_controller/test_switch.py index eb10d42e208..c53d20891b1 100644 --- a/tests/components/homekit_controller/test_switch.py +++ b/tests/components/homekit_controller/test_switch.py @@ -1,6 +1,10 @@ """Basic checks for HomeKitSwitch.""" -from aiohomekit.model.characteristics import CharacteristicsTypes +from aiohomekit.model.characteristics import ( + CharacteristicsTypes, + InUseValues, + IsConfiguredValues, +) from aiohomekit.model.services import ServicesTypes from tests.components.homekit_controller.common import setup_test_component @@ -17,6 +21,23 @@ def create_switch_service(accessory): outlet_in_use.value = False +def create_valve_service(accessory): + """Define valve characteristics.""" + service = accessory.add_service(ServicesTypes.VALVE) + + on_char = service.add_char(CharacteristicsTypes.ACTIVE) + on_char.value = False + + in_use = service.add_char(CharacteristicsTypes.IN_USE) + in_use.value = InUseValues.IN_USE + + configured = service.add_char(CharacteristicsTypes.IS_CONFIGURED) + configured.value = IsConfiguredValues.CONFIGURED + + remaining = service.add_char(CharacteristicsTypes.REMAINING_DURATION) + remaining.value = 99 + + async def test_switch_change_outlet_state(hass, utcnow): """Test that we can turn a HomeKit outlet on and off again.""" helper = await setup_test_component(hass, create_switch_service) @@ -57,3 +78,47 @@ async def test_switch_read_outlet_state(hass, utcnow): switch_1 = await helper.poll_and_get_state() assert switch_1.state == "off" assert switch_1.attributes["outlet_in_use"] is True + + +async def test_valve_change_active_state(hass, utcnow): + """Test that we can turn a valve on and off again.""" + helper = await setup_test_component(hass, create_valve_service) + + await hass.services.async_call( + "switch", "turn_on", {"entity_id": "switch.testdevice"}, blocking=True + ) + assert helper.characteristics[("valve", "active")].value == 1 + + await hass.services.async_call( + "switch", "turn_off", {"entity_id": "switch.testdevice"}, blocking=True + ) + assert helper.characteristics[("valve", "active")].value == 0 + + +async def test_valve_read_state(hass, utcnow): + """Test that we can read the state of a valve accessory.""" + helper = await setup_test_component(hass, create_valve_service) + + # Initial state is that the switch is off and the outlet isn't in use + switch_1 = await helper.poll_and_get_state() + assert switch_1.state == "off" + assert switch_1.attributes["in_use"] is True + assert switch_1.attributes["is_configured"] is True + assert switch_1.attributes["remaining_duration"] == 99 + + # Simulate that someone switched on the device in the real world not via HA + helper.characteristics[("valve", "active")].set_value(True) + switch_1 = await helper.poll_and_get_state() + assert switch_1.state == "on" + + # Simulate that someone configured the device in the real world not via HA + helper.characteristics[ + ("valve", "is-configured") + ].value = IsConfiguredValues.NOT_CONFIGURED + switch_1 = await helper.poll_and_get_state() + assert switch_1.attributes["is_configured"] is False + + # Simulate that someone using the device in the real world not via HA + helper.characteristics[("valve", "in-use")].value = InUseValues.NOT_IN_USE + switch_1 = await helper.poll_and_get_state() + assert switch_1.attributes["in_use"] is False diff --git a/tests/fixtures/homekit_controller/rainmachine-pro-8.json b/tests/fixtures/homekit_controller/rainmachine-pro-8.json new file mode 100644 index 00000000000..1b50063006e --- /dev/null +++ b/tests/fixtures/homekit_controller/rainmachine-pro-8.json @@ -0,0 +1,1137 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 2, + "type": "00000014-0000-1000-8000-0026BB765291", + "format": "bool", + "perms": [ + "pw" + ] + }, + { + "iid": 3, + "type": "00000020-0000-1000-8000-0026BB765291", + "format": "string", + "value": "Green Electronics LLC", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 4, + "type": "00000021-0000-1000-8000-0026BB765291", + "format": "string", + "value": "SPK5 Pro", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 5, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "RainMachine-00ce4a", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 6, + "type": "00000030-0000-1000-8000-0026BB765291", + "format": "string", + "value": "00aa0000aa0a", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 7, + "type": "00000052-0000-1000-8000-0026BB765291", + "format": "string", + "value": "1.0.4", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 8, + "type": "00000053-0000-1000-8000-0026BB765291", + "format": "string", + "value": "1", + "perms": [ + "pr" + ], + "ev": false + }, + { + "iid": 9, + "type": "34AB8811-AC7F-4340-BAC3-FD6A85F9943B", + "format": "string", + "value": "2.0;16A62", + "perms": [ + "pr", + "hd" + ], + "ev": false + } + ] + }, + { + "iid": 16, + "type": "000000A2-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 18, + "type": "00000037-0000-1000-8000-0026BB765291", + "format": "string", + "value": "1.1.0", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 64, + "type": "000000CF-0000-1000-8000-0026BB765291", + "primary": true, + "hidden": false, + "linked": [ + 512, + 768, + 1024, + 1280, + 1536, + 1792, + 2048, + 2304 + ], + "characteristics": [ + { + "iid": 67, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 65, + "type": "000000D1-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 2, + "minStep": 1 + }, + { + "iid": 68, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 66, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "RainMachine", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 512, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 544, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 560, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 576, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 592, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 608, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 624, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 640, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 528, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 768, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 800, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 816, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 832, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 848, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 864, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 880, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 896, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 2, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 784, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 1024, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 1056, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1072, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1088, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 1104, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1120, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1136, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1152, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 3, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 1040, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 1280, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 1312, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1328, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1344, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 1360, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1376, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1392, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1408, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 4, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 1296, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 1536, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 1568, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1584, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1600, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 1616, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1632, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1648, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1664, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 5, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 1552, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 1792, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 1824, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1840, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1856, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 1872, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 1888, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1904, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 1920, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 6, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 1808, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 2048, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 2080, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2096, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2112, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 2128, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2144, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 2160, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 2176, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 7, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 2064, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + }, + { + "iid": 2304, + "type": "000000D0-0000-1000-8000-0026BB765291", + "primary": false, + "hidden": false, + "linked": [], + "characteristics": [ + { + "iid": 2336, + "type": "000000B0-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2352, + "type": "000000D2-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2368, + "type": "000000D5-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 3, + "minStep": 1 + }, + { + "iid": 2384, + "type": "000000D6-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 1, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 1, + "minStep": 1 + }, + { + "iid": 2400, + "type": "000000D4-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 0, + "perms": [ + "pr", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 2416, + "type": "000000D3-0000-1000-8000-0026BB765291", + "format": "uint32", + "value": 300, + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "minValue": 0, + "maxValue": 86400, + "minStep": 1 + }, + { + "iid": 2432, + "type": "000000CB-0000-1000-8000-0026BB765291", + "format": "uint8", + "value": 8, + "perms": [ + "pr" + ], + "ev": false, + "minValue": 1, + "maxValue": 255, + "minStep": 1 + }, + { + "iid": 2320, + "type": "00000023-0000-1000-8000-0026BB765291", + "format": "string", + "value": "", + "perms": [ + "pr" + ], + "ev": false + } + ] + } + ] + } +] \ No newline at end of file