Refactoring, added tests
###Fix # In light of submitting this as a pull request to the core of HA there have been some refactoring changes to comply with HA's style requirements #Sensor names now moved to strings file to allow for translations #Coordinator now properly handles multiple devices #Spelling of signal strength sensor corrected ###Feature #Tests added
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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",
|
||||
),
|
||||
|
||||
@@ -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."""
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user