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
This commit is contained in:
Patrick Frazer 2024-08-21 15:56:59 -04:00 committed by GitHub
parent e9798cd1b4
commit 5f53d3f917
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 236 additions and 13 deletions

View file

@ -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],

View file

@ -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"

View file

@ -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,

View file

@ -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" }
}
}
}

View file

@ -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(

View file

@ -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': <ANY>,
'device_class': None,
'device_id': <ANY>,
'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': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.POWER: 'power'>,
'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': <ANY>,
'entity_id': 'binary_sensor.alert_power',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_sensors[alert][binary_sensor.alert_sensor-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'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': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
'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': <ANY>,
'entity_id': 'binary_sensor.alert_sensor',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_sensors[hub][binary_sensor.hub_drop_1_c0ffee_leak_detected-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View file

@ -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': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.alert_battery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '100',
})
# ---
# name: test_sensors[alert][sensor.alert_battery-reset]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery',
'friendly_name': 'Alert Battery',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.alert_battery',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_sensors[alert][sensor.alert_temperature-data]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Alert Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.alert_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '20.1111111111111',
})
# ---
# name: test_sensors[alert][sensor.alert_temperature-reset]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Alert Temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.alert_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '-17.7777777777778',
})
# ---
# name: test_sensors[filter][sensor.filter_battery-data]
StateSnapshot({
'attributes': ReadOnlyDict({

View file

@ -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",

View file

@ -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",