-
-
Notifications
You must be signed in to change notification settings - Fork 28.6k
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
Add extra sensors for BMW ConnectedDrive #12591
Changes from all commits
a4887f0
7117933
b508099
97b3ada
74883a3
53a92e8
2bb2323
0345a28
fadb643
57b13d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
""" | ||
Reads vehicle status from BMW connected drive portal. | ||
|
||
For more details about this platform, please refer to the documentation at | ||
https://home-assistant.io/components/binary_sensor.bmw_connected_drive/ | ||
""" | ||
import asyncio | ||
import logging | ||
|
||
from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN | ||
from homeassistant.components.binary_sensor import BinarySensorDevice | ||
|
||
DEPENDENCIES = ['bmw_connected_drive'] | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
SENSOR_TYPES = { | ||
'all_lids_closed': ['Doors', 'opening'], | ||
'all_windows_closed': ['Windows', 'opening'], | ||
'door_lock_state': ['Door lock state', 'safety'] | ||
} | ||
|
||
|
||
def setup_platform(hass, config, add_devices, discovery_info=None): | ||
"""Set up the BMW sensors.""" | ||
accounts = hass.data[BMW_DOMAIN] | ||
_LOGGER.debug('Found BMW accounts: %s', | ||
', '.join([a.name for a in accounts])) | ||
devices = [] | ||
for account in accounts: | ||
for vehicle in account.account.vehicles: | ||
for key, value in sorted(SENSOR_TYPES.items()): | ||
device = BMWConnectedDriveSensor(account, vehicle, key, | ||
value[0], value[1]) | ||
devices.append(device) | ||
add_devices(devices, True) | ||
|
||
|
||
class BMWConnectedDriveSensor(BinarySensorDevice): | ||
"""Representation of a BMW vehicle binary sensor.""" | ||
|
||
def __init__(self, account, vehicle, attribute: str, sensor_name, | ||
device_class): | ||
"""Constructor.""" | ||
self._account = account | ||
self._vehicle = vehicle | ||
self._attribute = attribute | ||
self._name = sensor_name | ||
self._device_class = device_class | ||
self._state = None | ||
|
||
@property | ||
def should_poll(self) -> bool: | ||
"""Data update is triggered from BMWConnectedDriveEntity.""" | ||
return False | ||
|
||
@property | ||
def name(self): | ||
"""Return the name of the binary sensor.""" | ||
return self._name | ||
|
||
@property | ||
def device_class(self): | ||
"""Return the class of the binary sensor.""" | ||
return self._device_class | ||
|
||
@property | ||
def is_on(self): | ||
"""Return the state of the binary sensor.""" | ||
return self._state | ||
|
||
@property | ||
def device_state_attributes(self): | ||
"""Return the state attributes of the binary sensor.""" | ||
vehicle_state = self._vehicle.state | ||
result = { | ||
'car': self._vehicle.modelName | ||
} | ||
|
||
if self._attribute == 'all_lids_closed': | ||
for lid in vehicle_state.lids: | ||
result[lid.name] = lid.state.value | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is lid name lowercase snakecase? That's the home assistant standard. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is, this is an example of a lid name: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
elif self._attribute == 'all_windows_closed': | ||
for window in vehicle_state.windows: | ||
result[window.name] = window.state.value | ||
elif self._attribute == 'door_lock_state': | ||
result['door_lock_state'] = vehicle_state.door_lock_state.value | ||
|
||
return result | ||
|
||
def update(self): | ||
"""Read new state data from the library.""" | ||
vehicle_state = self._vehicle.state | ||
|
||
# device class opening: On means open, Off means closed | ||
if self._attribute == 'all_lids_closed': | ||
_LOGGER.debug("Status of lid: %s", vehicle_state.all_lids_closed) | ||
self._state = not vehicle_state.all_lids_closed | ||
if self._attribute == 'all_windows_closed': | ||
self._state = not vehicle_state.all_windows_closed | ||
# device class safety: On means unsafe, Off means safe | ||
if self._attribute == 'door_lock_state': | ||
# Possible values: LOCKED, SECURED, SELECTIVELOCKED, UNLOCKED | ||
self._state = bool(vehicle_state.door_lock_state.value | ||
in ('SELECTIVELOCKED', 'UNLOCKED')) | ||
|
||
def update_callback(self): | ||
"""Schedule a state update.""" | ||
self.schedule_update_ha_state(True) | ||
|
||
@asyncio.coroutine | ||
def async_added_to_hass(self): | ||
"""Add callback after being added to hass. | ||
|
||
Show latest data after startup. | ||
""" | ||
self._account.add_update_listener(self.update_callback) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
""" | ||
Support for BMW cars with BMW ConnectedDrive. | ||
|
||
For more details about this component, please refer to the documentation at | ||
https://home-assistant.io/components/lock.bmw_connected_drive/ | ||
""" | ||
import asyncio | ||
import logging | ||
|
||
from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN | ||
from homeassistant.components.lock import LockDevice | ||
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED | ||
|
||
DEPENDENCIES = ['bmw_connected_drive'] | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
def setup_platform(hass, config, add_devices, discovery_info=None): | ||
"""Setup the BMW Connected Drive lock.""" | ||
accounts = hass.data[BMW_DOMAIN] | ||
_LOGGER.debug('Found BMW accounts: %s', | ||
', '.join([a.name for a in accounts])) | ||
devices = [] | ||
for account in accounts: | ||
for vehicle in account.account.vehicles: | ||
device = BMWLock(account, vehicle, 'lock', 'BMW lock') | ||
devices.append(device) | ||
add_devices(devices, True) | ||
|
||
|
||
class BMWLock(LockDevice): | ||
"""Representation of a BMW vehicle lock.""" | ||
|
||
def __init__(self, account, vehicle, attribute: str, sensor_name): | ||
"""Initialize the lock.""" | ||
self._account = account | ||
self._vehicle = vehicle | ||
self._attribute = attribute | ||
self._name = sensor_name | ||
self._state = None | ||
|
||
@property | ||
def should_poll(self): | ||
"""Do not poll this class. | ||
|
||
Updates are triggered from BMWConnectedDriveAccount. | ||
""" | ||
return False | ||
|
||
@property | ||
def name(self): | ||
"""Return the name of the lock.""" | ||
return self._name | ||
|
||
@property | ||
def device_state_attributes(self): | ||
"""Return the state attributes of the lock.""" | ||
vehicle_state = self._vehicle.state | ||
return { | ||
'car': self._vehicle.modelName, | ||
'door_lock_state': vehicle_state.door_lock_state.value | ||
} | ||
|
||
@property | ||
def is_locked(self): | ||
"""Return true if lock is locked.""" | ||
return self._state == STATE_LOCKED | ||
|
||
def lock(self, **kwargs): | ||
"""Lock the car.""" | ||
_LOGGER.debug("%s: locking doors", self._vehicle.modelName) | ||
# Optimistic state set here because it takes some time before the | ||
# update callback response | ||
self._state = STATE_LOCKED | ||
self.schedule_update_ha_state() | ||
self._vehicle.remote_services.trigger_remote_door_lock() | ||
|
||
def unlock(self, **kwargs): | ||
"""Unlock the car.""" | ||
_LOGGER.debug("%s: unlocking doors", self._vehicle.modelName) | ||
# Optimistic state set here because it takes some time before the | ||
# update callback response | ||
self._state = STATE_UNLOCKED | ||
self.schedule_update_ha_state() | ||
self._vehicle.remote_services.trigger_remote_door_unlock() | ||
|
||
def update(self): | ||
"""Update state of the lock.""" | ||
_LOGGER.debug("%s: updating data for %s", self._vehicle.modelName, | ||
self._attribute) | ||
vehicle_state = self._vehicle.state | ||
|
||
# Possible values: LOCKED, SECURED, SELECTIVELOCKED, UNLOCKED | ||
self._state = (STATE_LOCKED if vehicle_state.door_lock_state.value | ||
in ('LOCKED', 'SECURED') else STATE_UNLOCKED) | ||
|
||
def update_callback(self): | ||
"""Schedule a state update.""" | ||
self.schedule_update_ha_state(True) | ||
|
||
@asyncio.coroutine | ||
def async_added_to_hass(self): | ||
"""Add callback after being added to hass. | ||
|
||
Show latest data after startup. | ||
""" | ||
self._account.add_update_listener(self.update_callback) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the name of the sensor also contain the name of the vehicle?
If someone has more than one vehicle, we need to make sure that the sensors then get different names...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The vehicle name is not show in the sensor name, but it is shown in the attributes. Not sure what is the best approach, but maybe those people with more than one vehicle can update the friendly name of the sensor? Because in my opinion it's not necessary to show the vehicle name in the sensor name if you have one BMW (which will be the majority I guess).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add an option where people can give names to their vehicles? Something like:
That way people can
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is indeed something we could add as an option.