Amended config flow, hardcoded support for v3
-Amended config flow, took out second step to select socks -Added configuration to allow users to change polling interval -Hardcoded support for only v3 sock, I do not own any other socks to test with
This commit is contained in:
@@ -3,14 +3,24 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pyowletapi.owlet import Owlet
|
||||
from pyowletapi.api import OwletAPI
|
||||
from pyowletapi.sock import Sock
|
||||
from pyowletapi.exceptions import OwletAuthenticationError, OwletDevicesError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from .const import DOMAIN, CONF_OWLET_REGION, CONF_OWLET_USERNAME, CONF_OWLET_PASSWORD
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
CONF_OWLET_REGION,
|
||||
CONF_OWLET_USERNAME,
|
||||
CONF_OWLET_PASSWORD,
|
||||
CONF_OWLET_POLLINTERVAL,
|
||||
CONF_OWLET_EXPIRY,
|
||||
CONF_OWLET_TOKEN,
|
||||
SUPPORTED_VERSIONS,
|
||||
)
|
||||
from .coordinator import OwletCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||
@@ -22,34 +32,35 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up Owlet Smart Sock from a config entry."""
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
owlet = Owlet(
|
||||
owlet_api = OwletAPI(
|
||||
entry.data[CONF_OWLET_REGION],
|
||||
entry.data[CONF_OWLET_USERNAME],
|
||||
entry.data[CONF_OWLET_PASSWORD],
|
||||
entry.data[CONF_OWLET_TOKEN],
|
||||
entry.data[CONF_OWLET_EXPIRY],
|
||||
async_get_clientsession(hass),
|
||||
)
|
||||
|
||||
try:
|
||||
await owlet.authenticate()
|
||||
token = await owlet_api.authenticate()
|
||||
|
||||
if token:
|
||||
entry.data[CONF_OWLET_TOKEN] = token[CONF_OWLET_TOKEN]
|
||||
entry.data[CONF_OWLET_EXPIRY] = token[CONF_OWLET_EXPIRY]
|
||||
|
||||
socks = {
|
||||
device["device"]["dsn"]: Sock(owlet_api, device["device"])
|
||||
for device in await owlet_api.get_devices(SUPPORTED_VERSIONS)
|
||||
}
|
||||
|
||||
except OwletAuthenticationError as err:
|
||||
_LOGGER.error("Login failed %s", err)
|
||||
return False
|
||||
|
||||
existing_socks = entry.data["devices"]
|
||||
new_socks = []
|
||||
try:
|
||||
socks = await owlet.get_devices()
|
||||
except OwletDevicesError:
|
||||
pass
|
||||
|
||||
[new_socks.append(sock) for sock in socks if sock not in existing_socks]
|
||||
|
||||
if new_socks:
|
||||
hass.config_entries.async_update_entry(
|
||||
entry, data={**entry.data, **{"devices": socks}}
|
||||
)
|
||||
|
||||
coordinators = [OwletCoordinator(hass, sock) for sock in socks.values()]
|
||||
coordinators = [
|
||||
OwletCoordinator(hass, sock, entry.options.get(CONF_OWLET_POLLINTERVAL))
|
||||
for sock in socks.values()
|
||||
]
|
||||
|
||||
for coordinator in coordinators:
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pyowletapi.owlet import Owlet
|
||||
from pyowletapi.api import OwletAPI
|
||||
from pyowletapi.sock import Sock
|
||||
from pyowletapi.exceptions import (
|
||||
OwletConnectionError,
|
||||
@@ -18,22 +18,27 @@ from homeassistant import config_entries
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers import config_validation
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
CONF_OWLET_REGION,
|
||||
CONF_OWLET_USERNAME,
|
||||
CONF_OWLET_PASSWORD,
|
||||
CONF_OWLET_POLLINTERVAL,
|
||||
CONF_OWLET_TOKEN,
|
||||
CONF_OWLET_EXPIRY,
|
||||
POLLING_INTERVAL,
|
||||
SUPPORTED_VERSIONS,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_OWLET_REGION): vol.In(["europe", "world"]),
|
||||
vol.Required(CONF_OWLET_USERNAME): str,
|
||||
vol.Required(CONF_OWLET_PASSWORD): str,
|
||||
vol.Required("region"): vol.In(["europe", "world"]),
|
||||
vol.Required("username"): str,
|
||||
vol.Required("password"): str,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -60,7 +65,7 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._username = user_input[CONF_OWLET_USERNAME]
|
||||
self._password = user_input[CONF_OWLET_PASSWORD]
|
||||
|
||||
owlet = Owlet(
|
||||
owlet_api = OwletAPI(
|
||||
self._region,
|
||||
self._username,
|
||||
self._password,
|
||||
@@ -71,10 +76,20 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
try:
|
||||
await owlet.authenticate()
|
||||
token = await owlet_api.authenticate()
|
||||
try:
|
||||
self._devices = await owlet.get_devices()
|
||||
return await self.async_step_socks()
|
||||
await owlet_api.get_devices(SUPPORTED_VERSIONS)
|
||||
return self.async_create_entry(
|
||||
title=self._username,
|
||||
data={
|
||||
CONF_OWLET_REGION: self._region,
|
||||
CONF_OWLET_USERNAME: self._username,
|
||||
CONF_OWLET_PASSWORD: self._password,
|
||||
CONF_OWLET_TOKEN: token[CONF_OWLET_TOKEN],
|
||||
CONF_OWLET_EXPIRY: token[CONF_OWLET_EXPIRY],
|
||||
},
|
||||
options={CONF_OWLET_POLLINTERVAL: POLLING_INTERVAL},
|
||||
)
|
||||
except OwletDevicesError:
|
||||
errors["base"] = "no_devices"
|
||||
|
||||
@@ -90,27 +105,32 @@ class OwletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_socks(self, user_input=None):
|
||||
"""Allow the user to choose which devices to configure"""
|
||||
errors = {}
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry):
|
||||
"""Get the options flow for this handler."""
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Handle a options flow for owlet"""
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
||||
"""Initialise options flow"""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Handle options flow"""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(
|
||||
title="Owlet",
|
||||
data={
|
||||
CONF_OWLET_REGION: self._region,
|
||||
CONF_OWLET_USERNAME: self._username,
|
||||
CONF_OWLET_PASSWORD: self._password,
|
||||
"devices": user_input["socks"],
|
||||
},
|
||||
)
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
schema = vol.Schema(
|
||||
{
|
||||
vol.Required("socks"): config_validation.multi_select(
|
||||
{sock: sock for sock in list(self._devices.keys())}
|
||||
),
|
||||
vol.Required(
|
||||
CONF_OWLET_POLLINTERVAL,
|
||||
default=self.config_entry.options.get(CONF_OWLET_POLLINTERVAL),
|
||||
): vol.All(vol.Coerce(int), vol.Range(min=10)),
|
||||
}
|
||||
)
|
||||
|
||||
return self.async_show_form(step_id="socks", data_schema=schema, errors=errors)
|
||||
return self.async_show_form(step_id="init", data_schema=schema)
|
||||
|
||||
@@ -5,7 +5,11 @@ DOMAIN = "owlet"
|
||||
CONF_OWLET_REGION = "region"
|
||||
CONF_OWLET_USERNAME = "username"
|
||||
CONF_OWLET_PASSWORD = "password"
|
||||
CONF_SOCK_SERIAL = "sock_serial"
|
||||
CONF_OWLET_DEVICES = "devices"
|
||||
CONF_OWLET_POLLINTERVAL = "pollinterval"
|
||||
CONF_OWLET_TOKEN = "token"
|
||||
CONF_OWLET_EXPIRY = "expiry"
|
||||
|
||||
SUPPORTED_VERSIONS = [3]
|
||||
POLLING_INTERVAL = 10
|
||||
MANUFACTURER = "Owlet Baby Care"
|
||||
|
||||
@@ -13,7 +13,6 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
POLLING_INTERVAL,
|
||||
MANUFACTURER,
|
||||
)
|
||||
|
||||
@@ -23,18 +22,19 @@ _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) -> None:
|
||||
def __init__(self, hass: HomeAssistant, sock: Sock, interval: int) -> None:
|
||||
"""Initialise a custom coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=timedelta(seconds=POLLING_INTERVAL),
|
||||
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.sock = sock
|
||||
self.device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, self._device_unique_id)},
|
||||
@@ -42,6 +42,7 @@ class OwletCoordinator(DataUpdateCoordinator):
|
||||
manufacturer=MANUFACTURER,
|
||||
model=self._model,
|
||||
sw_version=self._sw_version,
|
||||
hw_version=self._hw_version,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> None:
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"homekit": {},
|
||||
"iot_class": "cloud_polling",
|
||||
"requirements": [
|
||||
"pyowletapi==2023.5.7"
|
||||
"pyowletapi==2023.5.17"
|
||||
],
|
||||
"version":"1.1.0"
|
||||
"version":"1.2.0"
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
"username": "Email",
|
||||
"password": "Password"
|
||||
}
|
||||
},
|
||||
"socks":{
|
||||
"title": "Configure Socks",
|
||||
"description":"Select socks to configure"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
@@ -22,5 +18,15 @@
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init":{
|
||||
"title":"Configure options for Owlet",
|
||||
"data":{
|
||||
"pollinterval": "Polling interval in seconds, min 10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,32 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user":{
|
||||
"title": "Enter login details",
|
||||
"data":{
|
||||
"region": "Region",
|
||||
"username": "Email",
|
||||
"password": "Password"
|
||||
}
|
||||
},
|
||||
"socks":{
|
||||
"title": "Configure Socks",
|
||||
"description":"Select socks to configure"
|
||||
"config": {
|
||||
"step": {
|
||||
"user":{
|
||||
"title": "Enter login details",
|
||||
"data":{
|
||||
"region": "Region",
|
||||
"username": "Email",
|
||||
"password": "Password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init":{
|
||||
"title":"Configure options for Owlet",
|
||||
"data":{
|
||||
"pollinterval": "Polling interval in seconds, min 10"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,32 @@
|
||||
{
|
||||
"config": {
|
||||
"step": {
|
||||
"user":{
|
||||
"title": "Enter login details",
|
||||
"data":{
|
||||
"region": "Region",
|
||||
"username": "Email",
|
||||
"password": "Password"
|
||||
}
|
||||
},
|
||||
"socks":{
|
||||
"title": "Configure Socks",
|
||||
"description":"Select socks to configure"
|
||||
"config": {
|
||||
"step": {
|
||||
"user":{
|
||||
"title": "Enter login details",
|
||||
"data":{
|
||||
"region": "Region",
|
||||
"username": "Email",
|
||||
"password": "Password"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init":{
|
||||
"title":"Configure options for Owlet",
|
||||
"data":{
|
||||
"pollinterval": "Polling interval in seconds, min 10"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user