### Asynchronous Setup for Owlet Integration Source: https://context7.com/ryanbdclark/owlet/llms.txt This Python function handles the asynchronous setup of the Owlet Smart Sock integration upon loading a configuration entry. It initializes the API client, refreshes authentication tokens, discovers devices, creates data coordinators for each device, performs an initial data fetch, and sets up the necessary Home Assistant platforms (binary sensor, sensor, switch). It also includes error handling for authentication, connection, and device discovery issues. ```python async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Owlet Smart Sock from a config entry.""" hass.data.setdefault(DOMAIN, {}) # Initialize API client with stored credentials owlet_api = OwletAPI( region=entry.data[CONF_REGION], token=entry.data[CONF_API_TOKEN], expiry=entry.data[CONF_OWLET_EXPIRY], refresh=entry.data[CONF_OWLET_REFRESH], session=async_get_clientsession(hass) ) try: # Refresh authentication if needed if token := await owlet_api.authenticate(): hass.config_entries.async_update_entry( entry, data={**entry.data, **token} ) # Discover all Owlet devices (versions 2 and 3 only) devices = await owlet_api.get_devices([2, 3]) # Handle token refresh from API response if "tokens" in devices: hass.config_entries.async_update_entry( entry, data={**entry.data, **devices["tokens"]} ) # Create coordinator for each device scan_interval = entry.options.get(CONF_SCAN_INTERVAL) coordinators = { device["device"]["dsn"]: OwletCoordinator( hass, Sock(owlet_api, device["device"]), scan_interval, entry ) for device in devices["response"] } # Perform initial data fetch for all coordinators await asyncio.gather(*( coordinator.async_config_entry_first_refresh() for coordinator in list(coordinators.values()) )) # Store coordinators and setup platforms hass.data[DOMAIN][entry.entry_id] = coordinators await hass.config_entries.async_forward_entry_setups( entry, [Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SWITCH] ) return True except (OwletAuthenticationError, OwletEmailError, OwletPasswordError): raise ConfigEntryAuthFailed("Credentials expired") except OwletConnectionError as err: raise ConfigEntryNotReady("Connection error") from err except OwletDevicesError: return False # No devices found ``` -------------------------------- ### Owlet Sensor Entity Setup and Configuration Source: https://context7.com/ryanbdclark/owlet/llms.txt Defines the structure for various Owlet sensor entities and provides an asynchronous setup function for Home Assistant. It filters available sensors based on coordinator properties. ```python SENSORS = ( # Battery level (0-100%) OwletSensorEntityDescription( key="battery_percentage", native_unit_of_measurement=PERCENTAGE, device_class=SensorDeviceClass.BATTERY, state_class=SensorStateClass.MEASUREMENT, available_during_charging=True ), # Oxygen saturation (0-100%) OwletSensorEntityDescription( key="oxygen_saturation", native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, icon="mdi:leaf", available_during_charging=False ), # Heart rate (beats per minute) OwletSensorEntityDescription( key="heart_rate", native_unit_of_measurement="bpm", state_class=SensorStateClass.MEASUREMENT, icon="mdi:heart-pulse", available_during_charging=False ), # Battery time remaining (minutes) OwletSensorEntityDescription( key="battery_minutes", native_unit_of_measurement=UnitOfTime.MINUTES, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, available_during_charging=False ), # WiFi signal strength (dBm) OwletSensorEntityDescription( key="signal_strength", native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, device_class=SensorDeviceClass.SIGNAL_STRENGTH, state_class=SensorStateClass.MEASUREMENT, available_during_charging=True ), # Skin temperature (Celsius) OwletSensorEntityDescription( key="skin_temperature", native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, available_during_charging=False ), # Movement metrics (disabled by default) OwletSensorEntityDescription( key="movement", state_class=SensorStateClass.MEASUREMENT, icon="mdi:cursor-move", entity_registry_enabled_default=False, available_during_charging=False ) ) # Sensor setup example async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: coordinators = list(hass.data[DOMAIN][config_entry.entry_id].values()) sensors = [] for coordinator in coordinators: # Only create sensors for available properties sensors.extend([ OwletSensor(coordinator, sensor) for sensor in SENSORS if sensor.key in coordinator.sock.properties ]) async_add_entities(sensors) ``` -------------------------------- ### Automation: Notify when Baby Wakes Up Source: https://context7.com/ryanbdclark/owlet/llms.txt An example Home Assistant automation that sends a notification when the baby's awake status changes to 'on'. This utilizes the OwletAwakeSensor entity. ```yaml # Automation example - Notify when baby wakes up # automation: # - alias: "Baby Awake Notification" # trigger: # - platform: state # entity_id: binary_sensor.owlet_sock_12345_awake # to: "on" # action: # - service: notify.parent # data: # message: "Baby is awake!" ``` -------------------------------- ### Control Owlet Base Station On/Off (Python) Source: https://context7.com/ryanbdclark/owlet/llms.txt Defines a switch entity to control the on/off state of the Owlet base station. It uses lambda functions for turn_on and turn_off operations and determines availability based on charging status. Service calls for turning the base station on and off are also provided as examples. ```python SWITCHES = ( OwletSwitchEntityDescription( key="base_station_on", turn_on_fn=lambda sock: (lambda state: sock.control_base_station(state)), turn_off_fn=lambda sock: (lambda state: sock.control_base_station(state)), available_during_charging=False ), ) class OwletBaseSwitch(OwletBaseEntity, SwitchEntity): """Switch entity for base station control.""" @property def is_on(self) -> bool: """Return current state from device properties.""" return self.sock.properties[self.entity_description.key] async def async_turn_on(self, **kwargs) -> None: """Turn on the base station.""" await self.entity_description.turn_on_fn(self.sock)(True) async def async_turn_off(self, **kwargs) -> None: """Turn off the base station.""" await self.entity_description.turn_off_fn(self.sock)(False) @property def available(self) -> bool: """Not available during charging.""" return super().available and ( not self.sock.properties["charging"] or self.entity_description.available_during_charging ) # Service call examples: # Turn on base station # service: switch.turn_on # target: # entity_id: switch.owlet_sock_12345_base_station_on # Turn off base station # service: switch.turn_off # target: # entity_id: switch.owlet_sock_12345_base_station_on ``` -------------------------------- ### Automation: Owlet Critical Oxygen Alert Notification Source: https://context7.com/ryanbdclark/owlet/llms.txt An example Home Assistant automation that triggers a notification service when the Owlet device reports a critical oxygen alert. It uses a state trigger for the specific binary sensor entity. ```yaml # automation: # - alias: "Owlet Critical Oxygen Alert" # trigger: # - platform: state # entity_id: binary_sensor.owlet_sock_12345_critical_oxygen_alert # to: "on" # action: # - service: notify.mobile_app # data: # message: "CRITICAL: Baby oxygen level alert!" # data: # priority: high # ttl: 0 ``` -------------------------------- ### Python: Configure Owlet Integration with User Credentials Source: https://context7.com/ryanbdclark/owlet/llms.txt This Python snippet demonstrates the initial configuration flow for the Owlet Smart Sock integration in Home Assistant. It shows how user-provided credentials (region, username, password) are used to instantiate the OwletAPI and authenticate with the Owlet cloud service. The resulting tokens and configuration are then used to create a Home Assistant configuration entry. ```python # User provides credentials during setup via Home Assistant UI # Configuration data schema: { "region": "europe", # or "world" "username": "user@example.com", "password": "your_password" } # The integration authenticates and stores tokens automatically # From custom_components/owlet/config_flow.py: owlet_api = OwletAPI( region=user_input[CONF_REGION], user=user_input[CONF_USERNAME], password=user_input[CONF_PASSWORD], session=async_get_clientsession(hass) ) # Authentication returns tokens that are stored in the config entry token = await owlet_api.authenticate() await owlet_api.validate_authentication() # Entry is created with username as title hass.config_entries.async_create_entry( title=user_input[CONF_USERNAME], data={ CONF_REGION: user_input[CONF_REGION], CONF_USERNAME: user_input[CONF_USERNAME], **token # Includes api_token, expiry, refresh tokens }, options={CONF_SCAN_INTERVAL: 5} # Default 5 second polling ) ``` -------------------------------- ### Owlet Binary Sensor Implementation Source: https://context7.com/ryanbdclark/owlet/llms.txt Implements the logic for Owlet binary sensors, determining their 'on' state based on device properties and their availability considering the charging state. This class inherits from OwletBaseEntity and BinarySensorEntity. ```python # Binary sensor implementation class OwletBinarySensor(OwletBaseEntity, BinarySensorEntity): """Binary sensor for boolean device properties.""" @property def is_on(self) -> bool: """Return true if alert is active.""" return self.sock.properties[self.entity_description.key] @property def available(self) -> bool: """Check availability based on charging state.""" return super().available and ( not self.sock.properties["charging"] or self.entity_description.available_during_charging ) ``` -------------------------------- ### Owlet Binary Sensor Definitions Source: https://context7.com/ryanbdclark/owlet/llms.txt Defines constants for Owlet binary sensors, including keys, device classes, and availability during charging. These are used to represent various device states and alerts. ```python BINARY_SENSORS = ( # Charging status OwletBinarySensorEntityDescription( key="charging", device_class=BinarySensorDeviceClass.BATTERY_CHARGING, available_during_charging=True ), # Heart rate alerts OwletBinarySensorEntityDescription( key="high_heart_rate_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), OwletBinarySensorEntityDescription( key="low_heart_rate_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), # Oxygen alerts OwletBinarySensorEntityDescription( key="high_oxygen_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), OwletBinarySensorEntityDescription( key="low_oxygen_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), OwletBinarySensorEntityDescription( key="critical_oxygen_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), # Battery alerts OwletBinarySensorEntityDescription( key="low_battery_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), OwletBinarySensorEntityDescription( key="critical_battery_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), # Connection alerts OwletBinarySensorEntityDescription( key="lost_power_alert", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), OwletBinarySensorEntityDescription( key="sock_disconnected", device_class=BinarySensorDeviceClass.SOUND, available_during_charging=True ), # Sock status OwletBinarySensorEntityDescription( key="sock_off", device_class=BinarySensorDeviceClass.POWER, available_during_charging=True ) ) ``` -------------------------------- ### Owlet Data Coordinator Implementation Source: https://context7.com/ryanbdclark/owlet/llms.txt This Python class, OwletCoordinator, extends Home Assistant's DataUpdateCoordinator to handle periodic data updates from an Owlet device. It initializes with the Home Assistant instance, a Sock object, the update interval, and the configuration entry. The _async_update_data method fetches device properties, updates tokens if present in the response, and includes error handling for authentication and connection issues, raising appropriate Home Assistant exceptions. ```python # From custom_components/owlet/coordinator.py # Handles periodic data updates with error handling class OwletCoordinator(DataUpdateCoordinator): """Coordinator for querying device at specified intervals.""" def __init__( self, hass: HomeAssistant, sock: Sock, interval: int, entry: ConfigEntry ) -> None: super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=interval) ) self.sock = sock self.config_entry = entry async def _async_update_data(self) -> None: """Fetch data from device.""" try: properties = await self.sock.update_properties() # Update tokens if provided in response if "tokens" in properties: self.hass.config_entries.async_update_entry( self.config_entry, data={**self.config_entry.data, **properties["tokens"]} ) except OwletAuthenticationError as err: raise ConfigEntryAuthFailed("Authentication failed") from err except (OwletError, OwletConnectionError) as err: raise UpdateFailed(err) from err # Usage: Coordinator automatically polls based on update_interval # All entities subscribed to coordinator receive updates automatically ``` -------------------------------- ### Owlet Device Registry Information (Python) Source: https://context7.com/ryanbdclark/owlet/llms.txt Defines the base entity class for Owlet Sock entities, inheriting from CoordinatorEntity and Entity. It provides device registry information, including identifiers, name, connections, manufacturer, model, and firmware versions, enabling grouping and enhanced display within Home Assistant. ```python # From custom_components/owlet/entity.py # All entities inherit from OwletBaseEntity class OwletBaseEntity(CoordinatorEntity[OwletCoordinator], Entity): """Base class for Owlet Sock entities.""" _attr_has_entity_name = True def __init__(self, coordinator: OwletCoordinator) -> None: super().__init__(coordinator) self.coordinator = coordinator self.sock = coordinator.sock @property def device_info(self) -> DeviceInfo: """Return device registry information.""" return DeviceInfo( identifiers={(DOMAIN, self.sock.serial)}, name=f"Owlet Sock {self.sock.serial}", connections={("mac", getattr(self.sock, "mac", "unknown"))}, suggested_area="Nursery", configuration_url="https://my.owletcare.com/", manufacturer="Owlet Baby Care", model=getattr(self.sock, "model", None), sw_version=getattr(self.sock, "sw_version", None), hw_version=getattr(self.sock, "hw_version", "3r8") ) # Device info enables: # - Grouping all entities under one device # - Displaying firmware versions # - Direct links to Owlet cloud dashboard # - Proper MAC address tracking ``` -------------------------------- ### Python: Configure Owlet Integration Polling Interval Source: https://context7.com/ryanbdclark/owlet/llms.txt This Python snippet illustrates how users can adjust the polling frequency for the Owlet Smart Sock integration through the Home Assistant UI options. It defines a schema for the scan interval, enforcing a minimum of 5 seconds, and demonstrates how these options can be modified at runtime without requiring re-authentication. ```python # Users can adjust polling frequency via integration options # Minimum allowed: 5 seconds # From custom_components/owlet/config_flow.py: schema = vol.Schema({ vol.Required( CONF_SCAN_INTERVAL, default=self.config_entry.options.get(CONF_SCAN_INTERVAL) ): vol.All(vol.Coerce(int), vol.Range(min=5)) }) # Options flow allows runtime changes without re-authentication # Access via: Configuration -> Integrations -> Owlet -> Options ``` -------------------------------- ### Owlet Oxygen Average Sensor with Validation Source: https://context7.com/ryanbdclark/owlet/llms.txt A sensor that calculates and displays a 10-minute rolling average of oxygen saturation, including validation to ensure readings are within the valid range of 0-100%. ```python # From custom_components/owlet/sensor.py # 10-minute rolling average with validation class OwletOxygenAverageSensor(OwletSensor): """10-minute oxygen saturation average.""" entity_description = OwletSensorEntityDescription( key="oxygen_10_av", native_unit_of_measurement=PERCENTAGE, icon="mdi:leaf", available_during_charging=False, state_class=SensorStateClass.MEASUREMENT ) @property def available(self) -> bool: """Only available when value is valid (0-100%).""" if not super().available: return False value = self.sock.properties["oxygen_10_av"] return 0 <= value <= 100 # This sensor filters out invalid readings before displaying # Useful for trend monitoring and medical tracking ``` -------------------------------- ### Owlet Sleep State Sensor Implementation Source: https://context7.com/ryanbdclark/owlet/llms.txt Implements a sensor for the baby's sleep state, translating numerical codes into human-readable strings. It inherits from OwletSensor and defines specific options and entity description. ```python # From custom_components/owlet/sensor.py # Enum sensor for baby's sleep state SLEEP_STATES = { 0: "unknown", 1: "awake", 8: "light_sleep", 15: "deep_sleep" } class OwletSleepSensor(OwletSensor): """Sleep state sensor with enum values.""" _attr_options = ["unknown", "awake", "light_sleep", "deep_sleep"] entity_description = OwletSensorEntityDescription( key="sleep_state", device_class=SensorDeviceClass.ENUM, available_during_charging=False ) @property def native_value(self) -> str: """Return human-readable sleep state.""" state_code = self.sock.properties["sleep_state"] return SLEEP_STATES[state_code] # Usage in automations: # trigger: # - platform: state # entity_id: sensor.owlet_sock_12345_sleep_state # to: "deep_sleep" # action: # - service: light.turn_off # target: # entity_id: light.nursery ``` -------------------------------- ### Owlet Awake/Asleep Sensor Implementation Source: https://context7.com/ryanbdclark/owlet/llms.txt Provides a specific binary sensor implementation to indicate whether the baby is awake or asleep. It interprets the 'sleep_state' property from the sock's data to determine the current state. ```python # From custom_components/owlet/binary_sensor.py # Simplified awake/asleep sensor class OwletAwakeSensor(OwletBinarySensor): """Binary sensor indicating if baby is awake.""" entity_description = OwletBinarySensorEntityDescription( key="sleep_state", icon="mdi:sleep", available_during_charging=False ) @property def is_on(self) -> bool: """True if awake, False if sleeping.""" sleep_state = self.sock.properties["sleep_state"] # States 8 and 15 are sleep states return sleep_state not in [8, 15] ``` -------------------------------- ### Owlet Re-authentication Flow (Python) Source: https://context7.com/ryanbdclark/owlet/llms.txt Handles the re-authentication process for the Owlet integration when user credentials expire. It prompts the user for their password, attempts to re-authenticate with the Owlet API, and updates the stored credentials upon success. Errors like invalid passwords are caught and displayed to the user. ```python # From custom_components/owlet/config_flow.py # Automatic re-authentication when credentials expire async def async_step_reauth_confirm( self, user_input: dict[str, Any] | None = None ) -> ConfigFlowResult: """Handle re-authentication dialog.""" errors = {} if user_input is not None: entry_data = self.reauth_entry.data owlet_api = OwletAPI( entry_data[CONF_REGION], entry_data[CONF_USERNAME], user_input[CONF_PASSWORD], session=async_get_clientsession(self.hass) ) try: if token := await owlet_api.authenticate(): # Update stored credentials self.hass.config_entries.async_update_entry( self.reauth_entry, data={**entry_data, **token} ) # Reload integration with new credentials await self.hass.config_entries.async_reload( self.reauth_entry.entry_id ) return self.async_abort(reason="reauth_successful") except OwletPasswordError: errors[CONF_PASSWORD] = "invalid_password" # Show password re-entry form return self.async_show_form( step_id="reauth_confirm", data_schema=vol.Schema({ vol.Required(CONF_PASSWORD): str }), errors=errors ) # When authentication fails, Home Assistant shows notification # User clicks notification to enter new password # Integration automatically resumes operation after successful reauth ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.