Add Baby Tracker client and Home Assistant integration
Python client for the Baby Tracker sync server, reverse engineered from the Android app (4.53), and a HACS-installable Home Assistant integration built on it. Each baby gets a log calendar and summary sensors, and actions add entries that sync back to the group. Reading has been run against the real server. Uploading and running inside real Home Assistant have not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
6466f002e0
51 files changed
+5199
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,22 @@
|
||||
from datetime import datetime as datetime_sys
|
||||
|
||||
import voluptuous
|
||||
|
||||
|
||||
def string(value):
|
||||
if value is None:
|
||||
raise voluptuous.Invalid("string value is None")
|
||||
return str(value)
|
||||
|
||||
|
||||
def datetime(value):
|
||||
if isinstance(value, datetime_sys):
|
||||
return value
|
||||
try:
|
||||
return datetime_sys.fromisoformat(value)
|
||||
except (TypeError, ValueError) as err:
|
||||
raise voluptuous.Invalid("invalid datetime") from err
|
||||
|
||||
|
||||
def config_entry_only_config_schema(domain):
|
||||
return lambda config: config
|
||||
@@ -0,0 +1,30 @@
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class DeviceEntryType(Enum):
|
||||
SERVICE = "service"
|
||||
|
||||
|
||||
def DeviceInfo(**kwargs):
|
||||
return kwargs
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeviceEntry:
|
||||
identifiers: set
|
||||
|
||||
|
||||
class DeviceRegistry:
|
||||
def __init__(self):
|
||||
self.devices = {}
|
||||
|
||||
def async_get(self, device_id):
|
||||
return self.devices.get(device_id)
|
||||
|
||||
|
||||
REGISTRY = DeviceRegistry()
|
||||
|
||||
|
||||
def async_get(hass):
|
||||
return REGISTRY
|
||||
@@ -0,0 +1,18 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class TextSelectorType(str, Enum):
|
||||
EMAIL = "email"
|
||||
PASSWORD = "password"
|
||||
|
||||
|
||||
def TextSelectorConfig(**kwargs):
|
||||
return kwargs
|
||||
|
||||
|
||||
class TextSelector:
|
||||
def __init__(self, config=None):
|
||||
self.config = config
|
||||
|
||||
def __call__(self, value):
|
||||
return str(value)
|
||||
@@ -0,0 +1 @@
|
||||
ConfigType = dict
|
||||
@@ -0,0 +1,60 @@
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
from ..exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady, HomeAssistantError
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class UpdateFailed(HomeAssistantError):
|
||||
pass
|
||||
|
||||
|
||||
class DataUpdateCoordinator(Generic[_T]):
|
||||
def __init__(self, hass, logger, *, config_entry=None, name=None, update_interval=None):
|
||||
self.hass = hass
|
||||
self.logger = logger
|
||||
self.config_entry = config_entry
|
||||
self.name = name
|
||||
self.update_interval = update_interval
|
||||
self.data = None
|
||||
self.last_update_success = True
|
||||
self.last_exception = None
|
||||
self._listeners = []
|
||||
|
||||
def async_add_listener(self, listener):
|
||||
self._listeners.append(listener)
|
||||
return lambda: self._listeners.remove(listener)
|
||||
|
||||
def _notify(self):
|
||||
for listener in list(self._listeners):
|
||||
listener()
|
||||
|
||||
async def async_refresh(self):
|
||||
try:
|
||||
self.data = await self._async_update_data()
|
||||
except UpdateFailed as err:
|
||||
self.last_update_success = False
|
||||
self.last_exception = err
|
||||
else:
|
||||
self.last_update_success = True
|
||||
self._notify()
|
||||
|
||||
async def async_config_entry_first_refresh(self):
|
||||
try:
|
||||
self.data = await self._async_update_data()
|
||||
except UpdateFailed as err:
|
||||
raise ConfigEntryNotReady(str(err)) from err
|
||||
|
||||
def async_set_updated_data(self, data):
|
||||
self.data = data
|
||||
self.last_update_success = True
|
||||
self._notify()
|
||||
|
||||
|
||||
class CoordinatorEntity(Generic[_T]):
|
||||
def __init__(self, coordinator):
|
||||
self.coordinator = coordinator
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
return self.coordinator.last_update_success
|
||||
Reference in new issue
Block a user