mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add services for bmw_connected_drive (#13497)
* implemented services for bmw remote services * added vin to attributes of tracker * moved component to new package * added service description * fixed static analysis warnings * implemented first set of code reviews * removed locking related services * fixed static analysis warnings * removed excess blank lines * refactoring of setup() to resolve warning "Cell variable bimmer defined in loop (cell-var-from-loop)" * added missing docstring * added service to update all vehicles from the server * implemented changes requested in code review * added check if invalid vin is entered
This commit is contained in:
parent
783e9a5f8c
commit
e472436b84
@ -20,7 +20,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
DOMAIN = 'bmw_connected_drive'
|
DOMAIN = 'bmw_connected_drive'
|
||||||
CONF_REGION = 'region'
|
CONF_REGION = 'region'
|
||||||
|
ATTR_VIN = 'vin'
|
||||||
|
|
||||||
ACCOUNT_SCHEMA = vol.Schema({
|
ACCOUNT_SCHEMA = vol.Schema({
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
@ -35,35 +35,40 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
},
|
},
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
SERVICE_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_VIN): cv.string,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
BMW_COMPONENTS = ['binary_sensor', 'device_tracker', 'lock', 'sensor']
|
BMW_COMPONENTS = ['binary_sensor', 'device_tracker', 'lock', 'sensor']
|
||||||
UPDATE_INTERVAL = 5 # in minutes
|
UPDATE_INTERVAL = 5 # in minutes
|
||||||
|
|
||||||
|
SERVICE_UPDATE_STATE = 'update_state'
|
||||||
|
|
||||||
def setup(hass, config):
|
_SERVICE_MAP = {
|
||||||
|
'light_flash': 'trigger_remote_light_flash',
|
||||||
|
'sound_horn': 'trigger_remote_horn',
|
||||||
|
'activate_air_conditioning': 'trigger_remote_air_conditioning',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config: dict):
|
||||||
"""Set up the BMW connected drive components."""
|
"""Set up the BMW connected drive components."""
|
||||||
accounts = []
|
accounts = []
|
||||||
for name, account_config in config[DOMAIN].items():
|
for name, account_config in config[DOMAIN].items():
|
||||||
username = account_config[CONF_USERNAME]
|
accounts.append(setup_account(account_config, hass, name))
|
||||||
password = account_config[CONF_PASSWORD]
|
|
||||||
region = account_config[CONF_REGION]
|
|
||||||
_LOGGER.debug('Adding new account %s', name)
|
|
||||||
bimmer = BMWConnectedDriveAccount(username, password, region, name)
|
|
||||||
accounts.append(bimmer)
|
|
||||||
|
|
||||||
# update every UPDATE_INTERVAL minutes, starting now
|
|
||||||
# this should even out the load on the servers
|
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
track_utc_time_change(
|
|
||||||
hass, bimmer.update,
|
|
||||||
minute=range(now.minute % UPDATE_INTERVAL, 60, UPDATE_INTERVAL),
|
|
||||||
second=now.second)
|
|
||||||
|
|
||||||
hass.data[DOMAIN] = accounts
|
hass.data[DOMAIN] = accounts
|
||||||
|
|
||||||
for account in accounts:
|
def _update_all(call) -> None:
|
||||||
account.update()
|
"""Update all BMW accounts."""
|
||||||
|
for cd_account in hass.data[DOMAIN]:
|
||||||
|
cd_account.update()
|
||||||
|
|
||||||
|
# Service to manually trigger updates for all accounts.
|
||||||
|
hass.services.register(DOMAIN, SERVICE_UPDATE_STATE, _update_all)
|
||||||
|
|
||||||
|
_update_all(None)
|
||||||
|
|
||||||
for component in BMW_COMPONENTS:
|
for component in BMW_COMPONENTS:
|
||||||
discovery.load_platform(hass, component, DOMAIN, {}, config)
|
discovery.load_platform(hass, component, DOMAIN, {}, config)
|
||||||
@ -71,6 +76,48 @@ def setup(hass, config):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def setup_account(account_config: dict, hass, name: str) \
|
||||||
|
-> 'BMWConnectedDriveAccount':
|
||||||
|
"""Set up a new BMWConnectedDriveAccount based on the config."""
|
||||||
|
username = account_config[CONF_USERNAME]
|
||||||
|
password = account_config[CONF_PASSWORD]
|
||||||
|
region = account_config[CONF_REGION]
|
||||||
|
_LOGGER.debug('Adding new account %s', name)
|
||||||
|
cd_account = BMWConnectedDriveAccount(username, password, region, name)
|
||||||
|
|
||||||
|
def execute_service(call):
|
||||||
|
"""Execute a service for a vehicle.
|
||||||
|
|
||||||
|
This must be a member function as we need access to the cd_account
|
||||||
|
object here.
|
||||||
|
"""
|
||||||
|
vin = call.data[ATTR_VIN]
|
||||||
|
vehicle = cd_account.account.get_vehicle(vin)
|
||||||
|
if not vehicle:
|
||||||
|
_LOGGER.error('Could not find a vehicle for VIN "%s"!', vin)
|
||||||
|
return
|
||||||
|
function_name = _SERVICE_MAP[call.service]
|
||||||
|
function_call = getattr(vehicle.remote_services, function_name)
|
||||||
|
function_call()
|
||||||
|
|
||||||
|
# register the remote services
|
||||||
|
for service in _SERVICE_MAP:
|
||||||
|
hass.services.register(
|
||||||
|
DOMAIN, service,
|
||||||
|
execute_service,
|
||||||
|
schema=SERVICE_SCHEMA)
|
||||||
|
|
||||||
|
# update every UPDATE_INTERVAL minutes, starting now
|
||||||
|
# this should even out the load on the servers
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
track_utc_time_change(
|
||||||
|
hass, cd_account.update,
|
||||||
|
minute=range(now.minute % UPDATE_INTERVAL, 60, UPDATE_INTERVAL),
|
||||||
|
second=now.second)
|
||||||
|
|
||||||
|
return cd_account
|
||||||
|
|
||||||
|
|
||||||
class BMWConnectedDriveAccount(object):
|
class BMWConnectedDriveAccount(object):
|
||||||
"""Representation of a BMW vehicle."""
|
"""Representation of a BMW vehicle."""
|
||||||
|
|
42
homeassistant/components/bmw_connected_drive/services.yaml
Normal file
42
homeassistant/components/bmw_connected_drive/services.yaml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Describes the format for available services for bmw_connected_drive
|
||||||
|
#
|
||||||
|
# The services related to locking/unlocking are implemented in the lock
|
||||||
|
# component to avoid redundancy.
|
||||||
|
|
||||||
|
light_flash:
|
||||||
|
description: >
|
||||||
|
Flash the lights of the vehicle. The vehicle is identified via the vin
|
||||||
|
(see below).
|
||||||
|
fields:
|
||||||
|
vin:
|
||||||
|
description: >
|
||||||
|
The vehicle identification number (VIN) of the vehicle, 17 characters
|
||||||
|
example: WBANXXXXXX1234567
|
||||||
|
|
||||||
|
sound_horn:
|
||||||
|
description: >
|
||||||
|
Sound the horn of the vehicle. The vehicle is identified via the vin
|
||||||
|
(see below).
|
||||||
|
fields:
|
||||||
|
vin:
|
||||||
|
description: >
|
||||||
|
The vehicle identification number (VIN) of the vehicle, 17 characters
|
||||||
|
example: WBANXXXXXX1234567
|
||||||
|
|
||||||
|
activate_air_conditioning:
|
||||||
|
description: >
|
||||||
|
Start the air conditioning of the vehicle. What exactly is started here
|
||||||
|
depends on the type of vehicle. It might range from just ventilation over
|
||||||
|
auxilary heating to real air conditioning. The vehicle is identified via
|
||||||
|
the vin (see below).
|
||||||
|
fields:
|
||||||
|
vin:
|
||||||
|
description: >
|
||||||
|
The vehicle identification number (VIN) of the vehicle, 17 characters
|
||||||
|
example: WBANXXXXXX1234567
|
||||||
|
|
||||||
|
update_state:
|
||||||
|
description: >
|
||||||
|
Fetch the last state of the vehicles of all your accounts from the BMW
|
||||||
|
server. This does *not* trigger an update from the vehicle, it just gets
|
||||||
|
the data from the BMW servers. This service does not require any attributes.
|
@ -48,8 +48,11 @@ class BMWDeviceTracker(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug('Updating %s', dev_id)
|
_LOGGER.debug('Updating %s', dev_id)
|
||||||
|
attrs = {
|
||||||
|
'vin': self.vehicle.vin,
|
||||||
|
}
|
||||||
self._see(
|
self._see(
|
||||||
dev_id=dev_id, host_name=self.vehicle.name,
|
dev_id=dev_id, host_name=self.vehicle.name,
|
||||||
gps=self.vehicle.state.gps_position, icon='mdi:car'
|
gps=self.vehicle.state.gps_position, attributes=attrs,
|
||||||
|
icon='mdi:car'
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user