From 5f53d3f917d985eb6ad4ca01300c43ccfa512ed2 Mon Sep 17 00:00:00 2001 From: Patrick Frazer Date: Wed, 21 Aug 2024 15:56:59 -0400 Subject: [PATCH] Add DROP Alert product support (#117867) * Add DROP Alert product support * Add DROP Alert to sensor selftest * Fix Alert sensor naming ambiguity * Reorder a constant * Alphabetize strings * Remove unnecessary translation key --- .../components/drop_connect/binary_sensor.py | 16 ++++ .../components/drop_connect/const.py | 1 + .../components/drop_connect/sensor.py | 2 + .../components/drop_connect/strings.json | 27 +++--- tests/components/drop_connect/common.py | 23 +++++ .../snapshots/test_binary_sensor.ambr | 94 +++++++++++++++++++ .../drop_connect/snapshots/test_sensor.ambr | 64 +++++++++++++ .../drop_connect/test_binary_sensor.py | 11 +++ tests/components/drop_connect/test_sensor.py | 11 +++ 9 files changed, 236 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/drop_connect/binary_sensor.py b/homeassistant/components/drop_connect/binary_sensor.py index 73e0e254607..093c5bcbb8e 100644 --- a/homeassistant/components/drop_connect/binary_sensor.py +++ b/homeassistant/components/drop_connect/binary_sensor.py @@ -17,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ( CONF_DEVICE_TYPE, + DEV_ALERT, DEV_HUB, DEV_LEAK_DETECTOR, DEV_PROTECTION_VALVE, @@ -33,8 +34,10 @@ _LOGGER = logging.getLogger(__name__) # Binary sensor type constants +ALERT_SENSOR = "alert_sensor" LEAK_DETECTED = "leak" PENDING_NOTIFICATION = "pending_notification" +POWER = "power" PUMP_STATUS = "pump" RESERVE_IN_USE = "reserve_in_use" SALT_LOW = "salt" @@ -74,10 +77,23 @@ BINARY_SENSORS: list[DROPBinarySensorEntityDescription] = [ translation_key=PUMP_STATUS, value_fn=lambda device: device.drop_api.pump_status(), ), + DROPBinarySensorEntityDescription( + key=ALERT_SENSOR, + translation_key=ALERT_SENSOR, + device_class=BinarySensorDeviceClass.PROBLEM, + value_fn=lambda device: device.drop_api.sensor_high(), + ), + DROPBinarySensorEntityDescription( + key=POWER, + translation_key=None, # Use name provided by binary sensor device class + device_class=BinarySensorDeviceClass.POWER, + value_fn=lambda device: device.drop_api.power(), + ), ] # Defines which binary sensors are used by each device type DEVICE_BINARY_SENSORS: dict[str, list[str]] = { + DEV_ALERT: [ALERT_SENSOR, POWER], DEV_HUB: [LEAK_DETECTED, PENDING_NOTIFICATION], DEV_LEAK_DETECTOR: [LEAK_DETECTED], DEV_PROTECTION_VALVE: [LEAK_DETECTED], diff --git a/homeassistant/components/drop_connect/const.py b/homeassistant/components/drop_connect/const.py index 38a8a57ea72..f1012f9652c 100644 --- a/homeassistant/components/drop_connect/const.py +++ b/homeassistant/components/drop_connect/const.py @@ -11,6 +11,7 @@ CONF_DEVICE_NAME = "name" CONF_DEVICE_OWNER_ID = "drop_device_owner_id" # Values for DROP device types +DEV_ALERT = "alrt" DEV_FILTER = "filt" DEV_HUB = "hub" DEV_LEAK_DETECTOR = "leak" diff --git a/homeassistant/components/drop_connect/sensor.py b/homeassistant/components/drop_connect/sensor.py index 0806737254e..ad123ee13c7 100644 --- a/homeassistant/components/drop_connect/sensor.py +++ b/homeassistant/components/drop_connect/sensor.py @@ -27,6 +27,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ( CONF_DEVICE_TYPE, + DEV_ALERT, DEV_FILTER, DEV_HUB, DEV_LEAK_DETECTOR, @@ -222,6 +223,7 @@ DEVICE_SENSORS: dict[str, list[str]] = { ], DEV_FILTER: [BATTERY, CURRENT_FLOW_RATE, CURRENT_SYSTEM_PRESSURE], DEV_LEAK_DETECTOR: [BATTERY, TEMPERATURE], + DEV_ALERT: [BATTERY, TEMPERATURE], DEV_PROTECTION_VALVE: [ BATTERY, CURRENT_FLOW_RATE, diff --git a/homeassistant/components/drop_connect/strings.json b/homeassistant/components/drop_connect/strings.json index 761d134bd18..93df4dc3310 100644 --- a/homeassistant/components/drop_connect/strings.json +++ b/homeassistant/components/drop_connect/strings.json @@ -12,26 +12,27 @@ }, "entity": { "sensor": { - "current_flow_rate": { "name": "Water flow rate" }, - "peak_flow_rate": { "name": "Peak water flow rate today" }, - "water_used_today": { "name": "Total water used today" }, "average_water_used": { "name": "Average daily water usage" }, "capacity_remaining": { "name": "Capacity remaining" }, - "current_system_pressure": { "name": "Current water pressure" }, - "high_system_pressure": { "name": "High water pressure today" }, - "low_system_pressure": { "name": "Low water pressure today" }, - "inlet_tds": { "name": "Inlet TDS" }, - "outlet_tds": { "name": "Outlet TDS" }, "cart1": { "name": "Cartridge 1 life remaining" }, "cart2": { "name": "Cartridge 2 life remaining" }, - "cart3": { "name": "Cartridge 3 life remaining" } + "cart3": { "name": "Cartridge 3 life remaining" }, + "current_flow_rate": { "name": "Water flow rate" }, + "current_system_pressure": { "name": "Current water pressure" }, + "high_system_pressure": { "name": "High water pressure today" }, + "inlet_tds": { "name": "Inlet TDS" }, + "low_system_pressure": { "name": "Low water pressure today" }, + "outlet_tds": { "name": "Outlet TDS" }, + "peak_flow_rate": { "name": "Peak water flow rate today" }, + "water_used_today": { "name": "Total water used today" } }, "binary_sensor": { + "alert_sensor": { "name": "Sensor" }, "leak": { "name": "Leak detected" }, "pending_notification": { "name": "Notification unread" }, + "pump": { "name": "Pump status" }, "reserve_in_use": { "name": "Reserve capacity in use" }, - "salt": { "name": "Salt low" }, - "pump": { "name": "Pump status" } + "salt": { "name": "Salt low" } }, "select": { "protect_mode": { @@ -44,8 +45,8 @@ } }, "switch": { - "water": { "name": "Water supply" }, - "bypass": { "name": "Treatment bypass" } + "bypass": { "name": "Treatment bypass" }, + "water": { "name": "Water supply" } } } } diff --git a/tests/components/drop_connect/common.py b/tests/components/drop_connect/common.py index bdba79bbd95..9eb76f57dad 100644 --- a/tests/components/drop_connect/common.py +++ b/tests/components/drop_connect/common.py @@ -34,6 +34,10 @@ TEST_DATA_SALT_TOPIC = "drop_connect/DROP-1_C0FFEE/8" TEST_DATA_SALT = '{"salt":1}' TEST_DATA_SALT_RESET = '{"salt":0}' +TEST_DATA_ALERT_TOPIC = "drop_connect/DROP-1_C0FFEE/81" +TEST_DATA_ALERT = '{"battery":100,"sens":1,"pwrOff":0,"temp":68.2}' +TEST_DATA_ALERT_RESET = '{"battery":0,"sens":0,"pwrOff":1,"temp":0}' + TEST_DATA_LEAK_TOPIC = "drop_connect/DROP-1_C0FFEE/20" TEST_DATA_LEAK = '{"battery":100,"leak":1,"temp":68.2}' TEST_DATA_LEAK_RESET = '{"battery":0,"leak":0,"temp":0}' @@ -109,6 +113,25 @@ def config_entry_salt() -> ConfigEntry: ) +def config_entry_alert() -> ConfigEntry: + """Config entry version 1 fixture.""" + return MockConfigEntry( + domain=DOMAIN, + unique_id="DROP-1_C0FFEE_81", + data={ + CONF_COMMAND_TOPIC: "drop_connect/DROP-1_C0FFEE/81/cmd", + CONF_DATA_TOPIC: "drop_connect/DROP-1_C0FFEE/81/#", + CONF_DEVICE_DESC: "Alert", + CONF_DEVICE_ID: 81, + CONF_DEVICE_NAME: "Alert", + CONF_DEVICE_TYPE: "alrt", + CONF_HUB_ID: "DROP-1_C0FFEE", + CONF_DEVICE_OWNER_ID: "DROP-1_C0FFEE_255", + }, + version=1, + ) + + def config_entry_leak() -> ConfigEntry: """Config entry version 1 fixture.""" return MockConfigEntry( diff --git a/tests/components/drop_connect/snapshots/test_binary_sensor.ambr b/tests/components/drop_connect/snapshots/test_binary_sensor.ambr index c42cdb8cde1..9b0cc201573 100644 --- a/tests/components/drop_connect/snapshots/test_binary_sensor.ambr +++ b/tests/components/drop_connect/snapshots/test_binary_sensor.ambr @@ -1,4 +1,98 @@ # serializer version: 1 +# name: test_sensors[alert][binary_sensor.alert_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.alert_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Power', + 'platform': 'drop_connect', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'DROP-1_C0FFEE_81_power', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[alert][binary_sensor.alert_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Alert Power', + }), + 'context': , + 'entity_id': 'binary_sensor.alert_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_sensors[alert][binary_sensor.alert_sensor-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.alert_sensor', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Sensor', + 'platform': 'drop_connect', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'alert_sensor', + 'unique_id': 'DROP-1_C0FFEE_81_alert_sensor', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[alert][binary_sensor.alert_sensor-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'problem', + 'friendly_name': 'Alert Sensor', + }), + 'context': , + 'entity_id': 'binary_sensor.alert_sensor', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_sensors[hub][binary_sensor.hub_drop_1_c0ffee_leak_detected-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/drop_connect/snapshots/test_sensor.ambr b/tests/components/drop_connect/snapshots/test_sensor.ambr index 54e3259e455..a5c91dbe3e4 100644 --- a/tests/components/drop_connect/snapshots/test_sensor.ambr +++ b/tests/components/drop_connect/snapshots/test_sensor.ambr @@ -1,4 +1,68 @@ # serializer version: 1 +# name: test_sensors[alert][sensor.alert_battery-data] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Alert Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.alert_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_sensors[alert][sensor.alert_battery-reset] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Alert Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.alert_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensors[alert][sensor.alert_temperature-data] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Alert Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.alert_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '20.1111111111111', + }) +# --- +# name: test_sensors[alert][sensor.alert_temperature-reset] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Alert Temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.alert_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '-17.7777777777778', + }) +# --- # name: test_sensors[filter][sensor.filter_battery-data] StateSnapshot({ 'attributes': ReadOnlyDict({ diff --git a/tests/components/drop_connect/test_binary_sensor.py b/tests/components/drop_connect/test_binary_sensor.py index 895921291ef..ab89e05d809 100644 --- a/tests/components/drop_connect/test_binary_sensor.py +++ b/tests/components/drop_connect/test_binary_sensor.py @@ -10,6 +10,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from .common import ( + TEST_DATA_ALERT, + TEST_DATA_ALERT_RESET, + TEST_DATA_ALERT_TOPIC, TEST_DATA_HUB, TEST_DATA_HUB_RESET, TEST_DATA_HUB_TOPIC, @@ -28,6 +31,7 @@ from .common import ( TEST_DATA_SOFTENER, TEST_DATA_SOFTENER_RESET, TEST_DATA_SOFTENER_TOPIC, + config_entry_alert, config_entry_hub, config_entry_leak, config_entry_protection_valve, @@ -44,6 +48,12 @@ from tests.typing import MqttMockHAClient ("config_entry", "topic", "reset", "data"), [ (config_entry_hub(), TEST_DATA_HUB_TOPIC, TEST_DATA_HUB_RESET, TEST_DATA_HUB), + ( + config_entry_alert(), + TEST_DATA_ALERT_TOPIC, + TEST_DATA_ALERT_RESET, + TEST_DATA_ALERT, + ), ( config_entry_leak(), TEST_DATA_LEAK_TOPIC, @@ -77,6 +87,7 @@ from tests.typing import MqttMockHAClient ], ids=[ "hub", + "alert", "leak", "softener", "protection_valve", diff --git a/tests/components/drop_connect/test_sensor.py b/tests/components/drop_connect/test_sensor.py index cb56522a09d..c33f0aefe37 100644 --- a/tests/components/drop_connect/test_sensor.py +++ b/tests/components/drop_connect/test_sensor.py @@ -11,6 +11,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er from .common import ( + TEST_DATA_ALERT, + TEST_DATA_ALERT_RESET, + TEST_DATA_ALERT_TOPIC, TEST_DATA_FILTER, TEST_DATA_FILTER_RESET, TEST_DATA_FILTER_TOPIC, @@ -32,6 +35,7 @@ from .common import ( TEST_DATA_SOFTENER, TEST_DATA_SOFTENER_RESET, TEST_DATA_SOFTENER_TOPIC, + config_entry_alert, config_entry_filter, config_entry_hub, config_entry_leak, @@ -57,6 +61,12 @@ def only_sensor_platform() -> Generator[None]: ("config_entry", "topic", "reset", "data"), [ (config_entry_hub(), TEST_DATA_HUB_TOPIC, TEST_DATA_HUB_RESET, TEST_DATA_HUB), + ( + config_entry_alert(), + TEST_DATA_ALERT_TOPIC, + TEST_DATA_ALERT_RESET, + TEST_DATA_ALERT, + ), ( config_entry_leak(), TEST_DATA_LEAK_TOPIC, @@ -96,6 +106,7 @@ def only_sensor_platform() -> Generator[None]: ], ids=[ "hub", + "alert", "leak", "softener", "filter",