From df6fa43bff4ee00499bedf5a0a48cd802f55f253 Mon Sep 17 00:00:00 2001 From: Ed Coen Date: Thu, 23 Dec 2021 13:05:36 -0600 Subject: [PATCH] Add connectsense to homekit_controller (#62675) --- .../components/homekit_controller/const.py | 4 + .../components/homekit_controller/sensor.py | 30 ++ .../fixtures/connectsense.json | 476 ++++++++++++++++++ .../specific_devices/test_connectsense.py | 89 ++++ 4 files changed, 599 insertions(+) create mode 100644 tests/components/homekit_controller/fixtures/connectsense.json create mode 100644 tests/components/homekit_controller/specific_devices/test_connectsense.py diff --git a/homeassistant/components/homekit_controller/const.py b/homeassistant/components/homekit_controller/const.py index 7fab8222ae2..271834f2e92 100644 --- a/homeassistant/components/homekit_controller/const.py +++ b/homeassistant/components/homekit_controller/const.py @@ -47,6 +47,10 @@ HOMEKIT_ACCESSORY_DISPATCH = { } CHARACTERISTIC_PLATFORMS = { + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_WATT: "sensor", + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS: "sensor", + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS_20: "sensor", + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_KW_HOUR: "sensor", CharacteristicsTypes.Vendor.AQARA_GATEWAY_VOLUME: "number", CharacteristicsTypes.Vendor.AQARA_E1_GATEWAY_VOLUME: "number", CharacteristicsTypes.Vendor.AQARA_PAIRING_MODE: "switch", diff --git a/homeassistant/components/homekit_controller/sensor.py b/homeassistant/components/homekit_controller/sensor.py index a12858542b9..0ee74525dce 100644 --- a/homeassistant/components/homekit_controller/sensor.py +++ b/homeassistant/components/homekit_controller/sensor.py @@ -16,6 +16,8 @@ from homeassistant.components.sensor import ( from homeassistant.const import ( CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_PARTS_PER_MILLION, + ELECTRIC_CURRENT_AMPERE, + ENERGY_KILO_WATT_HOUR, LIGHT_LUX, PERCENTAGE, POWER_WATT, @@ -37,6 +39,34 @@ class HomeKitSensorEntityDescription(SensorEntityDescription): SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = { + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_WATT: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_WATT, + name="Real Time Energy", + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=POWER_WATT, + ), + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS, + name="Real Time Current", + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=ELECTRIC_CURRENT_AMPERE, + ), + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS_20: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_AMPS_20, + name="Real Time Current", + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=ELECTRIC_CURRENT_AMPERE, + ), + CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_KW_HOUR: HomeKitSensorEntityDescription( + key=CharacteristicsTypes.Vendor.CONNECTSENSE_ENERGY_KW_HOUR, + name="Energy kWh", + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + ), CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: HomeKitSensorEntityDescription( key=CharacteristicsTypes.Vendor.EVE_ENERGY_WATT, name="Real Time Energy", diff --git a/tests/components/homekit_controller/fixtures/connectsense.json b/tests/components/homekit_controller/fixtures/connectsense.json new file mode 100644 index 00000000000..a2ea1c17cb0 --- /dev/null +++ b/tests/components/homekit_controller/fixtures/connectsense.json @@ -0,0 +1,476 @@ +[ + { + "aid": 1, + "services": [ + { + "iid": 1, + "type": "0000003E-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "iid": 2, + "type": "00000014-0000-1000-8000-0026BB765291", + "perms": [ + "pw" + ], + "ev": false, + "format": "bool" + }, + { + "iid": 3, + "value": "ConnectSense", + "type": "00000020-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 4, + "value": "CS-IWO", + "type": "00000021-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 5, + "value": "InWall Outlet-0394DE", + "type": "00000023-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 6, + "value": "1020301376", + "type": "00000030-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 7, + "value": "1.0.0", + "type": "00000052-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + } + ] + }, + { + "iid": 8, + "type": "000000A2-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "iid": 9, + "value": "1.1.0", + "type": "00000037-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + } + ] + }, + { + "iid": 10, + "type": "B3BD50B1-B30B-4974-A71F-5C68AA126698", + "hidden": true, + "characteristics": [ + { + "iid": 11, + "value": 100, + "type": "00000008-0000-1000-8000-0026BB765291", + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": false, + "format": "int", + "minValue": 0, + "maxValue": 100, + "minStep": 1, + "unit": "percentage" + }, + { + "iid": 12, + "value": 7250712, + "type": "00000005-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint32", + "description": "Epoch", + "unit": "seconds" + } + ] + }, + { + "iid": 13, + "type": "00000047-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "iid": 14, + "value": true, + "type": "00000025-0000-1000-8000-0026BB765291", + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": true, + "format": "bool" + }, + { + "iid": 15, + "value": true, + "type": "00000026-0000-1000-8000-0026BB765291", + "perms": [ + "pr", + "ev" + ], + "ev": true, + "format": "bool" + }, + { + "iid": 16, + "value": "Outlet A", + "type": "00000023-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 17, + "value": 126.3, + "type": "00000008-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 130.0, + "minStep": 0.1, + "description": "Volts" + }, + { + "iid": 18, + "value": 0.03, + "type": "00000009-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 20.0, + "minStep": 0.1, + "description": "Amps" + }, + { + "iid": 19, + "value": 0.8, + "type": "0000000A-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "description": "Watts" + }, + { + "iid": 20, + "value": 379.69299, + "type": "0000000C-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 34028234663852885981170418348, + "minStep": 0.1, + "description": "Kilowatt-hours" + }, + { + "iid": 21, + "value": 22, + "type": "0000000B-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "int", + "minValue": 0, + "maxValue": 100, + "minStep": 1, + "description": "Power factor" + }, + { + "iid": 22, + "value": 390, + "type": "00000005-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint32", + "description": "State timer", + "unit": "seconds" + }, + { + "iid": 23, + "value": "Outlet A", + "type": "0000000E-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "string", + "description": "Assigned name" + }, + { + "iid": 24, + "value": 0, + "type": "0000000F-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint32", + "description": "Device type" + } + ] + }, + { + "iid": 25, + "type": "00000047-0000-1000-8000-0026BB765291", + "characteristics": [ + { + "iid": 26, + "value": true, + "type": "00000025-0000-1000-8000-0026BB765291", + "perms": [ + "pr", + "pw", + "ev" + ], + "ev": true, + "format": "bool" + }, + { + "iid": 27, + "value": true, + "type": "00000026-0000-1000-8000-0026BB765291", + "perms": [ + "pr", + "ev" + ], + "ev": true, + "format": "bool" + }, + { + "iid": 28, + "value": "Outlet B", + "type": "00000023-0000-1000-8000-0026BB765291", + "perms": [ + "pr" + ], + "ev": false, + "format": "string" + }, + { + "iid": 29, + "value": 126.3, + "type": "00000008-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 130.0, + "minStep": 0.1, + "description": "Volts" + }, + { + "iid": 30, + "value": 0.05, + "type": "00000009-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 20.0, + "minStep": 0.1, + "description": "Amps" + }, + { + "iid": 31, + "value": 0.8, + "type": "0000000A-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "description": "Watts" + }, + { + "iid": 32, + "value": 175.85001, + "type": "0000000C-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "float", + "minValue": 0.0, + "maxValue": 34028234663852885981170418348, + "minStep": 0.1, + "description": "Kilowatt-hours" + }, + { + "iid": 33, + "value": 13, + "type": "0000000B-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "int", + "minValue": 0, + "maxValue": 100, + "minStep": 1, + "description": "Power factor" + }, + { + "iid": 34, + "value": 390, + "type": "00000005-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint32", + "description": "State timer", + "unit": "seconds" + }, + { + "iid": 35, + "value": "Outlet B", + "type": "0000000E-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "string", + "description": "Assigned name" + }, + { + "iid": 36, + "value": 0, + "type": "0000000F-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint32", + "description": "Device type" + } + ] + }, + { + "iid": 37, + "type": "00000020-0000-1000-8000-001D4B474349", + "hidden": true, + "characteristics": [ + { + "iid": 38, + "value": 0, + "type": "00000021-0000-1000-8000-001D4B474349", + "perms": [ + "pr", + "ev" + ], + "ev": false, + "format": "uint8" + }, + { + "iid": 39, + "type": "00000022-0000-1000-8000-001D4B474349", + "perms": [ + "pw" + ], + "ev": false, + "format": "uint8" + }, + { + "iid": 40, + "type": "00000023-0000-1000-8000-001D4B474349", + "perms": [ + "pw" + ], + "ev": false, + "format": "string", + "maxLen": 256 + }, + { + "iid": 41, + "type": "00000024-0000-1000-8000-001D4B474349", + "perms": [ + "pw" + ], + "ev": false, + "format": "bool" + }, + { + "iid": 42, + "type": "00000300-0000-1000-8000-001D4B474349", + "perms": [ + "pw" + ], + "ev": false, + "format": "string", + "maxLen": 65 + } + ] + } + ] + } +] diff --git a/tests/components/homekit_controller/specific_devices/test_connectsense.py b/tests/components/homekit_controller/specific_devices/test_connectsense.py new file mode 100644 index 00000000000..29559118fe6 --- /dev/null +++ b/tests/components/homekit_controller/specific_devices/test_connectsense.py @@ -0,0 +1,89 @@ +"""Make sure that ConnectSense Smart Outlet2 / In-Wall Outlet is enumerated properly.""" + +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from tests.components.homekit_controller.common import ( + Helper, + setup_accessories_from_file, + setup_test_accessories, +) + + +async def test_connectsense_setup(hass): + """Test that the accessory can be correctly setup in HA.""" + accessories = await setup_accessories_from_file(hass, "connectsense.json") + config_entry, pairing = await setup_test_accessories(hass, accessories) + + entity_registry = er.async_get(hass) + device_registry = dr.async_get(hass) + + entities = [ + ( + "sensor.inwall_outlet_0394de_real_time_current", + "homekit-1020301376-aid:1-sid:13-cid:18", + "InWall Outlet-0394DE - Real Time Current", + ), + ( + "sensor.inwall_outlet_0394de_real_time_energy", + "homekit-1020301376-aid:1-sid:13-cid:19", + "InWall Outlet-0394DE - Real Time Energy", + ), + ( + "sensor.inwall_outlet_0394de_energy_kwh", + "homekit-1020301376-aid:1-sid:13-cid:20", + "InWall Outlet-0394DE - Energy kWh", + ), + ( + "switch.inwall_outlet_0394de", + "homekit-1020301376-13", + "InWall Outlet-0394DE", + ), + ( + "sensor.inwall_outlet_0394de_real_time_current_2", + "homekit-1020301376-aid:1-sid:25-cid:30", + "InWall Outlet-0394DE - Real Time Current", + ), + ( + "sensor.inwall_outlet_0394de_real_time_energy_2", + "homekit-1020301376-aid:1-sid:25-cid:31", + "InWall Outlet-0394DE - Real Time Energy", + ), + ( + "sensor.inwall_outlet_0394de_energy_kwh_2", + "homekit-1020301376-aid:1-sid:25-cid:32", + "InWall Outlet-0394DE - Energy kWh", + ), + ( + "switch.inwall_outlet_0394de_2", + "homekit-1020301376-25", + "InWall Outlet-0394DE", + ), + ] + + device_ids = set() + + for (entity_id, unique_id, friendly_name) in entities: + entry = entity_registry.async_get(entity_id) + assert entry.unique_id == unique_id + + helper = Helper( + hass, + entity_id, + pairing, + accessories[0], + config_entry, + ) + state = await helper.poll_and_get_state() + assert state.attributes["friendly_name"] == friendly_name + + device = device_registry.async_get(entry.device_id) + assert device.manufacturer == "ConnectSense" + assert device.name == "InWall Outlet-0394DE" + assert device.model == "CS-IWO" + assert device.sw_version == "1.0.0" + assert device.via_device_id is None + + device_ids.add(entry.device_id) + + # All entities should be part of same device + assert len(device_ids) == 1