Skip to content

Commit

Permalink
v0.6.2 (#48)
Browse files Browse the repository at this point in the history
* Add 2FA support to config flow
* Add vehicle model year/name to device info
* Update remote start service to use device id
* Fix timestamp format for EV charge time
* Code quality/maintainability updates
* Add warning for deprecated services
  • Loading branch information
G-Two authored Mar 27, 2022
1 parent 68c0619 commit 72a99cd
Show file tree
Hide file tree
Showing 28 changed files with 818 additions and 543 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9]
python-version: ["3.9", "3.10"]

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ repos:
stages: [manual]
- id: check-json
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.770
rev: v0.941
hooks:
- id: mypy
args:
Expand Down
49 changes: 23 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Subaru STARLINK Integration for Home Assistant
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg)](https://github.com/hacs/integration)

**NOTE:** The [Subaru](https://www.home-assistant.io/integrations/subaru/) integration is now part of Home Assistant Core (as of release [2021.3](https://www.home-assistant.io/blog/2021/03/03/release-20213/)), however not all features have been implemented. Currently, only the sensor platform is available. Additional PRs will be submitted to include all features of this custom component into Home Assistant Core.
**NOTE:** The [Subaru](https://www.home-assistant.io/integrations/subaru/) integration is now part of Home Assistant Core (as of release [2021.3](https://www.home-assistant.io/blog/2021/03/03/release-20213/)), however not all features have been implemented. Currently, only the sensor and lock platforms are available. Additional PRs will be submitted to include all features of this custom component into Home Assistant Core.

Users that desire full functionality should continue to use this custom component until all functionality is merged into the official integration. This custom component will override the HA Core built-in integration.

Expand Down Expand Up @@ -106,9 +106,9 @@ When prompted, enter the following configuration parameters:
- **Password:** The password associated with your MySubaru account
- **Country:** The country your MySubaru account is associated with

The initial device registration process may take up to 20 seconds.
After your account is authenticated, you will need to authorize the application with Subaru's two factor authentication. Follow the prompts to select a phone number or email address to receive a verification code and enter when prompted. This should only need to be accomplished during initial configuration.

After successful authentication, if a supported remote services vehicle with active subscription is found in your account, an additional prompt will appear:
After successful authorization, if a supported remote services vehicle with active subscription is found in your account, an additional prompt will appear:
- **PIN:** The PIN associated with your MySubaru account

**NOTE:** If your account includes multiple vehicles, the same PIN will be used for all vehicles. Ensure that you have configured all vehicles in your account to have the same PIN.
Expand All @@ -134,14 +134,12 @@ All options involve remote commands, thus only apply to vehicles with Security P

## Services

As of v0.6.0, the following Subaru entities now use the native Home Assistant services:
The following Subaru entities use built-in Home Assistant services:
- Lock
- Button (Remote Start, Lights/Horn, Locate, Refresh)
- Button (Remote Start/Stop, Lights/Horn, Locate, Refresh)
- Select (Climate Control Preset)

The legacy Subaru integration specific services that required the VIN are no longer needed to access the features above and will be removed in a future release.

The Lock entity's "Unlock" will always unlock all doors. The Subaru API supports selecting a specific door to unlock. Users that desire this functionality may use a Subaru integration specific service which allows the user to choose the door to unlock. See the Services UI in Developer Tools for usage. Example YAML for this service is:
The Lock entity's "Unlock" will unlock all doors. The Subaru API supports selecting a specific door to unlock. Users that wish to use this functionality may call an integration specific service which allows the user to choose the door to unlock. See the Services UI in Developer Tools for usage. Example YAML for this service is:
```yaml
service: subaru.unlock_specific_door
target:
Expand All @@ -150,10 +148,25 @@ data:
# Valid values for door are 'all', 'driver', 'tailgate' (note that 'tailgate' is not supported by all vehicles)
door: driver
```
### Remote Climate Control
For supported vehicles, this integration supports selecting specific remote climate control presets when remotely starting the engine. See the Services UI in Developer Tools for usage. Example YAML for this service is:
```yaml
service: subaru.remote_start
data:
# preset_name is case sensitive
preset_name: Full Heat
# Use the Services UI to populate device_id
device_id: 0cce5d5135ac6459ce620654362e45b8
```
There are 3 pre-configured Subaru climate presets, **Auto** (not available for EVs), **Full Cool**, and **Full Heat**. In addition you may configure up to 4 additional custom presets from the MySubaru website or the
official mobile app. Although the underlying subarulink python package does support the creation of new presets, that functionality has not yet been implemented in this
integration.
---
### Legacy Services
**NOTE:** All the legacy services below will be removed in a future release:
**NOTE:** All the legacy services below will be removed in release v0.7.0:
| Service | Description |
| ---------------------- | ----------- |
Expand All @@ -166,29 +179,13 @@ data:
|`subaru.remote_stop` | Stop the engine and climate control of the vehicle |
|`subaru.update` | Sends request to vehicle to update data which will update cache on Subaru servers |

All of the above services require the same service data attribute shown below. The service will be invoked on the vehicle identified by `vin`.
All of the legacy services require the same service data attribute shown below. The service will be invoked on the vehicle identified by `vin`.

| Service Data Attribute | Required | Type | Description |
| ---------------------- | -------- | ------ | -------------------------------------------------- |
| `vin` | yes | String | The vehicle identification number (VIN) of the vehicle, 17 characters |

#### Remote Climate Control

For supported vehicles, this integration supports selecting specific remote climate control presets when remotely starting the engine via the following service:

| Service | Description |
| ---------------------- | ----------- |
|`subaru.remote_start` | Start the engine and climate control of the vehicle using the user specified climate control preset |

`subaru.remote_start` requires an additional data attribute, `preset_name`, which is a preconfigured set of climate control settings. There are 3 "built-in" Subaru presets:
`Auto` (not available for EVs), `Full Cool`, and `Full Heat`. In addition you may configure up to 4 additional custom presets from the MySubaru website or the
official mobile app. Although the underlying subarulink python package does support the creation of new presets, that functionality has not yet been implemented in this
integration.

| Service Data Attribute | Required | Type | Description |
| ---------------------- | -------- | ------ | -------------------------------------------------- |
| `vin` | yes | String | The vehicle identification number (VIN) of the vehicle, 17 characters |
| `preset_name` | yes | String | Either a Subaru or user defined climate control preset name |

## Lovelace Example
<img src="https://user-images.githubusercontent.com/7310260/148698672-48cdc85f-623b-4f06-88e2-6e1949b4a522.png" width="1024" />
Expand Down
61 changes: 55 additions & 6 deletions custom_components/subaru/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,21 @@
import voluptuous as vol

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_PIN, CONF_USERNAME
from homeassistant.const import (
ATTR_DEVICE_ID,
CONF_DEVICE_ID,
CONF_PASSWORD,
CONF_PIN,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers import (
aiohttp_client,
config_validation as cv,
device_registry,
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
Expand All @@ -24,6 +35,7 @@
ENTRY_COORDINATOR,
ENTRY_VEHICLES,
FETCH_INTERVAL,
MANUFACTURER,
REMOTE_CLIMATE_PRESET_NAME,
REMOTE_SERVICE_REMOTE_START,
SUPPORTED_PLATFORMS,
Expand All @@ -35,6 +47,8 @@
VEHICLE_HAS_SAFETY_SERVICE,
VEHICLE_LAST_FETCH,
VEHICLE_LAST_UPDATE,
VEHICLE_MODEL_NAME,
VEHICLE_MODEL_YEAR,
VEHICLE_NAME,
VEHICLE_VIN,
)
Expand Down Expand Up @@ -118,10 +132,11 @@ async def async_update_data():

async def async_call_service(call):
"""Execute subaru service."""
_LOGGER.warn(
"This Subaru-specific service is deprecated and will be removed in v0.7.0. Use button or lock entities (or their respective services) to actuate remove vehicle services."
)
vin = call.data[VEHICLE_VIN].upper()
arg = None
if call.service == REMOTE_SERVICE_REMOTE_START:
arg = call.data[REMOTE_CLIMATE_PRESET_NAME]

if vin in vehicles:
await async_call_remote_service(
Expand All @@ -140,17 +155,39 @@ async def async_call_service(call):
)
raise HomeAssistantError(f"Invalid VIN provided while calling {call.service}")

async def async_remote_start(call):
"""Start the vehicle engine."""
dev_reg = device_registry.async_get(hass)
device_entry = dev_reg.async_get(call.data[ATTR_DEVICE_ID])
if device_entry:
vin = list(device_entry.identifiers)[0][1]
_LOGGER.info(
"Remote engine start initiated with climate preset: %s",
call.data[REMOTE_CLIMATE_PRESET_NAME],
)
await async_call_remote_service(
hass,
controller,
call.service,
vehicles[vin],
call.data[REMOTE_CLIMATE_PRESET_NAME],
entry.options.get(CONF_NOTIFICATION_OPTION),
)
await coordinator.async_refresh()
else:
raise HomeAssistantError(f"device_id {call.data[ATTR_DEVICE_ID]} not found")

supported_services = get_supported_services(vehicles)

for service in supported_services:
if service == REMOTE_SERVICE_REMOTE_START:
hass.services.async_register(
DOMAIN,
service,
async_call_service,
async_remote_start,
schema=vol.Schema(
{
vol.Required(VEHICLE_VIN): cv.string,
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(REMOTE_CLIMATE_PRESET_NAME): cv.string,
}
),
Expand Down Expand Up @@ -217,6 +254,8 @@ def get_vehicle_info(controller, vin):
"""Obtain vehicle identifiers and capabilities."""
info = {
VEHICLE_VIN: vin,
VEHICLE_MODEL_NAME: controller.get_model_name(vin),
VEHICLE_MODEL_YEAR: controller.get_model_year(vin),
VEHICLE_NAME: controller.vin_to_name(vin),
VEHICLE_HAS_EV: controller.get_ev_status(vin),
VEHICLE_API_GEN: controller.get_api_gen(vin),
Expand All @@ -227,3 +266,13 @@ def get_vehicle_info(controller, vin):
VEHICLE_LAST_FETCH: 0,
}
return info


def get_device_info(vehicle_info):
"""Return DeviceInfo object based on vehicle info."""
return DeviceInfo(
identifiers={(DOMAIN, vehicle_info[VEHICLE_VIN])},
manufacturer=MANUFACTURER,
model=f"{vehicle_info[VEHICLE_MODEL_YEAR]} {vehicle_info[VEHICLE_MODEL_NAME]}",
name=vehicle_info[VEHICLE_NAME],
)
Loading

0 comments on commit 72a99cd

Please sign in to comment.