From ad86eb4be3ece16a08eedb4487e86334c17ac942 Mon Sep 17 00:00:00 2001 From: Adam Ernst Date: Mon, 8 Mar 2021 06:36:03 -0600 Subject: [PATCH] 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. --- homeassistant/components/flo/binary_sensor.py | 34 +++- homeassistant/components/flo/device.py | 19 ++- homeassistant/components/flo/sensor.py | 95 +++++++++-- homeassistant/components/flo/switch.py | 6 +- tests/components/flo/conftest.py | 8 +- tests/components/flo/test_binary_sensor.py | 19 ++- tests/components/flo/test_device.py | 76 +++++---- tests/components/flo/test_init.py | 2 +- tests/components/flo/test_sensor.py | 13 +- tests/components/flo/test_services.py | 12 +- tests/components/flo/test_switch.py | 2 +- .../flo/device_info_response_detector.json | 161 ++++++++++++++++++ .../flo/location_info_base_response.json | 4 + .../user_info_expand_locations_response.json | 4 + 14 files changed, 389 insertions(+), 66 deletions(-) create mode 100644 tests/fixtures/flo/device_info_response_detector.json diff --git a/homeassistant/components/flo/binary_sensor.py b/homeassistant/components/flo/binary_sensor.py index a8bac498674..3ab1152f83e 100644 --- a/homeassistant/components/flo/binary_sensor.py +++ b/homeassistant/components/flo/binary_sensor.py @@ -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 diff --git a/homeassistant/components/flo/device.py b/homeassistant/components/flo/device.py index af36034026d..49e0e991376 100644 --- a/homeassistant/components/flo/device.py +++ b/homeassistant/components/flo/device.py @@ -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) diff --git a/homeassistant/components/flo/sensor.py b/homeassistant/components/flo/sensor.py index 2feeb3702a6..d88f2b950fc 100644 --- a/homeassistant/components/flo/sensor.py +++ b/homeassistant/components/flo/sensor.py @@ -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 diff --git a/homeassistant/components/flo/switch.py b/homeassistant/components/flo/switch.py index 91f3fdf54e4..895212c56a0 100644 --- a/homeassistant/components/flo/switch.py +++ b/homeassistant/components/flo/switch.py @@ -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() diff --git a/tests/components/flo/conftest.py b/tests/components/flo/conftest.py index 907feb85569..d4ba80e6406 100644 --- a/tests/components/flo/conftest.py +++ b/tests/components/flo/conftest.py @@ -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", diff --git a/tests/components/flo/test_binary_sensor.py b/tests/components/flo/test_binary_sensor.py index 64b8f787a85..b6a8abf727c 100644 --- a/tests/components/flo/test_binary_sensor.py +++ b/tests/components/flo/test_binary_sensor.py @@ -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 diff --git a/tests/components/flo/test_device.py b/tests/components/flo/test_device.py index 63e81a16fb4..5ac31a2bff9 100644 --- a/tests/components/flo/test_device.py +++ b/tests/components/flo/test_device.py @@ -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 diff --git a/tests/components/flo/test_init.py b/tests/components/flo/test_init.py index 9061477da47..13f16f06cbf 100644 --- a/tests/components/flo/test_init.py +++ b/tests/components/flo/test_init.py @@ -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) diff --git a/tests/components/flo/test_sensor.py b/tests/components/flo/test_sensor.py index 309dfc11266..f1572dae02c 100644 --- a/tests/components/flo/test_sensor.py +++ b/tests/components/flo/test_sensor.py @@ -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", {}) diff --git a/tests/components/flo/test_services.py b/tests/components/flo/test_services.py index 270279e4a9d..4941a118e48 100644 --- a/tests/components/flo/test_services.py +++ b/tests/components/flo/test_services.py @@ -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 diff --git a/tests/components/flo/test_switch.py b/tests/components/flo/test_switch.py index 25a64433a29..cc6ab7e3a7e 100644 --- a/tests/components/flo/test_switch.py +++ b/tests/components/flo/test_switch.py @@ -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 diff --git a/tests/fixtures/flo/device_info_response_detector.json b/tests/fixtures/flo/device_info_response_detector.json new file mode 100644 index 00000000000..aac24ab5e68 --- /dev/null +++ b/tests/fixtures/flo/device_info_response_detector.json @@ -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": {} +} diff --git a/tests/fixtures/flo/location_info_base_response.json b/tests/fixtures/flo/location_info_base_response.json index f6840a0742b..a5a25da2d6c 100644 --- a/tests/fixtures/flo/location_info_base_response.json +++ b/tests/fixtures/flo/location_info_base_response.json @@ -9,6 +9,10 @@ { "id": "98765", "macAddress": "123456abcdef" + }, + { + "id": "32839", + "macAddress": "1a2b3c4d5e6f" } ], "userRoles": [ diff --git a/tests/fixtures/flo/user_info_expand_locations_response.json b/tests/fixtures/flo/user_info_expand_locations_response.json index 829596b6849..18643e049ba 100644 --- a/tests/fixtures/flo/user_info_expand_locations_response.json +++ b/tests/fixtures/flo/user_info_expand_locations_response.json @@ -19,6 +19,10 @@ { "id": "98765", "macAddress": "606405c11e10" + }, + { + "id": "32839", + "macAddress": "1a2b3c4d5e6f" } ], "userRoles": [