-
-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Owlet Care Baby Monitor Component #20258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
71fc79d
Initial commit of owlet component
oblogic7 df1b363
Remove monitored conditions
oblogic7 4ddb053
Formatting
oblogic7 a1452bb
Update requirements file
oblogic7 d59b951
Remove unused import
oblogic7 8a81a29
Update scan interval
oblogic7 d275865
Correct documentation link and copy paste remnant
oblogic7 b0e2c23
Wording
oblogic7 73cfc4f
Missing docstrings
oblogic7 1177802
Imperative mood. Punctuation
oblogic7 6c1272c
Requested changes.
oblogic7 0bb5cae
Lint
oblogic7 0b2f7fb
Embed platforms into component
oblogic7 e978153
Update coveragerc again.
oblogic7 1c67d9d
Requested changes.
oblogic7 1997993
Please the hound
oblogic7 59b8b8e
Missed a change
oblogic7 3fc8df0
Guard clause updates
oblogic7 694930c
Correct import order
oblogic7 b1c4f7d
Lint
oblogic7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| """Support for Owlet baby monitors.""" | ||
| import logging | ||
|
|
||
| import voluptuous as vol | ||
|
|
||
| from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, CONF_NAME) | ||
| import homeassistant.helpers.config_validation as cv | ||
| from homeassistant.helpers.discovery import load_platform | ||
|
|
||
| from .const import SENSOR_MOVEMENT, SENSOR_BASE_STATION, SENSOR_HEART_RATE, \ | ||
| SENSOR_OXYGEN_LEVEL | ||
|
|
||
| REQUIREMENTS = ['pyowlet==1.0.2'] | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| DOMAIN = 'owlet' | ||
|
|
||
| SENSOR_TYPES = [ | ||
| SENSOR_OXYGEN_LEVEL, | ||
| SENSOR_HEART_RATE, | ||
| SENSOR_BASE_STATION, | ||
| SENSOR_MOVEMENT | ||
| ] | ||
|
|
||
| CONFIG_SCHEMA = vol.Schema({ | ||
| DOMAIN: vol.Schema({ | ||
| vol.Required(CONF_USERNAME): cv.string, | ||
| vol.Required(CONF_PASSWORD): cv.string, | ||
| vol.Optional(CONF_NAME): cv.string, | ||
| }), | ||
| }, extra=vol.ALLOW_EXTRA) | ||
|
|
||
|
|
||
| def setup(hass, config): | ||
| """Set up owlet component.""" | ||
| from pyowlet.PyOwlet import PyOwlet | ||
|
|
||
| username = config[DOMAIN][CONF_USERNAME] | ||
| password = config[DOMAIN][CONF_PASSWORD] | ||
| name = config[DOMAIN].get(CONF_NAME) | ||
|
|
||
| try: | ||
| device = PyOwlet(username, password) | ||
| except KeyError: | ||
| _LOGGER.error('Owlet authentication failed. Please verify your ' | ||
| 'credentials are correct.') | ||
| return False | ||
|
|
||
| device.update_properties() | ||
|
|
||
| if not name: | ||
| name = '{}\'s Owlet'.format(device.baby_name) | ||
|
|
||
| hass.data[DOMAIN] = OwletDevice(device, name, SENSOR_TYPES) | ||
|
|
||
| load_platform(hass, 'sensor', DOMAIN, {}, config) | ||
| load_platform(hass, 'binary_sensor', DOMAIN, {}, config) | ||
|
|
||
| return True | ||
|
|
||
|
|
||
| class OwletDevice(): | ||
| """Represents a configured Owlet device.""" | ||
|
|
||
| def __init__(self, device, name, monitor): | ||
| """Initialize device.""" | ||
| self.name = name | ||
| self.monitor = monitor | ||
| self.device = device | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| """Support for Owlet binary sensors.""" | ||
| from datetime import timedelta | ||
|
|
||
| from homeassistant.components.binary_sensor import BinarySensorDevice | ||
| from homeassistant.components.owlet import DOMAIN as OWLET_DOMAIN | ||
| from homeassistant.util import dt as dt_util | ||
|
|
||
| from .const import SENSOR_BASE_STATION, SENSOR_MOVEMENT | ||
|
|
||
| SCAN_INTERVAL = timedelta(seconds=120) | ||
|
|
||
| BINARY_CONDITIONS = { | ||
| SENSOR_BASE_STATION: { | ||
| 'name': 'Base Station', | ||
| 'device_class': 'power' | ||
| }, | ||
| SENSOR_MOVEMENT: { | ||
| 'name': 'Movement', | ||
| 'device_class': 'motion' | ||
| } | ||
| } | ||
|
|
||
|
|
||
| def setup_platform(hass, config, add_entities, discovery_info=None): | ||
| """Set up owlet binary sensor.""" | ||
| if discovery_info is None: | ||
|
oblogic7 marked this conversation as resolved.
|
||
| return | ||
|
|
||
| device = hass.data[OWLET_DOMAIN] | ||
|
oblogic7 marked this conversation as resolved.
|
||
|
|
||
| entities = [] | ||
| for condition in BINARY_CONDITIONS: | ||
| if condition in device.monitor: | ||
| entities.append(OwletBinarySensor(device, condition)) | ||
|
|
||
| add_entities(entities, True) | ||
|
|
||
|
|
||
| class OwletBinarySensor(BinarySensorDevice): | ||
| """Representation of owlet binary sensor.""" | ||
|
|
||
| def __init__(self, device, condition): | ||
| """Init owlet binary sensor.""" | ||
| self._device = device | ||
| self._condition = condition | ||
| self._state = None | ||
| self._base_on = False | ||
| self._prop_expiration = None | ||
| self._is_charging = None | ||
|
|
||
| @property | ||
| def name(self): | ||
| """Return sensor name.""" | ||
| return '{} {}'.format(self._device.name, | ||
| BINARY_CONDITIONS[self._condition]['name']) | ||
|
|
||
| @property | ||
| def is_on(self): | ||
| """Return current state of sensor.""" | ||
| return self._state | ||
|
|
||
| @property | ||
| def device_class(self): | ||
| """Return the device class.""" | ||
| return BINARY_CONDITIONS[self._condition]['device_class'] | ||
|
|
||
| def update(self): | ||
| """Update state of sensor.""" | ||
| self._base_on = self._device.device.base_station_on | ||
| self._prop_expiration = self._device.device.prop_expire_time | ||
| self._is_charging = self._device.device.charge_status > 0 | ||
|
|
||
| # handle expired values | ||
| if self._prop_expiration < dt_util.now().timestamp(): | ||
| self._state = False | ||
| return | ||
|
|
||
| if self._condition == 'movement': | ||
| if not self._base_on or self._is_charging: | ||
| return False | ||
|
|
||
| self._state = getattr(self._device.device, self._condition) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| """Constants for Owlet component.""" | ||
| SENSOR_OXYGEN_LEVEL = 'oxygen_level' | ||
| SENSOR_HEART_RATE = 'heart_rate' | ||
|
|
||
| SENSOR_BASE_STATION = 'base_station_on' | ||
| SENSOR_MOVEMENT = 'movement' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| """Support for Owlet sensors.""" | ||
| from datetime import timedelta | ||
|
|
||
| from homeassistant.components.owlet import DOMAIN as OWLET_DOMAIN | ||
| from homeassistant.helpers.entity import Entity | ||
| from homeassistant.util import dt as dt_util | ||
|
|
||
| from .const import SENSOR_HEART_RATE, SENSOR_OXYGEN_LEVEL | ||
|
|
||
| SCAN_INTERVAL = timedelta(seconds=120) | ||
|
|
||
| SENSOR_CONDITIONS = { | ||
| SENSOR_OXYGEN_LEVEL: { | ||
| 'name': 'Oxygen Level', | ||
| 'device_class': None | ||
| }, | ||
| SENSOR_HEART_RATE: { | ||
| 'name': 'Heart Rate', | ||
| 'device_class': None | ||
| } | ||
| } | ||
|
|
||
|
|
||
| def setup_platform(hass, config, add_entities, discovery_info=None): | ||
| """Set up owlet binary sensor.""" | ||
| if discovery_info is None: | ||
| return | ||
|
|
||
| device = hass.data[OWLET_DOMAIN] | ||
|
oblogic7 marked this conversation as resolved.
|
||
|
|
||
| entities = [] | ||
| for condition in SENSOR_CONDITIONS: | ||
| if condition in device.monitor: | ||
| entities.append(OwletSensor(device, condition)) | ||
|
|
||
| add_entities(entities, True) | ||
|
|
||
|
|
||
| class OwletSensor(Entity): | ||
| """Representation of Owlet sensor.""" | ||
|
|
||
| def __init__(self, device, condition): | ||
| """Init owlet binary sensor.""" | ||
| self._device = device | ||
| self._condition = condition | ||
| self._state = None | ||
| self._prop_expiration = None | ||
| self.is_charging = None | ||
| self.battery_level = None | ||
| self.sock_off = None | ||
| self.sock_connection = None | ||
| self._movement = None | ||
|
|
||
| @property | ||
| def name(self): | ||
| """Return sensor name.""" | ||
| return '{} {}'.format(self._device.name, | ||
| SENSOR_CONDITIONS[self._condition]['name']) | ||
|
|
||
| @property | ||
| def state(self): | ||
| """Return current state of sensor.""" | ||
| return self._state | ||
|
|
||
| @property | ||
| def device_class(self): | ||
| """Return the device class.""" | ||
| return SENSOR_CONDITIONS[self._condition]['device_class'] | ||
|
|
||
| @property | ||
| def device_state_attributes(self): | ||
| """Return state attributes.""" | ||
| attributes = { | ||
| 'battery_charging': self.is_charging, | ||
| 'battery_level': self.battery_level, | ||
| 'sock_off': self.sock_off, | ||
| 'sock_connection': self.sock_connection | ||
| } | ||
|
|
||
| return attributes | ||
|
|
||
| def update(self): | ||
| """Update state of sensor.""" | ||
| self.is_charging = self._device.device.charge_status | ||
| self.battery_level = self._device.device.batt_level | ||
| self.sock_off = self._device.device.sock_off | ||
| self.sock_connection = self._device.device.sock_connection | ||
| self._movement = self._device.device.movement | ||
| self._prop_expiration = self._device.device.prop_expire_time | ||
|
|
||
| value = getattr(self._device.device, self._condition) | ||
|
|
||
| if self._condition == 'batt_level': | ||
| self._state = min(100, value) | ||
| return | ||
|
|
||
| if not self._device.device.base_station_on \ | ||
| or self._device.device.charge_status > 0 \ | ||
| or self._prop_expiration < dt_util.now().timestamp() \ | ||
| or self._movement: | ||
| value = None | ||
|
|
||
| self._state = value | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.