Add support for Flo "pucks" (#47074)
So far the Flo integration only supports shutoff valves. Add support for Flo leak detector pucks, which measure temperature and humidity in addition to providing leak alerts.
This commit is contained in:
parent
d37fb7d88d
commit
ad86eb4be3
14 changed files with 389 additions and 66 deletions
|
@ -17,7 +17,21 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
devices: List[FloDeviceDataUpdateCoordinator] = hass.data[FLO_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]["devices"]
|
||||
entities = [FloPendingAlertsBinarySensor(device) for device in devices]
|
||||
entities = []
|
||||
for device in devices:
|
||||
if device.device_type == "puck_oem":
|
||||
# Flo "pucks" (leak detectors) *do* support pending alerts.
|
||||
# However these pending alerts mix unrelated issues like
|
||||
# low-battery alerts, humidity alerts, & temperature alerts
|
||||
# in addition to the critical "water detected" alert.
|
||||
#
|
||||
# Since there are non-binary sensors for battery, humidity,
|
||||
# and temperature, the binary sensor should only cover
|
||||
# water detection. If this sensor trips, you really have
|
||||
# a problem - vs. battery/temp/humidity which are warnings.
|
||||
entities.append(FloWaterDetectedBinarySensor(device))
|
||||
else:
|
||||
entities.append(FloPendingAlertsBinarySensor(device))
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
|
@ -48,3 +62,21 @@ class FloPendingAlertsBinarySensor(FloEntity, BinarySensorEntity):
|
|||
def device_class(self):
|
||||
"""Return the device class for the binary sensor."""
|
||||
return DEVICE_CLASS_PROBLEM
|
||||
|
||||
|
||||
class FloWaterDetectedBinarySensor(FloEntity, BinarySensorEntity):
|
||||
"""Binary sensor that reports if water is detected (for leak detectors)."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the pending alerts binary sensor."""
|
||||
super().__init__("water_detected", "Water Detected", device)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the Flo device is detecting water."""
|
||||
return self._device.water_detected
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the device class for the binary sensor."""
|
||||
return DEVICE_CLASS_PROBLEM
|
||||
|
|
|
@ -58,7 +58,9 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
@property
|
||||
def device_name(self) -> str:
|
||||
"""Return device name."""
|
||||
return f"{self.manufacturer} {self.model}"
|
||||
return self._device_information.get(
|
||||
"nickname", f"{self.manufacturer} {self.model}"
|
||||
)
|
||||
|
||||
@property
|
||||
def manufacturer(self) -> str:
|
||||
|
@ -120,6 +122,11 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
"""Return the current temperature in degrees F."""
|
||||
return self._device_information["telemetry"]["current"]["tempF"]
|
||||
|
||||
@property
|
||||
def humidity(self) -> float:
|
||||
"""Return the current humidity in percent (0-100)."""
|
||||
return self._device_information["telemetry"]["current"]["humidity"]
|
||||
|
||||
@property
|
||||
def consumption_today(self) -> float:
|
||||
"""Return the current consumption for today in gallons."""
|
||||
|
@ -159,6 +166,11 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
or self.pending_warning_alerts_count
|
||||
)
|
||||
|
||||
@property
|
||||
def water_detected(self) -> bool:
|
||||
"""Return whether water is detected, for leak detectors."""
|
||||
return self._device_information["fwProperties"]["telemetry_water"]
|
||||
|
||||
@property
|
||||
def last_known_valve_state(self) -> str:
|
||||
"""Return the last known valve state for the device."""
|
||||
|
@ -169,6 +181,11 @@ class FloDeviceDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
"""Return the target valve state for the device."""
|
||||
return self._device_information["valve"]["target"]
|
||||
|
||||
@property
|
||||
def battery_level(self) -> float:
|
||||
"""Return the battery level for battery-powered device, e.g. leak detectors."""
|
||||
return self._device_information["battery"]["level"]
|
||||
|
||||
async def async_set_mode_home(self):
|
||||
"""Set the Flo location to home mode."""
|
||||
await self.api_client.location.set_mode_home(self._flo_location_id)
|
||||
|
|
|
@ -3,13 +3,15 @@
|
|||
from typing import List, Optional
|
||||
|
||||
from homeassistant.const import (
|
||||
DEVICE_CLASS_BATTERY,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
PERCENTAGE,
|
||||
PRESSURE_PSI,
|
||||
TEMP_CELSIUS,
|
||||
TEMP_FAHRENHEIT,
|
||||
VOLUME_GALLONS,
|
||||
)
|
||||
from homeassistant.util.temperature import fahrenheit_to_celsius
|
||||
|
||||
from .const import DOMAIN as FLO_DOMAIN
|
||||
from .device import FloDeviceDataUpdateCoordinator
|
||||
|
@ -20,8 +22,11 @@ GAUGE_ICON = "mdi:gauge"
|
|||
NAME_DAILY_USAGE = "Today's Water Usage"
|
||||
NAME_CURRENT_SYSTEM_MODE = "Current System Mode"
|
||||
NAME_FLOW_RATE = "Water Flow Rate"
|
||||
NAME_TEMPERATURE = "Water Temperature"
|
||||
NAME_WATER_TEMPERATURE = "Water Temperature"
|
||||
NAME_AIR_TEMPERATURE = "Temperature"
|
||||
NAME_WATER_PRESSURE = "Water Pressure"
|
||||
NAME_HUMIDITY = "Humidity"
|
||||
NAME_BATTERY = "Battery"
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
|
@ -30,11 +35,25 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
config_entry.entry_id
|
||||
]["devices"]
|
||||
entities = []
|
||||
entities.extend([FloDailyUsageSensor(device) for device in devices])
|
||||
entities.extend([FloSystemModeSensor(device) for device in devices])
|
||||
entities.extend([FloCurrentFlowRateSensor(device) for device in devices])
|
||||
entities.extend([FloTemperatureSensor(device) for device in devices])
|
||||
entities.extend([FloPressureSensor(device) for device in devices])
|
||||
for device in devices:
|
||||
if device.device_type == "puck_oem":
|
||||
entities.extend(
|
||||
[
|
||||
FloTemperatureSensor(NAME_AIR_TEMPERATURE, device),
|
||||
FloHumiditySensor(device),
|
||||
FloBatterySensor(device),
|
||||
]
|
||||
)
|
||||
else:
|
||||
entities.extend(
|
||||
[
|
||||
FloDailyUsageSensor(device),
|
||||
FloSystemModeSensor(device),
|
||||
FloCurrentFlowRateSensor(device),
|
||||
FloTemperatureSensor(NAME_WATER_TEMPERATURE, device),
|
||||
FloPressureSensor(device),
|
||||
]
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
|
@ -109,9 +128,9 @@ class FloCurrentFlowRateSensor(FloEntity):
|
|||
class FloTemperatureSensor(FloEntity):
|
||||
"""Monitors the temperature."""
|
||||
|
||||
def __init__(self, device):
|
||||
def __init__(self, name, device):
|
||||
"""Initialize the temperature sensor."""
|
||||
super().__init__("temperature", NAME_TEMPERATURE, device)
|
||||
super().__init__("temperature", name, device)
|
||||
self._state: float = None
|
||||
|
||||
@property
|
||||
|
@ -119,12 +138,12 @@ class FloTemperatureSensor(FloEntity):
|
|||
"""Return the current temperature."""
|
||||
if self._device.temperature is None:
|
||||
return None
|
||||
return round(fahrenheit_to_celsius(self._device.temperature), 1)
|
||||
return round(self._device.temperature, 1)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return gallons as the unit measurement for water."""
|
||||
return TEMP_CELSIUS
|
||||
"""Return fahrenheit as the unit measurement for temperature."""
|
||||
return TEMP_FAHRENHEIT
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
|
@ -132,6 +151,32 @@ class FloTemperatureSensor(FloEntity):
|
|||
return DEVICE_CLASS_TEMPERATURE
|
||||
|
||||
|
||||
class FloHumiditySensor(FloEntity):
|
||||
"""Monitors the humidity."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the humidity sensor."""
|
||||
super().__init__("humidity", NAME_HUMIDITY, device)
|
||||
self._state: float = None
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[float]:
|
||||
"""Return the current humidity."""
|
||||
if self._device.humidity is None:
|
||||
return None
|
||||
return round(self._device.humidity, 1)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return percent as the unit measurement for humidity."""
|
||||
return PERCENTAGE
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return the device class for this sensor."""
|
||||
return DEVICE_CLASS_HUMIDITY
|
||||
|
||||
|
||||
class FloPressureSensor(FloEntity):
|
||||
"""Monitors the water pressure."""
|
||||
|
||||
|
@ -156,3 +201,27 @@ class FloPressureSensor(FloEntity):
|
|||
def device_class(self) -> Optional[str]:
|
||||
"""Return the device class for this sensor."""
|
||||
return DEVICE_CLASS_PRESSURE
|
||||
|
||||
|
||||
class FloBatterySensor(FloEntity):
|
||||
"""Monitors the battery level for battery-powered leak detectors."""
|
||||
|
||||
def __init__(self, device):
|
||||
"""Initialize the battery sensor."""
|
||||
super().__init__("battery", NAME_BATTERY, device)
|
||||
self._state: float = None
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[float]:
|
||||
"""Return the current battery level."""
|
||||
return self._device.battery_level
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
"""Return percentage as the unit measurement for battery."""
|
||||
return PERCENTAGE
|
||||
|
||||
@property
|
||||
def device_class(self) -> Optional[str]:
|
||||
"""Return the device class for this sensor."""
|
||||
return DEVICE_CLASS_BATTERY
|
||||
|
|
|
@ -26,7 +26,11 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||
devices: List[FloDeviceDataUpdateCoordinator] = hass.data[FLO_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]["devices"]
|
||||
async_add_entities([FloSwitch(device) for device in devices])
|
||||
entities = []
|
||||
for device in devices:
|
||||
if device.device_type != "puck_oem":
|
||||
entities.append(FloSwitch(device))
|
||||
async_add_entities(entities)
|
||||
|
||||
platform = entity_platform.current_platform.get()
|
||||
|
||||
|
|
|
@ -43,13 +43,19 @@ def aioclient_mock_fixture(aioclient_mock):
|
|||
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||
status=200,
|
||||
)
|
||||
# Mocks the device for flo.
|
||||
# Mocks the devices for flo.
|
||||
aioclient_mock.get(
|
||||
"https://api-gw.meetflo.com/api/v2/devices/98765",
|
||||
text=load_fixture("flo/device_info_response.json"),
|
||||
status=200,
|
||||
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||
)
|
||||
aioclient_mock.get(
|
||||
"https://api-gw.meetflo.com/api/v2/devices/32839",
|
||||
text=load_fixture("flo/device_info_response_detector.json"),
|
||||
status=200,
|
||||
headers={"Content-Type": CONTENT_TYPE_JSON},
|
||||
)
|
||||
# Mocks the water consumption for flo.
|
||||
aioclient_mock.get(
|
||||
"https://api-gw.meetflo.com/api/v2/water/consumption",
|
||||
|
|
|
@ -4,6 +4,7 @@ from homeassistant.const import (
|
|||
ATTR_FRIENDLY_NAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_USERNAME,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
@ -19,12 +20,14 @@ async def test_binary_sensors(hass, config_entry, aioclient_mock_fixture):
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
# we should have 6 entities for the device
|
||||
state = hass.states.get("binary_sensor.pending_system_alerts")
|
||||
assert state.state == STATE_ON
|
||||
assert state.attributes.get("info") == 0
|
||||
assert state.attributes.get("warning") == 2
|
||||
assert state.attributes.get("critical") == 0
|
||||
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Pending System Alerts"
|
||||
valve_state = hass.states.get("binary_sensor.pending_system_alerts")
|
||||
assert valve_state.state == STATE_ON
|
||||
assert valve_state.attributes.get("info") == 0
|
||||
assert valve_state.attributes.get("warning") == 2
|
||||
assert valve_state.attributes.get("critical") == 0
|
||||
assert valve_state.attributes.get(ATTR_FRIENDLY_NAME) == "Pending System Alerts"
|
||||
|
||||
detector_state = hass.states.get("binary_sensor.water_detected")
|
||||
assert detector_state.state == STATE_OFF
|
||||
|
|
|
@ -13,46 +13,64 @@ from tests.common import async_fire_time_changed
|
|||
|
||||
|
||||
async def test_device(hass, config_entry, aioclient_mock_fixture, aioclient_mock):
|
||||
"""Test Flo by Moen device."""
|
||||
"""Test Flo by Moen devices."""
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await async_setup_component(
|
||||
hass, FLO_DOMAIN, {CONF_USERNAME: TEST_USER_ID, CONF_PASSWORD: TEST_PASSWORD}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
device: FloDeviceDataUpdateCoordinator = hass.data[FLO_DOMAIN][
|
||||
valve: FloDeviceDataUpdateCoordinator = hass.data[FLO_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]["devices"][0]
|
||||
assert device.api_client is not None
|
||||
assert device.available
|
||||
assert device.consumption_today == 3.674
|
||||
assert device.current_flow_rate == 0
|
||||
assert device.current_psi == 54.20000076293945
|
||||
assert device.current_system_mode == "home"
|
||||
assert device.target_system_mode == "home"
|
||||
assert device.firmware_version == "6.1.1"
|
||||
assert device.device_type == "flo_device_v2"
|
||||
assert device.id == "98765"
|
||||
assert device.last_heard_from_time == "2020-07-24T12:45:00Z"
|
||||
assert device.location_id == "mmnnoopp"
|
||||
assert device.hass is not None
|
||||
assert device.temperature == 70
|
||||
assert device.mac_address == "111111111111"
|
||||
assert device.model == "flo_device_075_v2"
|
||||
assert device.manufacturer == "Flo by Moen"
|
||||
assert device.device_name == "Flo by Moen flo_device_075_v2"
|
||||
assert device.rssi == -47
|
||||
assert device.pending_info_alerts_count == 0
|
||||
assert device.pending_critical_alerts_count == 0
|
||||
assert device.pending_warning_alerts_count == 2
|
||||
assert device.has_alerts is True
|
||||
assert device.last_known_valve_state == "open"
|
||||
assert device.target_valve_state == "open"
|
||||
assert valve.api_client is not None
|
||||
assert valve.available
|
||||
assert valve.consumption_today == 3.674
|
||||
assert valve.current_flow_rate == 0
|
||||
assert valve.current_psi == 54.20000076293945
|
||||
assert valve.current_system_mode == "home"
|
||||
assert valve.target_system_mode == "home"
|
||||
assert valve.firmware_version == "6.1.1"
|
||||
assert valve.device_type == "flo_device_v2"
|
||||
assert valve.id == "98765"
|
||||
assert valve.last_heard_from_time == "2020-07-24T12:45:00Z"
|
||||
assert valve.location_id == "mmnnoopp"
|
||||
assert valve.hass is not None
|
||||
assert valve.temperature == 70
|
||||
assert valve.mac_address == "111111111111"
|
||||
assert valve.model == "flo_device_075_v2"
|
||||
assert valve.manufacturer == "Flo by Moen"
|
||||
assert valve.device_name == "Smart Water Shutoff"
|
||||
assert valve.rssi == -47
|
||||
assert valve.pending_info_alerts_count == 0
|
||||
assert valve.pending_critical_alerts_count == 0
|
||||
assert valve.pending_warning_alerts_count == 2
|
||||
assert valve.has_alerts is True
|
||||
assert valve.last_known_valve_state == "open"
|
||||
assert valve.target_valve_state == "open"
|
||||
|
||||
detector: FloDeviceDataUpdateCoordinator = hass.data[FLO_DOMAIN][
|
||||
config_entry.entry_id
|
||||
]["devices"][1]
|
||||
assert detector.api_client is not None
|
||||
assert detector.available
|
||||
assert detector.device_type == "puck_oem"
|
||||
assert detector.id == "32839"
|
||||
assert detector.last_heard_from_time == "2021-03-07T14:05:00Z"
|
||||
assert detector.location_id == "mmnnoopp"
|
||||
assert detector.hass is not None
|
||||
assert detector.temperature == 61
|
||||
assert detector.humidity == 43
|
||||
assert detector.water_detected is False
|
||||
assert detector.mac_address == "1a2b3c4d5e6f"
|
||||
assert detector.model == "puck_v1"
|
||||
assert detector.manufacturer == "Flo by Moen"
|
||||
assert detector.device_name == "Kitchen Sink"
|
||||
|
||||
call_count = aioclient_mock.call_count
|
||||
|
||||
async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=90))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == call_count + 2
|
||||
assert aioclient_mock.call_count == call_count + 4
|
||||
|
|
|
@ -13,6 +13,6 @@ async def test_setup_entry(hass, config_entry, aioclient_mock_fixture):
|
|||
hass, FLO_DOMAIN, {CONF_USERNAME: TEST_USER_ID, CONF_PASSWORD: TEST_PASSWORD}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
|
|
|
@ -14,14 +14,19 @@ async def test_sensors(hass, config_entry, aioclient_mock_fixture):
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
# we should have 5 entities for the device
|
||||
# we should have 5 entities for the valve
|
||||
assert hass.states.get("sensor.current_system_mode").state == "home"
|
||||
assert hass.states.get("sensor.today_s_water_usage").state == "3.7"
|
||||
assert hass.states.get("sensor.water_flow_rate").state == "0"
|
||||
assert hass.states.get("sensor.water_pressure").state == "54.2"
|
||||
assert hass.states.get("sensor.water_temperature").state == "21.1"
|
||||
assert hass.states.get("sensor.water_temperature").state == "21"
|
||||
|
||||
# and 3 entities for the detector
|
||||
assert hass.states.get("sensor.temperature").state == "16"
|
||||
assert hass.states.get("sensor.humidity").state == "43"
|
||||
assert hass.states.get("sensor.battery").state == "100"
|
||||
|
||||
|
||||
async def test_manual_update_entity(
|
||||
|
@ -34,7 +39,7 @@ async def test_manual_update_entity(
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert aioclient_mock.call_count == 4
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
assert aioclient_mock.call_count == 6
|
||||
|
||||
await hass.services.async_call(
|
||||
FLO_DOMAIN,
|
||||
|
@ -35,7 +35,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo
|
|||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert aioclient_mock.call_count == 5
|
||||
assert aioclient_mock.call_count == 7
|
||||
|
||||
await hass.services.async_call(
|
||||
FLO_DOMAIN,
|
||||
|
@ -44,7 +44,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo
|
|||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert aioclient_mock.call_count == 6
|
||||
assert aioclient_mock.call_count == 8
|
||||
|
||||
await hass.services.async_call(
|
||||
FLO_DOMAIN,
|
||||
|
@ -53,7 +53,7 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo
|
|||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert aioclient_mock.call_count == 7
|
||||
assert aioclient_mock.call_count == 9
|
||||
|
||||
await hass.services.async_call(
|
||||
FLO_DOMAIN,
|
||||
|
@ -66,4 +66,4 @@ async def test_services(hass, config_entry, aioclient_mock_fixture, aioclient_mo
|
|||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert aioclient_mock.call_count == 8
|
||||
assert aioclient_mock.call_count == 10
|
||||
|
|
|
@ -15,7 +15,7 @@ async def test_valve_switches(hass, config_entry, aioclient_mock_fixture):
|
|||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 1
|
||||
assert len(hass.data[FLO_DOMAIN][config_entry.entry_id]["devices"]) == 2
|
||||
|
||||
entity_id = "switch.shutoff_valve"
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
|
161
tests/fixtures/flo/device_info_response_detector.json
vendored
Normal file
161
tests/fixtures/flo/device_info_response_detector.json
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
{
|
||||
"actionRules": [],
|
||||
"battery": {
|
||||
"level": 100,
|
||||
"updated": "2021-03-01T12:05:00Z"
|
||||
},
|
||||
"connectivity": {
|
||||
"ssid": "SOMESSID"
|
||||
},
|
||||
"deviceModel": "puck_v1",
|
||||
"deviceType": "puck_oem",
|
||||
"fwProperties": {
|
||||
"alert_battery_active": false,
|
||||
"alert_humidity_high_active": false,
|
||||
"alert_humidity_high_count": 0,
|
||||
"alert_humidity_low_active": false,
|
||||
"alert_humidity_low_count": 1,
|
||||
"alert_state": "inactive",
|
||||
"alert_temperature_high_active": false,
|
||||
"alert_temperature_high_count": 0,
|
||||
"alert_temperature_low_active": false,
|
||||
"alert_temperature_low_count": 0,
|
||||
"alert_water_active": false,
|
||||
"alert_water_count": 0,
|
||||
"ap_mode_count": 1,
|
||||
"beep_pattern": "off",
|
||||
"button_click_count": 1,
|
||||
"date": "2021-03-07T14:00:05.054Z",
|
||||
"deep_sleep_count": 8229,
|
||||
"device_boot_count": 25,
|
||||
"device_boot_reason": "wakeup_timer",
|
||||
"device_count": 8230,
|
||||
"device_failed_count": 36,
|
||||
"device_id": "1a2b3c4d5e6f",
|
||||
"device_time_total": 405336,
|
||||
"device_time_up": 1502,
|
||||
"device_uuid": "32839",
|
||||
"device_wakeup_count": 8254,
|
||||
"flosense_shut_off_level": 2,
|
||||
"fw_name": "1.1.15",
|
||||
"fw_version": 10115,
|
||||
"led_pattern": "led_blue_solid",
|
||||
"limit_ota_battery_min": 30,
|
||||
"pairing_state": "configured",
|
||||
"reason": "heartbeat",
|
||||
"serial_number": "111111111112",
|
||||
"telemetry_battery_percent": 100,
|
||||
"telemetry_battery_voltage": 2.9896278381347656,
|
||||
"telemetry_count": 8224,
|
||||
"telemetry_failed_count": 27,
|
||||
"telemetry_humidity": 43.21965408325195,
|
||||
"telemetry_rssi": 100,
|
||||
"telemetry_temperature": 61.43144607543945,
|
||||
"telemetry_water": false,
|
||||
"timer_alarm_active": 10,
|
||||
"timer_heartbeat_battery_low": 3600,
|
||||
"timer_heartbeat_battery_ok": 1740,
|
||||
"timer_heartbeat_last": 1740,
|
||||
"timer_heartbeat_not_configured": 10,
|
||||
"timer_heartbeat_retry_attempts": 3,
|
||||
"timer_heartbeat_retry_delay": 600,
|
||||
"timer_water_debounce": 2000,
|
||||
"timer_wifi_ap_timeout": 600000,
|
||||
"wifi_ap_ssid": "FloDetector-a123",
|
||||
"wifi_sta_enc": "wpa2-psk",
|
||||
"wifi_sta_failed_count": 21,
|
||||
"wifi_sta_mac": "50:01:01:01:01:44",
|
||||
"wifi_sta_ssid": "SOMESSID"
|
||||
},
|
||||
"fwVersion": "1.1.15",
|
||||
"hardwareThresholds": {
|
||||
"battery": {
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"okMax": 100,
|
||||
"okMin": 20
|
||||
},
|
||||
"batteryEnabled": true,
|
||||
"humidity": {
|
||||
"maxValue": 100,
|
||||
"minValue": 0,
|
||||
"okMax": 85,
|
||||
"okMin": 15
|
||||
},
|
||||
"humidityEnabled": true,
|
||||
"tempC": {
|
||||
"maxValue": 60,
|
||||
"minValue": -17.77777777777778,
|
||||
"okMax": 37.77777777777778,
|
||||
"okMin": 0
|
||||
},
|
||||
"tempEnabled": true,
|
||||
"tempF": {
|
||||
"maxValue": 140,
|
||||
"minValue": 0,
|
||||
"okMax": 100,
|
||||
"okMin": 32
|
||||
}
|
||||
},
|
||||
"id": "32839",
|
||||
"installStatus": {
|
||||
"isInstalled": false
|
||||
},
|
||||
"isConnected": true,
|
||||
"isPaired": true,
|
||||
"lastHeardFromTime": "2021-03-07T14:05:00Z",
|
||||
"location": {
|
||||
"id": "mmnnoopp"
|
||||
},
|
||||
"macAddress": "1a2b3c4d5e6f",
|
||||
"nickname": "Kitchen Sink",
|
||||
"notifications": {
|
||||
"pending": {
|
||||
"alarmCount": [],
|
||||
"critical": {
|
||||
"count": 0,
|
||||
"devices": {
|
||||
"absolute": 0,
|
||||
"count": 0
|
||||
}
|
||||
},
|
||||
"criticalCount": 0,
|
||||
"info": {
|
||||
"count": 0,
|
||||
"devices": {
|
||||
"absolute": 0,
|
||||
"count": 0
|
||||
}
|
||||
},
|
||||
"infoCount": 0,
|
||||
"warning": {
|
||||
"count": 0,
|
||||
"devices": {
|
||||
"absolute": 0,
|
||||
"count": 0
|
||||
}
|
||||
},
|
||||
"warningCount": 0
|
||||
}
|
||||
},
|
||||
"puckConfig": {
|
||||
"configuredAt": "2020-09-01T18:15:12.216Z",
|
||||
"isConfigured": true
|
||||
},
|
||||
"serialNumber": "111111111112",
|
||||
"shutoff": {
|
||||
"scheduledAt": "1970-01-01T00:00:00.000Z"
|
||||
},
|
||||
"systemMode": {
|
||||
"isLocked": false,
|
||||
"shouldInherit": true
|
||||
},
|
||||
"telemetry": {
|
||||
"current": {
|
||||
"humidity": 43,
|
||||
"tempF": 61,
|
||||
"updated": "2021-03-07T14:05:00Z"
|
||||
}
|
||||
},
|
||||
"valve": {}
|
||||
}
|
|
@ -9,6 +9,10 @@
|
|||
{
|
||||
"id": "98765",
|
||||
"macAddress": "123456abcdef"
|
||||
},
|
||||
{
|
||||
"id": "32839",
|
||||
"macAddress": "1a2b3c4d5e6f"
|
||||
}
|
||||
],
|
||||
"userRoles": [
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
{
|
||||
"id": "98765",
|
||||
"macAddress": "606405c11e10"
|
||||
},
|
||||
{
|
||||
"id": "32839",
|
||||
"macAddress": "1a2b3c4d5e6f"
|
||||
}
|
||||
],
|
||||
"userRoles": [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue