diff --git a/custom_components/owlet/__init__.py b/custom_components/owlet/__init__.py index 096713e..3089c47 100644 --- a/custom_components/owlet/__init__.py +++ b/custom_components/owlet/__init__.py @@ -1,6 +1,7 @@ """The Owlet Smart Sock integration.""" from __future__ import annotations +import asyncio import logging from pyowletapi.api import OwletAPI @@ -13,11 +14,7 @@ from pyowletapi.exceptions import ( ) from pyowletapi.sock import Sock -from homeassistant.config_entries import ( - ConfigEntry, - ConfigEntryAuthFailed, - ConfigEntryNotReady, -) +from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( CONF_API_TOKEN, CONF_REGION, @@ -26,8 +23,8 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.device_registry import DeviceEntry from .const import CONF_OWLET_EXPIRY, CONF_OWLET_REFRESH, DOMAIN, SUPPORTED_VERSIONS from .coordinator import OwletCoordinator @@ -50,23 +47,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ) try: - token = await owlet_api.authenticate() - - if token: + if token := await owlet_api.authenticate(): hass.config_entries.async_update_entry(entry, data={**entry.data, **token}) devices = await owlet_api.get_devices(SUPPORTED_VERSIONS) - if devices["tokens"]: - hass.config_entries.async_update_entry( - entry, data={**entry.data, **devices["tokens"]} - ) - - socks = { - device["device"]["dsn"]: Sock(owlet_api, device["device"]) - for device in devices["response"] - } - except (OwletAuthenticationError, OwletEmailError, OwletPasswordError) as err: _LOGGER.error("Credentials no longer valid, please setup owlet again") raise ConfigEntryAuthFailed( @@ -78,14 +63,34 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: f"Error connecting to {entry.data[CONF_USERNAME]}" ) from err - coordinators = [ - OwletCoordinator(hass, sock, entry.options.get(CONF_SCAN_INTERVAL)) - for sock in socks.values() - ] + except OwletDevicesError: + _LOGGER.error("No owlet devices found to set up") + return False - for coordinator in coordinators: - await coordinator.async_config_entry_first_refresh() - hass.data[DOMAIN][entry.entry_id] = coordinator + if devices["tokens"]: + hass.config_entries.async_update_entry( + entry, data={**entry.data, **devices["tokens"]} + ) + + socks = { + device["device"]["dsn"]: Sock(owlet_api, device["device"]) + for device in devices["response"] + } + + scan_interval = entry.options.get(CONF_SCAN_INTERVAL) + coordinators = { + serial: OwletCoordinator(hass, sock, scan_interval) + for (serial, sock) in socks.items() + } + + await asyncio.gather( + *( + coordinator.async_config_entry_first_refresh() + for coordinator in list(coordinators.values()) + ) + ) + + hass.data[DOMAIN][entry.entry_id] = coordinators await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/custom_components/owlet/binary_sensor.py b/custom_components/owlet/binary_sensor.py index 0302d14..f52abc7 100644 --- a/custom_components/owlet/binary_sensor.py +++ b/custom_components/owlet/binary_sensor.py @@ -34,61 +34,61 @@ class OwletBinarySensorEntityDescription( SENSORS: tuple[OwletBinarySensorEntityDescription, ...] = ( OwletBinarySensorEntityDescription( key="charging", - name="Charging", + translation_key="charging", device_class=BinarySensorDeviceClass.BATTERY_CHARGING, element="charging", ), OwletBinarySensorEntityDescription( key="highhr", - name="High heart rate alert", + translation_key="high_hr_alrt", device_class=BinarySensorDeviceClass.SOUND, element="high_heart_rate_alert", ), OwletBinarySensorEntityDescription( key="lowhr", - name="Low Heart Rate Alert", + translation_key="low_hr_alrt", device_class=BinarySensorDeviceClass.SOUND, element="low_heart_rate_alert", ), OwletBinarySensorEntityDescription( key="higho2", - name="High oxygen alert", + translation_key="high_ox_alrt", device_class=BinarySensorDeviceClass.SOUND, element="high_oxygen_alert", ), OwletBinarySensorEntityDescription( key="lowo2", - name="Low oxygen alert", + translation_key="low_ox_alrt", device_class=BinarySensorDeviceClass.SOUND, element="low_oxygen_alert", ), OwletBinarySensorEntityDescription( key="lowbattery", - name="Low Battery alert", + translation_key="low_batt_alrt", device_class=BinarySensorDeviceClass.SOUND, element="low_battery_alert", ), OwletBinarySensorEntityDescription( key="lostpower", - name="Lost power alert", + translation_key="lost_pwr_alrt", device_class=BinarySensorDeviceClass.SOUND, element="lost_power_alert", ), OwletBinarySensorEntityDescription( key="sockdisconnected", - name="Sock disconnected alert", + translation_key="sock_discon_alrt", device_class=BinarySensorDeviceClass.SOUND, element="sock_disconnected", ), OwletBinarySensorEntityDescription( key="sock_off", - name="Sock off", + translation_key="sock_off", device_class=BinarySensorDeviceClass.POWER, element="sock_off", ), OwletBinarySensorEntityDescription( key="awake", - name="Awake", + translation_key="awake", element="sleep_state", icon="mdi:sleep", ), diff --git a/custom_components/owlet/config_flow.py b/custom_components/owlet/config_flow.py index 13da9d7..e4c7f5a 100644 --- a/custom_components/owlet/config_flow.py +++ b/custom_components/owlet/config_flow.py @@ -1,11 +1,17 @@ """Config flow for Owlet Smart Sock integration.""" from __future__ import annotations +from collections.abc import Mapping import logging from typing import Any from pyowletapi.api import OwletAPI -from pyowletapi.exceptions import OwletDevicesError, OwletEmailError, OwletPasswordError +from pyowletapi.exceptions import ( + OwletCredentialsError, + OwletDevicesError, + OwletEmailError, + OwletPasswordError, +) from pyowletapi.sock import Sock import voluptuous as vol @@ -41,6 +47,7 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 def __init__(self) -> None: + """Initialise config flow.""" self._entry: ConfigEntry self._region: str self._username: str @@ -70,29 +77,31 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: token = await owlet_api.authenticate() - try: - await owlet_api.validate_authentication() - return self.async_create_entry( - title=self._username, - data={ - CONF_REGION: self._region, - CONF_USERNAME: self._username, - CONF_API_TOKEN: token[CONF_API_TOKEN], - CONF_OWLET_EXPIRY: token[CONF_OWLET_EXPIRY], - CONF_OWLET_REFRESH: token[CONF_OWLET_REFRESH], - }, - options={CONF_SCAN_INTERVAL: POLLING_INTERVAL}, - ) - except OwletDevicesError: - errors["base"] = "no_devices" + await owlet_api.validate_authentication() + except OwletDevicesError: + errors["base"] = "no_devices" except OwletEmailError: errors["base"] = "invalid_email" except OwletPasswordError: errors["base"] = "invalid_password" + except OwletCredentialsError: + errors["base"] = "invalid_credentials" except Exception: # pylint: disable=broad-except _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" + else: + return self.async_create_entry( + title=self._username, + data={ + CONF_REGION: self._region, + CONF_USERNAME: self._username, + CONF_API_TOKEN: token[CONF_API_TOKEN], + CONF_OWLET_EXPIRY: token[CONF_OWLET_EXPIRY], + CONF_OWLET_REFRESH: token[CONF_OWLET_REFRESH], + }, + options={CONF_SCAN_INTERVAL: POLLING_INTERVAL}, + ) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors @@ -104,10 +113,8 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Get the options flow for this handler.""" return OptionsFlowHandler(config_entry) - async def async_step_reauth( - self, user_input: dict[str, Any] | None = None - ) -> FlowResult: - """Handle reauth""" + async def async_step_reauth(self, user_input: Mapping[str, Any]) -> FlowResult: + """Handle reauth.""" self.reauth_entry = self.hass.config_entries.async_get_entry( self.context["entry_id"] ) @@ -116,7 +123,7 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_reauth_confirm( self, user_input: dict[str, Any] | None = None ) -> FlowResult: - """Dialog that informs the user that reauth is required""" + """Dialog that informs the user that reauth is required.""" assert self.reauth_entry is not None errors: dict[str, str] = {} @@ -152,16 +159,16 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): class OptionsFlowHandler(config_entries.OptionsFlow): - """Handle a options flow for owlet""" + """Handle a options flow for owlet.""" def __init__(self, config_entry: ConfigEntry) -> None: - """Initialise options flow""" + """Initialise options flow.""" self.config_entry = config_entry async def async_step_init( self, user_input: dict[str, Any] | None = None ) -> FlowResult: - """Handle options flow""" + """Handle options flow.""" if user_input is not None: return self.async_create_entry(title="", data=user_input) @@ -178,4 +185,4 @@ class OptionsFlowHandler(config_entries.OptionsFlow): class InvalidAuth(exceptions.HomeAssistantError): - """Error to indiciate there is invalud auth""" + """Error to indicate there is invalid auth.""" diff --git a/custom_components/owlet/const.py b/custom_components/owlet/const.py index 61d5615..3365809 100644 --- a/custom_components/owlet/const.py +++ b/custom_components/owlet/const.py @@ -8,4 +8,4 @@ CONF_OWLET_REFRESH = "refresh" SUPPORTED_VERSIONS = [3] POLLING_INTERVAL = 5 MANUFACTURER = "Owlet Baby Care" -SLEEP_STATES = {0: "Unknown", 1: "Awake", 8: "Light Sleep", 15: "Deep Sleep"} +SLEEP_STATES = {0: "unknown", 1: "awake", 8: "light_sleep", 15: "deep_sleep"} diff --git a/custom_components/owlet/coordinator.py b/custom_components/owlet/coordinator.py index d615e90..a9f6dd4 100644 --- a/custom_components/owlet/coordinator.py +++ b/custom_components/owlet/coordinator.py @@ -11,14 +11,12 @@ from pyowletapi.exceptions import ( ) from pyowletapi.sock import Sock +from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_EMAIL from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.helpers.entity import DeviceInfo -from homeassistant.helpers.update_coordinator import ( - ConfigEntryAuthFailed, - DataUpdateCoordinator, - UpdateFailed, -) +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import DOMAIN, MANUFACTURER @@ -28,7 +26,7 @@ _LOGGER = logging.getLogger(__name__) class OwletCoordinator(DataUpdateCoordinator): """Coordinator is responsible for querying the device at a specified route.""" - def __init__(self, hass: HomeAssistant, sock: Sock, interval: int) -> None: + def __init__(self, hass: HomeAssistant, sock: Sock, interval) -> None: """Initialise a custom coordinator.""" super().__init__( hass, @@ -37,18 +35,15 @@ class OwletCoordinator(DataUpdateCoordinator): update_interval=timedelta(seconds=interval), ) assert self.config_entry is not None - self._device_unique_id = sock.serial - self._model = sock.model - self._sw_version = sock.sw_version - self._hw_version = sock.version + self.config_entry: ConfigEntry self.sock = sock self.device_info = DeviceInfo( - identifiers={(DOMAIN, self._device_unique_id)}, + identifiers={(DOMAIN, sock.serial)}, name="Owlet Baby Care Sock", manufacturer=MANUFACTURER, - model=self._model, - sw_version=self._sw_version, - hw_version=self._hw_version, + model=sock.model, + sw_version=sock.sw_version, + hw_version=sock.version, ) async def _async_update_data(self) -> None: diff --git a/custom_components/owlet/manifest.json b/custom_components/owlet/manifest.json index c8e7804..84c705b 100644 --- a/custom_components/owlet/manifest.json +++ b/custom_components/owlet/manifest.json @@ -3,9 +3,8 @@ "name": "Owlet Smart Sock", "codeowners": ["@ryanbdclark"], "config_flow": true, - "dependencies": [], "documentation": "https://www.home-assistant.io/integrations/owlet", - "homekit": {}, "iot_class": "cloud_polling", - "requirements": ["pyowletapi==2023.5.28"] + "requirements": ["pyowletapi==2023.5.30"], + "version":"2023.5.6" } diff --git a/custom_components/owlet/sensor.py b/custom_components/owlet/sensor.py index b4699d3..1f7c246 100644 --- a/custom_components/owlet/sensor.py +++ b/custom_components/owlet/sensor.py @@ -27,7 +27,7 @@ from .entity import OwletBaseEntity @dataclass class OwletSensorEntityDescriptionMixin: - """Owlet sensor description mix in""" + """Owlet sensor description mix in.""" element: str @@ -42,7 +42,7 @@ class OwletSensorEntityDescription( SENSORS: tuple[OwletSensorEntityDescription, ...] = ( OwletSensorEntityDescription( key="batterypercentage", - name="Battery", + translation_key="batterypercent", native_unit_of_measurement=PERCENTAGE, device_class=SensorDeviceClass.BATTERY, state_class=SensorStateClass.MEASUREMENT, @@ -50,7 +50,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="oxygensaturation", - name="O2 Saturation", + translation_key="o2saturation", native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, element="oxygen_saturation", @@ -58,7 +58,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="oxygensaturation10a", - name="O2 Saturation 10 Minute Average", + translation_key="o2saturation10a", native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, element="oxygen_10_av", @@ -66,7 +66,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="heartrate", - name="Heart rate", + translation_key="heartrate", native_unit_of_measurement="bpm", state_class=SensorStateClass.MEASUREMENT, element="heart_rate", @@ -74,7 +74,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="batteryminutes", - name="Battery Remaining", + translation_key="batterymin", native_unit_of_measurement=UnitOfTime.MINUTES, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, @@ -82,7 +82,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="signalstrength", - name="Signal Strength", + translation_key="signalstrength", native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, device_class=SensorDeviceClass.SIGNAL_STRENGTH, state_class=SensorStateClass.MEASUREMENT, @@ -90,7 +90,7 @@ SENSORS: tuple[OwletSensorEntityDescription, ...] = ( ), OwletSensorEntityDescription( key="skintemp", - name="Skin Temperature", + translation_key="skintemp", native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, @@ -106,12 +106,19 @@ async def async_setup_entry( ) -> None: """Set up the owlet sensors from config entry.""" - coordinator: OwletCoordinator = hass.data[DOMAIN][config_entry.entry_id] + coordinators: list[OwletCoordinator] = list( + hass.data[DOMAIN][config_entry.entry_id].values() + ) - entities = [OwletSensor(coordinator, sensor) for sensor in SENSORS] - entities.append(OwletSleepStateSensor(coordinator)) + async_add_entities( + OwletSensor(coordinator, sensor) + for coordinator in coordinators + for sensor in SENSORS + ) - async_add_entities(entities) + async_add_entities( + OwletSleepStateSensor(coordinator) for coordinator in coordinators + ) class OwletSensor(OwletBaseEntity, SensorEntity): @@ -124,12 +131,14 @@ class OwletSensor(OwletBaseEntity, SensorEntity): ) -> None: """Initialize the sensor.""" super().__init__(coordinator) - self.entity_description = sensor_description - self._attr_unique_id = f"{self.sock.serial}-{self.entity_description.name}" + self.entity_description: OwletSensorEntityDescription = sensor_description + self._attr_unique_id = ( + f"{self.sock.serial}-{self.entity_description.translation_key}" + ) @property def native_value(self) -> StateType: - """Return sensor value""" + """Return sensor value.""" if ( self.entity_description.element @@ -158,20 +167,20 @@ class OwletSleepStateSensor(OwletBaseEntity, SensorEntity): ) -> None: """Initialize the sensor.""" super().__init__(coordinator) - self._attr_unique_id = f"{self.sock.serial}-Sleep State" + self._attr_unique_id = f"{self.sock.serial}-sleepstate" self._attr_icon = "mdi:sleep" self._attr_device_class = SensorDeviceClass.ENUM self._attr_translation_key = "sleepstate" - self._attr_name = "Sleep State" @property def native_value(self) -> str: - """Return sensor value""" + """Return sensor value.""" if self.sock.properties["charging"]: - return None + return "unknown" return SLEEP_STATES[self.sock.properties["sleep_state"]] @property def options(self) -> list[str]: + """Set options for sleep state.""" return list(SLEEP_STATES.values()) diff --git a/custom_components/owlet/strings.json b/custom_components/owlet/strings.json index f932c92..3cfee18 100644 --- a/custom_components/owlet/strings.json +++ b/custom_components/owlet/strings.json @@ -1,17 +1,17 @@ { "config": { "step": { - "user":{ + "user": { "title": "Enter login details", - "data":{ + "data": { "region": "Region", "username": "Email", "password": "Password" } }, - "reauth_confirm":{ + "reauth_confirm": { "title": "Reauthentiaction required for Owlet", - "data":{ + "data": { "password": "Password" } } @@ -20,20 +20,88 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_email": "Entered email address is incorrect", "invalid_password": "Entered password is incorrect", - "unknown": "[%key:common::config_flow::error::unknown%]" + "invalid_credentials": "Entered credentials are incorrect", + "unknown": "Unknown error occured" }, "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + "already_configured": "Device already configured", + "reauth_successful": "Reauthentication successful" } }, "options": { "step": { - "init":{ - "title":"Configure options for Owlet", - "data":{ + "init": { + "title": "Configure options for Owlet", + "data": { "pollinterval": "Polling interval in seconds, min 10" } } } + }, + "entity": { + "binary_sensor":{ + "charging": { + "name": "Charging" + }, + "high_hr_alrt":{ + "name": "High Heart Rate Alert" + }, + "low_hr_alrt":{ + "name":"Low Heart Rate Alert" + }, + "high_ox_alrt":{ + "name":"High Oxygen Alert" + }, + "low_ox_alrt":{ + "name":"Low Oxygen Alert" + }, + "low_batt_alrt":{ + "name": "Low Battery Alert" + }, + "lost_pwr_alrt":{ + "name": "Lost Power Alert" + }, + "sock_discon_alrt":{ + "name": "Sock Diconnected Alert" + }, + "sock_off":{ + "name":"sock_off" + }, + "awake":{ + "name":"Awake" + } + }, + "sensor": { + "batterypercent": { + "name": "Battery Percentage" + }, + "o2saturation": { + "name": "O2 Saturation" + }, + "o2saturation10a": { + "name": "O2 Saturation 10 Minute Average" + }, + "heartrate": { + "name": "Heart Rate" + }, + "batterymin": { + "name": "Battery Remaining" + }, + "signalstrength": { + "name": "Signal Strength" + }, + "skintemp": { + "name": "Skin Temperature" + }, + "sleepstate": { + "name": "Sleep State", + "state": { + "unknown": "Unknown", + "awake": "Awake", + "light_sleep": "Light Sleep", + "deep_sleep": "Deep Sleep" + } + } + } } -} \ No newline at end of file +} diff --git a/custom_components/owlet/translations/en.json b/custom_components/owlet/translations/en.json index f932c92..3cfee18 100644 --- a/custom_components/owlet/translations/en.json +++ b/custom_components/owlet/translations/en.json @@ -1,17 +1,17 @@ { "config": { "step": { - "user":{ + "user": { "title": "Enter login details", - "data":{ + "data": { "region": "Region", "username": "Email", "password": "Password" } }, - "reauth_confirm":{ + "reauth_confirm": { "title": "Reauthentiaction required for Owlet", - "data":{ + "data": { "password": "Password" } } @@ -20,20 +20,88 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_email": "Entered email address is incorrect", "invalid_password": "Entered password is incorrect", - "unknown": "[%key:common::config_flow::error::unknown%]" + "invalid_credentials": "Entered credentials are incorrect", + "unknown": "Unknown error occured" }, "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + "already_configured": "Device already configured", + "reauth_successful": "Reauthentication successful" } }, "options": { "step": { - "init":{ - "title":"Configure options for Owlet", - "data":{ + "init": { + "title": "Configure options for Owlet", + "data": { "pollinterval": "Polling interval in seconds, min 10" } } } + }, + "entity": { + "binary_sensor":{ + "charging": { + "name": "Charging" + }, + "high_hr_alrt":{ + "name": "High Heart Rate Alert" + }, + "low_hr_alrt":{ + "name":"Low Heart Rate Alert" + }, + "high_ox_alrt":{ + "name":"High Oxygen Alert" + }, + "low_ox_alrt":{ + "name":"Low Oxygen Alert" + }, + "low_batt_alrt":{ + "name": "Low Battery Alert" + }, + "lost_pwr_alrt":{ + "name": "Lost Power Alert" + }, + "sock_discon_alrt":{ + "name": "Sock Diconnected Alert" + }, + "sock_off":{ + "name":"sock_off" + }, + "awake":{ + "name":"Awake" + } + }, + "sensor": { + "batterypercent": { + "name": "Battery Percentage" + }, + "o2saturation": { + "name": "O2 Saturation" + }, + "o2saturation10a": { + "name": "O2 Saturation 10 Minute Average" + }, + "heartrate": { + "name": "Heart Rate" + }, + "batterymin": { + "name": "Battery Remaining" + }, + "signalstrength": { + "name": "Signal Strength" + }, + "skintemp": { + "name": "Skin Temperature" + }, + "sleepstate": { + "name": "Sleep State", + "state": { + "unknown": "Unknown", + "awake": "Awake", + "light_sleep": "Light Sleep", + "deep_sleep": "Deep Sleep" + } + } + } } -} \ No newline at end of file +} diff --git a/custom_components/owlet/translations/uk.json b/custom_components/owlet/translations/uk.json index f932c92..00843cf 100644 --- a/custom_components/owlet/translations/uk.json +++ b/custom_components/owlet/translations/uk.json @@ -1,17 +1,17 @@ { "config": { "step": { - "user":{ + "user": { "title": "Enter login details", - "data":{ + "data": { "region": "Region", "username": "Email", "password": "Password" } }, - "reauth_confirm":{ + "reauth_confirm": { "title": "Reauthentiaction required for Owlet", - "data":{ + "data": { "password": "Password" } } @@ -20,20 +20,88 @@ "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_email": "Entered email address is incorrect", "invalid_password": "Entered password is incorrect", - "unknown": "[%key:common::config_flow::error::unknown%]" + "invalid_credentials": "Entered credentials are incorrect", + "unknown": "Unknown error occured" }, "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + "already_configured": "Device already configured", + "reauth_successful": "Reauthentication successful" } }, "options": { "step": { - "init":{ - "title":"Configure options for Owlet", - "data":{ + "init": { + "title": "Configure options for Owlet", + "data": { "pollinterval": "Polling interval in seconds, min 10" } } } + }, + "entity": { + "binary_sensor":{ + "charging": { + "name": "Charging" + }, + "high_hr_alrt":{ + "name": "High Heart Rate Alert" + }, + "low_hr_alrt":{ + "name":"Low Heart Rate Alert" + }, + "high_ox_alrt":{ + "name":"High Oxygen Alert" + }, + "low_ox_alrt":{ + "name":"Low Oxygen Alert" + }, + "low_batt_alrt":{ + "name": "Low Battery Alert" + }, + "lost_pwr_alrt":{ + "name": "Lost Power Alert" + }, + "sock_discon_alrt":{ + "name": "Sock Diconnected Alert" + }, + "sock_off":{ + "name":"Sock Off" + }, + "awake":{ + "name":"Awake" + } + }, + "sensor": { + "batterypercent": { + "name": "Battery Percentage" + }, + "o2saturation": { + "name": "O2 Saturation" + }, + "o2saturation10a": { + "name": "O2 Saturation 10 Minute Average" + }, + "heartrate": { + "name": "Heart Rate" + }, + "batterymin": { + "name": "Battery Remaining" + }, + "signalstrength": { + "name": "Signal Strength" + }, + "skintemp": { + "name": "Skin Temperature" + }, + "sleepstate": { + "name": "Sleep State", + "state": { + "unknown": "Unknown", + "awake": "Awake", + "light_sleep": "Light Sleep", + "deep_sleep": "Deep Sleep" + } + } + } } -} \ No newline at end of file +} diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..5bacde9 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,60 @@ +"""Tests for the Owlet integration.""" +from __future__ import annotations + +import json +from unittest.mock import patch + +from homeassistant.components.owlet.const import ( + CONF_OWLET_EXPIRY, + CONF_OWLET_REFRESH, + DOMAIN, + POLLING_INTERVAL, +) +from homeassistant.const import ( + CONF_API_TOKEN, + CONF_REGION, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry, load_fixture + + +async def async_init_integration( + hass: HomeAssistant, + skip_setup: bool = False, + properties_fixture: str = "update_properties_charging.json", + devices_fixture: str = "get_devices.json", +) -> MockConfigEntry: + """Set up integration entry.""" + entry = MockConfigEntry( + domain=DOMAIN, + title="sample@gmail.com", + unique_id="sample@gmail.com", + data={ + CONF_REGION: "europe", + CONF_USERNAME: "sample@gmail.com", + CONF_API_TOKEN: "api_token", + CONF_OWLET_EXPIRY: 100, + CONF_OWLET_REFRESH: "refresh_token", + }, + options={CONF_SCAN_INTERVAL: POLLING_INTERVAL}, + ) + + entry.add_to_hass(hass) + + if not skip_setup: + with patch( + "homeassistant.components.owlet.OwletAPI.get_properties", + return_value=json.loads(load_fixture(properties_fixture, "owlet")), + ), patch( + "homeassistant.components.owlet.OwletAPI.authenticate", return_value=None + ), patch( + "homeassistant.components.owlet.OwletAPI.get_devices", + return_value=json.loads(load_fixture(devices_fixture, "owlet")), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + return entry diff --git a/tests/const.py b/tests/const.py new file mode 100644 index 0000000..ac53adc --- /dev/null +++ b/tests/const.py @@ -0,0 +1,14 @@ +"""Constants used for Owlet tests.""" + +AUTH_RETURN = { + "api_token": "api_token", + "expiry": 100, + "refresh": "refresh_token", +} + + +CONF_INPUT = { + "region": "europe", + "username": "sample@gmail.com", + "password": "sample", +} diff --git a/tests/fixtures/get_devices.json b/tests/fixtures/get_devices.json new file mode 100644 index 0000000..b84215a --- /dev/null +++ b/tests/fixtures/get_devices.json @@ -0,0 +1,32 @@ +{ + "response": [ + { + "device": { + "product_name": "Owlet Baby Monitors", + "model": "AY001MTL1", + "dsn": "SERIAL_NUMBER", + "oem_model": "SS3-OBL-EU", + "sw_version": "bc 2.9.7-beta 05/01/19 16:15:18 ID beb2858", + "template_id": 48775, + "mac": "MAC", + "unique_hardware_id": "None", + "hwsig": "123-123-123", + "lan_ip": "192.0.0.1", + "connected_at": "2023-05-23T01:21:29Z", + "key": 123456, + "lan_enabled": false, + "connection_priority": [], + "has_properties": true, + "product_class": "None", + "connection_status": "Online", + "lat": "0.0", + "lng": "0.0", + "locality": "QW12", + "device_type": "Wifi", + "dealer": "None", + "manuf_model": "LBEE5PA1LD-222" + } + } + ], + "tokens": "" +} diff --git a/tests/fixtures/get_devices_with_tokens.json b/tests/fixtures/get_devices_with_tokens.json new file mode 100644 index 0000000..c216f1d --- /dev/null +++ b/tests/fixtures/get_devices_with_tokens.json @@ -0,0 +1,36 @@ +{ + "response": [ + { + "device": { + "product_name": "Owlet Baby Monitors", + "model": "AY001MTL1", + "dsn": "SERIAL_NUMBER", + "oem_model": "SS3-OBL-EU", + "sw_version": "bc 2.9.7-beta 05/01/19 16:15:18 ID beb2858", + "template_id": 48775, + "mac": "MAC", + "unique_hardware_id": "None", + "hwsig": "123-123-123", + "lan_ip": "192.0.0.1", + "connected_at": "2023-05-23T01:21:29Z", + "key": 123456, + "lan_enabled": false, + "connection_priority": [], + "has_properties": true, + "product_class": "None", + "connection_status": "Online", + "lat": "0.0", + "lng": "0.0", + "locality": "QW12", + "device_type": "Wifi", + "dealer": "None", + "manuf_model": "LBEE5PA1LD-222" + } + } + ], + "tokens": { + "api_token": "new_api_token", + "expiry": 200, + "refresh": "new_refresh_token" + } +} diff --git a/tests/fixtures/update_properties_asleep.json b/tests/fixtures/update_properties_asleep.json new file mode 100644 index 0000000..7450628 --- /dev/null +++ b/tests/fixtures/update_properties_asleep.json @@ -0,0 +1,1051 @@ +{ + "response": { + "ALRT_PAUSE_CMD": { + "type": "Property", + "name": "ALRT_PAUSE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-22T05:53:42Z", + "key": 108578717, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Alert Pause Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1684734822}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_ACTIVE": { + "type": "Property", + "name": "APP_ACTIVE", + "base_type": "boolean", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:54Z", + "key": 108578718, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "App Active", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_CMD_REQUEST": { + "type": "Property", + "name": "APP_CMD_REQUEST", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 570656602, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Request", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "APP_CMD_RESPONSE": { + "type": "Property", + "name": "APP_CMD_RESPONSE", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:46Z", + "key": 570656603, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Response", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_ERROR_LOG_FILE": { + "type": "Property", + "name": "BASE_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-03-04T09:31:36Z", + "key": 108578750, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/BASE_ERROR_LOG_FILE/datapoints/5c1df4b4-ba6f-11ed-cffb-a502331c1269.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_EVT_LOG_FILE": { + "type": "Property", + "name": "BASE_EVT_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578751, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Event Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "BASE_STATION_ON_CMD": { + "type": "Property", + "name": "BASE_STATION_ON_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-04-17T18:35:15Z", + "key": 108578719, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Base Station On Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1681756516, \"val\":\"false\"}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "CONFIG_STATUS": { + "type": "Property", + "name": "CONFIG_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578722, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Config Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"smac\":\"D0ECE231F766\",\"bmac\":\"F832C96E47EF\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DEVICE_PING": { + "type": "Property", + "name": "DEVICE_PING", + "base_type": "integer", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578723, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Device Ping", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DISCOMFORT_ALRT": { + "type": "Property", + "name": "DISCOMFORT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 153127355, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Discomfort Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "FW_UPDATE_STATUS": { + "type": "Property", + "name": "FW_UPDATE_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:51Z", + "key": 108578724, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Firmware Update Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"primary\":\"IDLE\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_HR_ALRT": { + "type": "Property", + "name": "HIGH_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578725, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_OX_ALRT": { + "type": "Property", + "name": "HIGH_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578726, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOST_POWER_ALRT": { + "type": "Property", + "name": "LOST_POWER_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 570656604, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Lost Power Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_BATT_ALRT": { + "type": "Property", + "name": "LOW_BATT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T07:02:17Z", + "key": 108578727, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Battery Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_HR_ALRT": { + "type": "Property", + "name": "LOW_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:35Z", + "key": 108578728, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_INTEG_READ": { + "type": "Property", + "name": "LOW_INTEG_READ", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578729, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Integrity Read", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_OX_ALRT": { + "type": "Property", + "name": "LOW_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578730, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_POWER_MODE_CMD": { + "type": "Property", + "name": "LOW_POWER_MODE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578747, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Low Power Mode Cmd", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MISC_LOG_FILE_DATA": { + "type": "Property", + "name": "MISC_LOG_FILE_DATA", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578731, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Misc Log File Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MONITORING_SUMMARY": { + "type": "Property", + "name": "MONITORING_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:11:16Z", + "key": 108578745, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Monitoring Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAALHQiosbijBiDYBDgg", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_base_version": { + "type": "Property", + "name": "oem_base_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578732, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_base_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.8.0.0-6ede9d9\",\"hw\":\"obl\",\"rev\":2,\"sd\":\"6.1.1\",\"bl\":\"0.7.34.0-3e109b0\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_flash_version": { + "type": "Property", + "name": "oem_flash_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578733, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_flash_version", + "host_sw_version": true, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "B3.8.0-6ede_S3.5.0-efc7_BB0.7.34_SB0.7.33_SD6.1.1", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": "None", + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_sock_version": { + "type": "Property", + "name": "oem_sock_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578734, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_sock_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.5.0.0-efc769f\",\"sd\":\"6.1.1\",\"bl\":\"0.7.33.0-3e109b0\",\"ext app\":\"3.5.0.0-efc769f\",\"hw\":\"oss\",\"rev\":2}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PPG_LOG_FILE": { + "type": "Property", + "name": "PPG_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-13T18:28:52Z", + "key": 108578748, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "PPG Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/PPG_LOG_FILE/datapoints/03320aaa-f1bc-11ed-e173-af5dc3b72e51.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_DRM_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_DRM_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 570656605, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Preview Dream Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_HIGH_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_HIGH_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578735, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview High Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_LOW_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_LOW_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:39Z", + "key": 108578736, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Low Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_MED_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_MED_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578737, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Med Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "REAL_TIME_VITALS": { + "type": "Property", + "name": "REAL_TIME_VITALS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:50Z", + "key": 108578738, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Real-Time Vitals", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ox\":99,\"hr\":97,\"mv\":0,\"sc\":2,\"st\":34,\"bso\":1,\"bat\":50,\"btt\":400,\"chg\":0,\"aps\":0,\"alrt\":0,\"ota\":0,\"srf\":1,\"rsi\":30,\"sb\":0,\"ss\":8,\"mvb\":0,\"mst\":0,\"oxta\":97,\"onm\":0,\"bsb\":4,\"hw\":\"obl\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "RED_ALERT_SUMMARY": { + "type": "Property", + "name": "RED_ALERT_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2022-11-28T07:46:24Z", + "key": 108578746, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Red Alert Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAHH7mOEY8xaAJlRCAYAq1IwBgCvXgIGAJxhJAYApmICBgCRYwAGAI9jAAYAjWMBBgCUYwUGAJdkMwYAAAAAAgAAAAACAAAAAAIAjWIABgCOYwEGAI9jAAYAjGIBBgCSYgEGAJZiFgYAtWQTBgC5YhEGALBgHAYAr2ETBgCqYQcGAI1hAAYAimICBgCKYgwGAIFiAAYAfGIABgCNYgYGAHdiAAYAiWIABgCFYgAGAItiAAYAjWEABgCLYAAGAIxhAAYAi2EDBgCMXwAGAI9fAQYAj2AABgCNYAAGAIJgAAYAjWAABgCNYAAGAI5gAQYAhF0hBgCrYCkGAAAAAAIAAAAAAgAAAAACAJZhAAYAiGIABgCDYgAGAH1jAAYAgmMABgB9YgAGAIRiAAYAgmEABgCGYQAGAIhiAAYAiGEABgCIYQAGAIZhAAYAiWEABgCJYQAGAIphAAYAimEABgCHYQAGAIthAAYAiGEABgCLYQAGAIlhAAYAiWEABgCIYQAGAIphAAYAiGEABgCLYQAGAIphAAYAi2EABgCLYQAGAIlhAAYAi2EABgCJYQAGAIdhAAYAiGEABgCIYQAGAIphAAYAimAGBgCAXwAG", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SENSOR_ERROR_LOG_FILE": { + "type": "Property", + "name": "SENSOR_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-21T20:01:28Z", + "key": 108578749, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sensor Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/SENSOR_ERROR_LOG_FILE/datapoints/4632dc1a-f812-11ed-e756-e8ae54d79c54.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SETTINGS_CMD": { + "type": "Property", + "name": "SETTINGS_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578739, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "SETTINGS_STATUS": { + "type": "Property", + "name": "SETTINGS_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578740, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"settings\":{}}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_DISCON_ALRT": { + "type": "Property", + "name": "SOCK_DISCON_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578741, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Disconnect Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_OFF": { + "type": "Property", + "name": "SOCK_OFF", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T17:46:50Z", + "key": 108578742, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Off", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "VITALS_LOG_DATA": { + "type": "Property", + "name": "VITALS_LOG_DATA", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578743, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Vitals Log Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "VITALS_LOG_FILE": { + "type": "Property", + "name": "VITALS_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-04-24T14:36:16Z", + "key": 108578744, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Vitals Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/VITALS_LOG_FILE/datapoints/5f08a91a-e2ad-11ed-8a87-6d985612e27c.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + } + }, + "tokens": "" +} diff --git a/tests/fixtures/update_properties_awake.json b/tests/fixtures/update_properties_awake.json new file mode 100644 index 0000000..e82f0cb --- /dev/null +++ b/tests/fixtures/update_properties_awake.json @@ -0,0 +1,1051 @@ +{ + "response": { + "ALRT_PAUSE_CMD": { + "type": "Property", + "name": "ALRT_PAUSE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-22T05:53:42Z", + "key": 108578717, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Alert Pause Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1684734822}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_ACTIVE": { + "type": "Property", + "name": "APP_ACTIVE", + "base_type": "boolean", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:54Z", + "key": 108578718, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "App Active", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_CMD_REQUEST": { + "type": "Property", + "name": "APP_CMD_REQUEST", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 570656602, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Request", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "APP_CMD_RESPONSE": { + "type": "Property", + "name": "APP_CMD_RESPONSE", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:46Z", + "key": 570656603, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Response", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_ERROR_LOG_FILE": { + "type": "Property", + "name": "BASE_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-03-04T09:31:36Z", + "key": 108578750, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/BASE_ERROR_LOG_FILE/datapoints/5c1df4b4-ba6f-11ed-cffb-a502331c1269.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_EVT_LOG_FILE": { + "type": "Property", + "name": "BASE_EVT_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578751, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Event Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "BASE_STATION_ON_CMD": { + "type": "Property", + "name": "BASE_STATION_ON_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-04-17T18:35:15Z", + "key": 108578719, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Base Station On Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1681756516, \"val\":\"false\"}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "CONFIG_STATUS": { + "type": "Property", + "name": "CONFIG_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578722, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Config Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"smac\":\"D0ECE231F766\",\"bmac\":\"F832C96E47EF\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DEVICE_PING": { + "type": "Property", + "name": "DEVICE_PING", + "base_type": "integer", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578723, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Device Ping", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DISCOMFORT_ALRT": { + "type": "Property", + "name": "DISCOMFORT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 153127355, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Discomfort Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "FW_UPDATE_STATUS": { + "type": "Property", + "name": "FW_UPDATE_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:51Z", + "key": 108578724, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Firmware Update Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"primary\":\"IDLE\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_HR_ALRT": { + "type": "Property", + "name": "HIGH_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578725, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_OX_ALRT": { + "type": "Property", + "name": "HIGH_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578726, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOST_POWER_ALRT": { + "type": "Property", + "name": "LOST_POWER_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 570656604, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Lost Power Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_BATT_ALRT": { + "type": "Property", + "name": "LOW_BATT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T07:02:17Z", + "key": 108578727, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Battery Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_HR_ALRT": { + "type": "Property", + "name": "LOW_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:35Z", + "key": 108578728, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_INTEG_READ": { + "type": "Property", + "name": "LOW_INTEG_READ", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578729, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Integrity Read", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_OX_ALRT": { + "type": "Property", + "name": "LOW_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578730, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_POWER_MODE_CMD": { + "type": "Property", + "name": "LOW_POWER_MODE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578747, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Low Power Mode Cmd", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MISC_LOG_FILE_DATA": { + "type": "Property", + "name": "MISC_LOG_FILE_DATA", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578731, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Misc Log File Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MONITORING_SUMMARY": { + "type": "Property", + "name": "MONITORING_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:11:16Z", + "key": 108578745, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Monitoring Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAALHQiosbijBiDYBDgg", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_base_version": { + "type": "Property", + "name": "oem_base_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578732, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_base_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.8.0.0-6ede9d9\",\"hw\":\"obl\",\"rev\":2,\"sd\":\"6.1.1\",\"bl\":\"0.7.34.0-3e109b0\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_flash_version": { + "type": "Property", + "name": "oem_flash_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578733, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_flash_version", + "host_sw_version": true, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "B3.8.0-6ede_S3.5.0-efc7_BB0.7.34_SB0.7.33_SD6.1.1", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": "None", + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_sock_version": { + "type": "Property", + "name": "oem_sock_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578734, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_sock_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.5.0.0-efc769f\",\"sd\":\"6.1.1\",\"bl\":\"0.7.33.0-3e109b0\",\"ext app\":\"3.5.0.0-efc769f\",\"hw\":\"oss\",\"rev\":2}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PPG_LOG_FILE": { + "type": "Property", + "name": "PPG_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-13T18:28:52Z", + "key": 108578748, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "PPG Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/PPG_LOG_FILE/datapoints/03320aaa-f1bc-11ed-e173-af5dc3b72e51.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_DRM_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_DRM_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 570656605, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Preview Dream Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_HIGH_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_HIGH_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578735, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview High Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_LOW_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_LOW_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:39Z", + "key": 108578736, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Low Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_MED_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_MED_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578737, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Med Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "REAL_TIME_VITALS": { + "type": "Property", + "name": "REAL_TIME_VITALS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:50Z", + "key": 108578738, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Real-Time Vitals", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ox\":98,\"hr\":110,\"mv\":1,\"sc\":2,\"st\":35,\"bso\":1,\"bat\":80,\"btt\":600,\"chg\":0,\"aps\":0,\"alrt\":0,\"ota\":0,\"srf\":1,\"rsi\":34,\"sb\":0,\"ss\":1,\"mvb\":0,\"mst\":0,\"oxta\":98,\"onm\":0,\"bsb\":4,\"hw\":\"obl\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "RED_ALERT_SUMMARY": { + "type": "Property", + "name": "RED_ALERT_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2022-11-28T07:46:24Z", + "key": 108578746, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Red Alert Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAHH7mOEY8xaAJlRCAYAq1IwBgCvXgIGAJxhJAYApmICBgCRYwAGAI9jAAYAjWMBBgCUYwUGAJdkMwYAAAAAAgAAAAACAAAAAAIAjWIABgCOYwEGAI9jAAYAjGIBBgCSYgEGAJZiFgYAtWQTBgC5YhEGALBgHAYAr2ETBgCqYQcGAI1hAAYAimICBgCKYgwGAIFiAAYAfGIABgCNYgYGAHdiAAYAiWIABgCFYgAGAItiAAYAjWEABgCLYAAGAIxhAAYAi2EDBgCMXwAGAI9fAQYAj2AABgCNYAAGAIJgAAYAjWAABgCNYAAGAI5gAQYAhF0hBgCrYCkGAAAAAAIAAAAAAgAAAAACAJZhAAYAiGIABgCDYgAGAH1jAAYAgmMABgB9YgAGAIRiAAYAgmEABgCGYQAGAIhiAAYAiGEABgCIYQAGAIZhAAYAiWEABgCJYQAGAIphAAYAimEABgCHYQAGAIthAAYAiGEABgCLYQAGAIlhAAYAiWEABgCIYQAGAIphAAYAiGEABgCLYQAGAIphAAYAi2EABgCLYQAGAIlhAAYAi2EABgCJYQAGAIdhAAYAiGEABgCIYQAGAIphAAYAimAGBgCAXwAG", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SENSOR_ERROR_LOG_FILE": { + "type": "Property", + "name": "SENSOR_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-21T20:01:28Z", + "key": 108578749, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sensor Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/SENSOR_ERROR_LOG_FILE/datapoints/4632dc1a-f812-11ed-e756-e8ae54d79c54.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SETTINGS_CMD": { + "type": "Property", + "name": "SETTINGS_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578739, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "SETTINGS_STATUS": { + "type": "Property", + "name": "SETTINGS_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578740, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"settings\":{}}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_DISCON_ALRT": { + "type": "Property", + "name": "SOCK_DISCON_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578741, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Disconnect Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_OFF": { + "type": "Property", + "name": "SOCK_OFF", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T17:46:50Z", + "key": 108578742, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Off", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "VITALS_LOG_DATA": { + "type": "Property", + "name": "VITALS_LOG_DATA", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578743, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Vitals Log Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "VITALS_LOG_FILE": { + "type": "Property", + "name": "VITALS_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-04-24T14:36:16Z", + "key": 108578744, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Vitals Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/VITALS_LOG_FILE/datapoints/5f08a91a-e2ad-11ed-8a87-6d985612e27c.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + } + }, + "tokens": "" +} diff --git a/tests/fixtures/update_properties_charging.json b/tests/fixtures/update_properties_charging.json new file mode 100644 index 0000000..e818eac --- /dev/null +++ b/tests/fixtures/update_properties_charging.json @@ -0,0 +1,1055 @@ +{ + "response": { + "ALRT_PAUSE_CMD": { + "type": "Property", + "name": "ALRT_PAUSE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-22T05:53:42Z", + "key": 108578717, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Alert Pause Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1684734822}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_ACTIVE": { + "type": "Property", + "name": "APP_ACTIVE", + "base_type": "boolean", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:54Z", + "key": 108578718, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "App Active", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 1, + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "APP_CMD_REQUEST": { + "type": "Property", + "name": "APP_CMD_REQUEST", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 570656602, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Request", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "APP_CMD_RESPONSE": { + "type": "Property", + "name": "APP_CMD_RESPONSE", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:46Z", + "key": 570656603, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "App Command Response", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_ERROR_LOG_FILE": { + "type": "Property", + "name": "BASE_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-03-04T09:31:36Z", + "key": 108578750, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/BASE_ERROR_LOG_FILE/datapoints/5c1df4b4-ba6f-11ed-cffb-a502331c1269.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "BASE_EVT_LOG_FILE": { + "type": "Property", + "name": "BASE_EVT_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578751, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Base Event Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "BASE_STATION_ON_CMD": { + "type": "Property", + "name": "BASE_STATION_ON_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-04-17T18:35:15Z", + "key": 108578719, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Base Station On Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ts\":1681756516, \"val\":\"false\"}", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "CONFIG_STATUS": { + "type": "Property", + "name": "CONFIG_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578722, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Config Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"smac\":\"D0ECE231F766\",\"bmac\":\"F832C96E47EF\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DEVICE_PING": { + "type": "Property", + "name": "DEVICE_PING", + "base_type": "integer", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578723, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Device Ping", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "DISCOMFORT_ALRT": { + "type": "Property", + "name": "DISCOMFORT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 153127355, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Discomfort Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "FW_UPDATE_STATUS": { + "type": "Property", + "name": "FW_UPDATE_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:51Z", + "key": 108578724, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Firmware Update Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"primary\":\"IDLE\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_HR_ALRT": { + "type": "Property", + "name": "HIGH_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578725, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "HIGH_OX_ALRT": { + "type": "Property", + "name": "HIGH_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578726, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "High Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOST_POWER_ALRT": { + "type": "Property", + "name": "LOST_POWER_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 570656604, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Lost Power Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_BATT_ALRT": { + "type": "Property", + "name": "LOW_BATT_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T07:02:17Z", + "key": 108578727, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Battery Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_HR_ALRT": { + "type": "Property", + "name": "LOW_HR_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:35Z", + "key": 108578728, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low HR Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_INTEG_READ": { + "type": "Property", + "name": "LOW_INTEG_READ", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578729, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Integrity Read", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_OX_ALRT": { + "type": "Property", + "name": "LOW_OX_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:36Z", + "key": 108578730, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Low Oxygen Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "LOW_POWER_MODE_CMD": { + "type": "Property", + "name": "LOW_POWER_MODE_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578747, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Low Power Mode Cmd", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MISC_LOG_FILE_DATA": { + "type": "Property", + "name": "MISC_LOG_FILE_DATA", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578731, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Misc Log File Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "MONITORING_SUMMARY": { + "type": "Property", + "name": "MONITORING_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:11:16Z", + "key": 108578745, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Monitoring Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAALHQiosbijBiDYBDgg", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_base_version": { + "type": "Property", + "name": "oem_base_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578732, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_base_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.8.0.0-6ede9d9\",\"hw\":\"obl\",\"rev\":2,\"sd\":\"6.1.1\",\"bl\":\"0.7.34.0-3e109b0\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_flash_version": { + "type": "Property", + "name": "oem_flash_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578733, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_flash_version", + "host_sw_version": true, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "B3.8.0-6ede_S3.5.0-efc7_BB0.7.34_SB0.7.33_SD6.1.1", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": "None", + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "oem_sock_version": { + "type": "Property", + "name": "oem_sock_version", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 108578734, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "oem_sock_version", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"app\":\"3.5.0.0-efc769f\",\"sd\":\"6.1.1\",\"bl\":\"0.7.33.0-3e109b0\",\"ext app\":\"3.5.0.0-efc769f\",\"hw\":\"oss\",\"rev\":2}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PPG_LOG_FILE": { + "type": "Property", + "name": "PPG_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-13T18:28:52Z", + "key": 108578748, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "PPG Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/PPG_LOG_FILE/datapoints/03320aaa-f1bc-11ed-e173-af5dc3b72e51.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_DRM_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_DRM_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:40Z", + "key": 570656605, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Preview Dream Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_HIGH_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_HIGH_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578735, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview High Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_LOW_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_LOW_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:39Z", + "key": 108578736, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Low Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "PREVIEW_MED_PRIORITY_ALARM": { + "type": "Property", + "name": "PREVIEW_MED_PRIORITY_ALARM", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:38Z", + "key": 108578737, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Preview Med Priority Alarm", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "REAL_TIME_VITALS": { + "type": "Property", + "name": "REAL_TIME_VITALS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-24T14:15:50Z", + "key": 108578738, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Real-Time Vitals", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"ox\":0,\"hr\":0,\"mv\":0,\"sc\":2,\"st\":0,\"bso\":0,\"bat\":100,\"btt\":0,\"chg\":2,\"aps\":0,\"alrt\":0,\"ota\":0,\"srf\":1,\"rsi\":34,\"sb\":0,\"ss\":0,\"mvb\":0,\"mst\":0,\"oxta\":255,\"onm\":0,\"bsb\":4,\"hw\":\"obl\"}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "RED_ALERT_SUMMARY": { + "type": "Property", + "name": "RED_ALERT_SUMMARY", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2022-11-28T07:46:24Z", + "key": 108578746, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Red Alert Summary", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "AAHH7mOEY8xaAJlRCAYAq1IwBgCvXgIGAJxhJAYApmICBgCRYwAGAI9jAAYAjWMBBgCUYwUGAJdkMwYAAAAAAgAAAAACAAAAAAIAjWIABgCOYwEGAI9jAAYAjGIBBgCSYgEGAJZiFgYAtWQTBgC5YhEGALBgHAYAr2ETBgCqYQcGAI1hAAYAimICBgCKYgwGAIFiAAYAfGIABgCNYgYGAHdiAAYAiWIABgCFYgAGAItiAAYAjWEABgCLYAAGAIxhAAYAi2EDBgCMXwAGAI9fAQYAj2AABgCNYAAGAIJgAAYAjWAABgCNYAAGAI5gAQYAhF0hBgCrYCkGAAAAAAIAAAAAAgAAAAACAJZhAAYAiGIABgCDYgAGAH1jAAYAgmMABgB9YgAGAIRiAAYAgmEABgCGYQAGAIhiAAYAiGEABgCIYQAGAIZhAAYAiWEABgCJYQAGAIphAAYAimEABgCHYQAGAIthAAYAiGEABgCLYQAGAIlhAAYAiWEABgCIYQAGAIphAAYAiGEABgCLYQAGAIphAAYAi2EABgCLYQAGAIlhAAYAi2EABgCJYQAGAIdhAAYAiGEABgCIYQAGAIphAAYAimAGBgCAXwAG", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SENSOR_ERROR_LOG_FILE": { + "type": "Property", + "name": "SENSOR_ERROR_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-21T20:01:28Z", + "key": 108578749, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sensor Error Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/SENSOR_ERROR_LOG_FILE/datapoints/4632dc1a-f812-11ed-e756-e8ae54d79c54.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SETTINGS_CMD": { + "type": "Property", + "name": "SETTINGS_CMD", + "base_type": "string", + "read_only": false, + "direction": "input", + "scope": "user", + "data_updated_at": "null", + "key": 108578739, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Command", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "SETTINGS_STATUS": { + "type": "Property", + "name": "SETTINGS_STATUS", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:41Z", + "key": 108578740, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Settings Status", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "{\"settings\":{}}", + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_DISCON_ALRT": { + "type": "Property", + "name": "SOCK_DISCON_ALRT", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T01:21:37Z", + "key": 108578741, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Disconnect Alert", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "SOCK_OFF": { + "type": "Property", + "name": "SOCK_OFF", + "base_type": "boolean", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-05-23T17:46:50Z", + "key": 108578742, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Sock Off", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": 0, + "generated_from": "AYLA::device", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + }, + "VITALS_LOG_DATA": { + "type": "Property", + "name": "VITALS_LOG_DATA", + "base_type": "string", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "null", + "key": 108578743, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": true, + "display_name": "Vitals Log Data", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "None", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30 + }, + "VITALS_LOG_FILE": { + "type": "Property", + "name": "VITALS_LOG_FILE", + "base_type": "file", + "read_only": true, + "direction": "output", + "scope": "user", + "data_updated_at": "2023-04-24T14:36:16Z", + "key": 108578744, + "device_key": 1234567, + "product_name": "Owlet Baby Monitors", + "track_only_changes": false, + "display_name": "Vitals Log File", + "host_sw_version": false, + "time_series": false, + "derived": false, + "app_type": "None", + "recipe": "None", + "value": "https://ads-field-eu.aylanetworks.com/apiv1/devices/1234567/properties/VITALS_LOG_FILE/datapoints/5f08a91a-e2ad-11ed-8a87-6d985612e27c.json", + "generated_from": "None", + "generated_at": "None", + "denied_roles": [], + "ack_enabled": false, + "retention_days": 30, + "ack_status": "None", + "ack_message": "None", + "acked_at": "None" + } + }, + "tokens": { + "api_token": "new_api_token", + "expiry": 200, + "refresh": "new_refresh_token" + } +} diff --git a/tests/test_config_flow.py b/tests/test_config_flow.py new file mode 100644 index 0000000..07ffa7d --- /dev/null +++ b/tests/test_config_flow.py @@ -0,0 +1,237 @@ +"""Test Owlet config flow.""" +from __future__ import annotations + +from unittest.mock import patch + +from pyowletapi.exceptions import ( + OwletCredentialsError, + OwletDevicesError, + OwletEmailError, + OwletPasswordError, +) + +from homeassistant import config_entries +from homeassistant.components.owlet.const import DOMAIN, POLLING_INTERVAL +from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER +from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResultType + +from . import async_init_integration +from .const import AUTH_RETURN, CONF_INPUT + + +async def test_form(hass: HomeAssistant) -> None: + """Test that the form is served with no input.""" + # await async_init_integration(hass) + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + return_value=AUTH_RETURN, + ), patch( + "homeassistant.components.owlet.config_flow.OwletAPI.validate_authentication" + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["title"] == "sample@gmail.com" + assert result["data"] == { + "region": "europe", + "username": "sample@gmail.com", + "api_token": "api_token", + "expiry": 100, + "refresh": "refresh_token", + } + assert result["options"] == {"scan_interval": POLLING_INTERVAL} + + +async def test_flow_wrong_password(hass: HomeAssistant) -> None: + """Test incorrect login throwing error.""" + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=OwletPasswordError(), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "invalid_password"} + + +async def test_flow_wrong_email(hass: HomeAssistant) -> None: + """Test incorrect login throwing error.""" + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=OwletEmailError(), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "invalid_email"} + + +async def test_flow_credentials_error(hass: HomeAssistant) -> None: + """Test incorrect login throwing error.""" + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=OwletCredentialsError(), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "invalid_credentials"} + + +async def test_flow_unknown_error(hass: HomeAssistant) -> None: + """Test unknown error throwing error.""" + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=Exception(), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "unknown"} + + +async def test_flow_no_devices(hass: HomeAssistant) -> None: + """Test unknown error throwing error.""" + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate" + ), patch( + "homeassistant.components.owlet.config_flow.OwletAPI.validate_authentication", + side_effect=OwletDevicesError(), + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input=CONF_INPUT, + ) + assert result["type"] == FlowResultType.FORM + assert result["errors"] == {"base": "no_devices"} + + +async def test_reauth_success(hass: HomeAssistant) -> None: + """Test reauth form.""" + + entry = await async_init_integration(hass, skip_setup=True) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_REAUTH, "entry_id": entry.entry_id} + ) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + return_value=AUTH_RETURN, + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={CONF_PASSWORD: "sample"}, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.ABORT + assert result["reason"] == "reauth_successful" + + await hass.config_entries.async_unload(entry.entry_id) + + +async def test_reauth_invalid_password(hass: HomeAssistant) -> None: + """Test reauth with invalid password errir.""" + entry = await async_init_integration(hass, skip_setup=True) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_REAUTH, "entry_id": entry.entry_id} + ) + + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=OwletPasswordError(), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={CONF_PASSWORD: "sample"} + ) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + assert result["errors"] == {"base": "invalid_password"} + + +async def test_reauth_unknown_error(hass: HomeAssistant) -> None: + """Test reauthing with an unknown error.""" + + entry = await async_init_integration(hass, skip_setup=True) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_REAUTH, "entry_id": entry.entry_id} + ) + + with patch( + "homeassistant.components.owlet.config_flow.OwletAPI.authenticate", + side_effect=Exception(), + ): + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={CONF_PASSWORD: "sample"} + ) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "reauth_confirm" + + +async def test_options_flow(hass: HomeAssistant) -> None: + """Test that the form is served with no input.""" + entry = await async_init_integration(hass, skip_setup=True) + + result = await hass.config_entries.options.async_init(entry.entry_id) + + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "init" + + result = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={CONF_SCAN_INTERVAL: 10}, + ) + await hass.async_block_till_done() + + assert result["type"] == FlowResultType.CREATE_ENTRY + assert result["title"] == "" + assert result["data"] == {CONF_SCAN_INTERVAL: 10} diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py new file mode 100644 index 0000000..97a470d --- /dev/null +++ b/tests/test_coordinator.py @@ -0,0 +1,74 @@ +"""Test owlet coordinator.""" +from __future__ import annotations + +import json +from unittest.mock import patch + +from pyowletapi.exceptions import OwletAuthenticationError, OwletConnectionError + +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant + +from . import async_init_integration + +from tests.common import load_fixture + +PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] + + +async def test_coordinator_auth_error(hass: HomeAssistant) -> None: + """Test coordinator setup authentication error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.Sock.update_properties", + side_effect=OwletAuthenticationError(), + ), patch( + "homeassistant.components.owlet.OwletAPI.authenticate", return_value=None + ), patch( + "homeassistant.components.owlet.OwletAPI.get_devices", + return_value=json.loads(load_fixture("get_devices.json", "owlet")), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_RETRY + + +async def test_coordinator_connection_error(hass: HomeAssistant) -> None: + """Test coordinator setup connection error error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.Sock.update_properties", + side_effect=OwletConnectionError(), + ), patch( + "homeassistant.components.owlet.OwletAPI.authenticate", return_value=None + ), patch( + "homeassistant.components.owlet.OwletAPI.get_devices", + return_value=json.loads(load_fixture("get_devices.json", "owlet")), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_RETRY + + +async def test_coordinator_error(hass: HomeAssistant) -> None: + """Test coordinator setup generic error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.Sock.update_properties", + side_effect=Exception(), + ), patch( + "homeassistant.components.owlet.OwletAPI.authenticate", return_value=None + ), patch( + "homeassistant.components.owlet.OwletAPI.get_devices", + return_value=json.loads(load_fixture("get_devices.json", "owlet")), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_RETRY diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..9ee5462 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,136 @@ +"""Test Owlet init.""" +from __future__ import annotations + +from unittest.mock import patch + +from pyowletapi.exceptions import ( + OwletAuthenticationError, + OwletConnectionError, + OwletDevicesError, + OwletError, +) + +from homeassistant.components.owlet.const import ( + CONF_OWLET_EXPIRY, + CONF_OWLET_REFRESH, + DOMAIN, +) +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import CONF_API_TOKEN, CONF_REGION, CONF_USERNAME, Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er + +from . import async_init_integration + +PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR] + + +async def test_async_setup_entry(hass: HomeAssistant) -> None: + """Test setting up entry.""" + entry = await async_init_integration(hass) + + assert entry.state == ConfigEntryState.LOADED + + device_registry = dr.async_get(hass) + + device_entry = device_registry.async_get_or_create( + config_entry_id=entry.entry_id, identifiers={(DOMAIN, "SERIAL_NUMBER")} + ) + + assert device_entry.name == "Owlet Baby Care Sock" + + entity_registry = er.async_get(hass) + + entities = er.async_entries_for_device(entity_registry, device_entry.id) + + assert len(entities) == 8 + + await entry.async_unload(hass) + + assert entry.state == ConfigEntryState.NOT_LOADED + + +async def test_async_setup_entry_new_tokens(hass: HomeAssistant) -> None: + """Test setting up entry and getting new tokens.""" + entry = await async_init_integration( + hass, devices_fixture="get_devices_with_tokens.json" + ) + + assert entry.data == { + CONF_REGION: "europe", + CONF_USERNAME: "sample@gmail.com", + CONF_API_TOKEN: "new_api_token", + CONF_OWLET_EXPIRY: 200, + CONF_OWLET_REFRESH: "new_refresh_token", + } + + assert entry.state == ConfigEntryState.LOADED + + await entry.async_unload(hass) + + assert entry.state == ConfigEntryState.NOT_LOADED + + +async def test_async_setup_entry_auth_error(hass: HomeAssistant) -> None: + """Test setting up entry with auth error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.OwletAPI.authenticate", + side_effect=OwletAuthenticationError(), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_ERROR + + await entry.async_unload(hass) + + +async def test_async_setup_entry_connection_error(hass: HomeAssistant) -> None: + """Test setting up entry with connection error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.OwletAPI.authenticate", + side_effect=OwletConnectionError(), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_RETRY + + await entry.async_unload(hass) + + +async def test_async_setup_entry_devices_error(hass: HomeAssistant) -> None: + """Test setting up entry with device error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.OwletAPI.authenticate", return_value=None + ), patch( + "homeassistant.components.owlet.OwletAPI.get_devices", + side_effect=OwletDevicesError(), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_ERROR + await entry.async_unload(hass) + + +async def test_async_setup_entry_error(hass: HomeAssistant) -> None: + """Test setting up entry with unknown error.""" + entry = await async_init_integration(hass, skip_setup=True) + + with patch( + "homeassistant.components.owlet.OwletAPI.authenticate", + side_effect=OwletError(), + ): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + assert entry.state == ConfigEntryState.SETUP_ERROR + + await entry.async_unload(hass) diff --git a/tests/test_sensor.py b/tests/test_sensor.py new file mode 100644 index 0000000..fb9475e --- /dev/null +++ b/tests/test_sensor.py @@ -0,0 +1,109 @@ +"""Test Owlet Sensor.""" +from __future__ import annotations + +from homeassistant.core import HomeAssistant + +from . import async_init_integration + + +async def test_sensors_asleep(hass: HomeAssistant) -> None: + """Test sensor values.""" + await async_init_integration( + hass, properties_fixture="update_properties_asleep.json" + ) + + assert len(hass.states.async_all("sensor")) == 8 + + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_percentage").state + == "50.0" + ) + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_remaining").state + == "400.0" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_heart_rate").state == "97.0" + assert hass.states.get("sensor.owlet_baby_care_sock_o2_saturation").state == "99.0" + assert ( + hass.states.get( + "sensor.owlet_baby_care_sock_o2_saturation_10_minute_average" + ).state + == "97.0" + ) + + assert ( + hass.states.get("sensor.owlet_baby_care_sock_signal_strength").state == "30.0" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_skin_temperature").state == "34" + assert ( + hass.states.get("sensor.owlet_baby_care_sock_sleep_state").state + == "light_sleep" + ) + + +async def test_sensors_awake(hass: HomeAssistant) -> None: + """Test sensor values.""" + await async_init_integration( + hass, properties_fixture="update_properties_awake.json" + ) + + assert len(hass.states.async_all("sensor")) == 8 + + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_percentage").state + == "80.0" + ) + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_remaining").state + == "600.0" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_heart_rate").state == "110.0" + assert hass.states.get("sensor.owlet_baby_care_sock_o2_saturation").state == "98.0" + assert ( + hass.states.get( + "sensor.owlet_baby_care_sock_o2_saturation_10_minute_average" + ).state + == "98.0" + ) + assert ( + hass.states.get("sensor.owlet_baby_care_sock_signal_strength").state == "34.0" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_skin_temperature").state == "35" + assert hass.states.get("sensor.owlet_baby_care_sock_sleep_state").state == "awake" + + +async def test_sensors_charging(hass: HomeAssistant) -> None: + """Test sensor values.""" + await async_init_integration( + hass, properties_fixture="update_properties_charging.json" + ) + + assert len(hass.states.async_all("sensor")) == 8 + + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_percentage").state + == "100.0" + ) + assert ( + hass.states.get("sensor.owlet_baby_care_sock_battery_remaining").state + == "unknown" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_heart_rate").state == "unknown" + assert ( + hass.states.get("sensor.owlet_baby_care_sock_o2_saturation").state == "unknown" + ) + assert ( + hass.states.get( + "sensor.owlet_baby_care_sock_o2_saturation_10_minute_average" + ).state + == "unknown" + ) + + assert ( + hass.states.get("sensor.owlet_baby_care_sock_signal_strength").state == "34.0" + ) + assert ( + hass.states.get("sensor.owlet_baby_care_sock_skin_temperature").state + == "unknown" + ) + assert hass.states.get("sensor.owlet_baby_care_sock_sleep_state").state == "unknown"