Skip to content

Commit

Permalink
v0.7.0 (#67)
Browse files Browse the repository at this point in the history
- Bump to subarulink 0.7.0
- Remove External temperature and 12V Battery voltage sensors
- Remove Subaru unique services replaced by HA native services
- Rename 'update' button to 'poll vehicle'
- Add debug logging for subarulink parsed data
- Add redacted raw API dump to device diagnostics
  • Loading branch information
G-Two authored Dec 4, 2022
1 parent f72c1a8 commit 3132114
Show file tree
Hide file tree
Showing 22 changed files with 630 additions and 439 deletions.
27 changes: 19 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
*.pyc
.coverage
.vscode/
.mypy_cache/
.pytest_cache/
*.code_workspace
Pipfile
Pipfile.lock
**/*

!custom_components/
!custom_components/**
!tests/
!tests/**

**/__pycache__
**/*.pyc
**/.DS_Store
**/.coverage

!.pre-commit-config.yaml
!hacs.json
!LICENSE
!pyproject.toml
!README.md
!requirements.test.txt
!setup.cfg
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ repos:
- --ignore-words-list=hass,spawnve
- --quiet-level=2

- repo: https://gitlab.com/pycqa/flake8
- repo: https://github.com/pycqa/flake8
rev: 4.0.1
hooks:
- id: flake8
Expand Down
27 changes: 2 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@ NOTE: There now appears to be a Gen 3, although it is unclear which model years

| Sensor | Gen 1 | Gen 2 | Gen 3 |
|--------------------------|---------|---------|---------|
| 12V battery voltage | | ✓ | ✓ |
| Average fuel consumption | | ✓ | ✓ |
| Distance to empty | | ✓ | ✓ |
| EV battery level | | ✓ | ✓ |
| EV range | | ✓ | ✓ |
| EV time to full charge | | ✓ | ✓ |
| External temperature | | ✓ | ✓ |
| Odometer | ✓*| ✓ | ✓ |
| Tire pressures | | ✓ | ✓ |

Expand Down Expand Up @@ -167,27 +165,6 @@ official mobile app. Although the underlying subarulink python package does supp
integration.
---
### Legacy Services
**NOTE:** All the legacy services below will be removed in release v0.7.0:
| Service | Description |
| ---------------------- | ----------- |
|`subaru.charge_start` | Starts EV charging (this cannot be stopped remotely) |
|`subaru.fetch` | Fetches vehicle data cached on Subaru servers (does not request update from vehicle) |
|`subaru.horn` | Sound the horn and flash the lights of the vehicle |
|`subaru.horn_cancel` | Stop sounding the horn and flash the lights of the vehicle |
|`subaru.lights` | Flash the lights of the vehicle |
|`subaru.lights_cancel` | Stop flashing the lights of the vehicle |
|`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 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 |


## Lovelace Example
<img src="https://user-images.githubusercontent.com/7310260/148698672-48cdc85f-623b-4f06-88e2-6e1949b4a522.png" width="1024" />
Expand Down Expand Up @@ -219,7 +196,7 @@ views:
entity_id: button.subaru_refresh
type: button
icon_height: 48px
- entity: button.subaru_locate
- entity: button.subaru_poll_vehicle
hold_action:
action: more-info
show_icon: true
Expand All @@ -232,7 +209,7 @@ views:
service: button.press
service_data: {}
target:
entity_id: button.subaru_locate
entity_id: button.subaru_update
type: button
icon_height: 48px
title: Update Data
Expand Down
92 changes: 6 additions & 86 deletions custom_components/subaru/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,39 @@
import asyncio
from datetime import timedelta
import logging
import pprint

from subarulink import Controller as SubaruAPI, InvalidCredentials, SubaruException
from subarulink.const import COUNTRY_USA
import voluptuous as vol

from homeassistant.components.binary_sensor import (
DOMAIN as BINARY_SENSOR_DOMAIN,
BinarySensorDeviceClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_DEVICE_ID,
CONF_DEVICE_ID,
CONF_PASSWORD,
CONF_PIN,
CONF_USERNAME,
STATE_ON,
Platform,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import (
aiohttp_client,
config_validation as cv,
device_registry,
entity_registry as er,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client, entity_registry as er
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
CONF_COUNTRY,
CONF_NOTIFICATION_OPTION,
CONF_POLLING_OPTION,
COORDINATOR_NAME,
DOMAIN,
ENTRY_CONTROLLER,
ENTRY_COORDINATOR,
ENTRY_VEHICLES,
FETCH_INTERVAL,
REMOTE_CLIMATE_PRESET_NAME,
REMOTE_SERVICE_REMOTE_START,
SUPPORTED_PLATFORMS,
UPDATE_INTERVAL,
UPDATE_INTERVAL_CHARGING,
Expand All @@ -63,12 +54,7 @@
)
from .migrate import async_migrate_entries
from .options import PollingOptions
from .remote_service import (
async_call_remote_service,
get_supported_services,
poll_subaru,
refresh_subaru,
)
from .remote_service import poll_subaru, refresh_subaru

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -143,73 +129,6 @@ async def async_update_data() -> dict:
hass.config_entries.async_forward_entry_setup(entry, component)
)

async def async_call_service(call: ServiceCall) -> None:
"""Execute subaru service."""
_LOGGER.warning(
"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 vin in vehicles:
await async_call_remote_service(
hass,
controller,
call.service,
vehicles[vin],
arg,
entry.options.get(CONF_NOTIFICATION_OPTION),
)
await coordinator.async_refresh()
return

raise HomeAssistantError(f"Invalid VIN provided while calling {call.service}")

async def async_remote_start(call: ServiceCall) -> None:
"""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_remote_start,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): cv.string,
vol.Required(REMOTE_CLIMATE_PRESET_NAME): cv.string,
}
),
)
else:
hass.services.async_register(
DOMAIN,
service,
async_call_service,
schema=vol.Schema({vol.Required(VEHICLE_VIN): cv.string}),
)

return True


Expand Down Expand Up @@ -283,6 +202,7 @@ async def _refresh_subaru_data(
received_data = await controller.get_data(vin)
if received_data:
data[vin] = received_data
_LOGGER.debug("Subaru data %s", pprint.pformat(received_data))

return data

Expand Down
8 changes: 4 additions & 4 deletions custom_components/subaru/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
ENTRY_COORDINATOR,
ENTRY_VEHICLES,
REMOTE_SERVICE_CHARGE_START,
REMOTE_SERVICE_FETCH,
REMOTE_SERVICE_HORN,
REMOTE_SERVICE_HORN_STOP,
REMOTE_SERVICE_LIGHTS,
REMOTE_SERVICE_LIGHTS_STOP,
REMOTE_SERVICE_POLL_VEHICLE,
REMOTE_SERVICE_REFRESH,
REMOTE_SERVICE_REMOTE_START,
REMOTE_SERVICE_REMOTE_STOP,
REMOTE_SERVICE_UPDATE,
VEHICLE_CLIMATE_SELECTED_PRESET,
VEHICLE_HAS_EV,
VEHICLE_HAS_REMOTE_SERVICE,
Expand All @@ -49,10 +49,10 @@
key=REMOTE_SERVICE_LIGHTS_STOP, icon="mdi:lightbulb-off", name="Lights stop"
),
ButtonEntityDescription(
key=REMOTE_SERVICE_UPDATE, icon="mdi:car-connected", name="Locate"
key=REMOTE_SERVICE_POLL_VEHICLE, icon="mdi:car-connected", name="Poll Vehicle"
),
ButtonEntityDescription(
key=REMOTE_SERVICE_FETCH, icon="mdi:refresh", name="Refresh"
key=REMOTE_SERVICE_REFRESH, icon="mdi:refresh", name="Refresh"
),
]

Expand Down
4 changes: 2 additions & 2 deletions custom_components/subaru/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@

ATTR_DOOR = "door"

REMOTE_SERVICE_FETCH = "fetch"
REMOTE_SERVICE_UPDATE = "update"
REMOTE_SERVICE_REFRESH = "fetch"
REMOTE_SERVICE_POLL_VEHICLE = "update"
REMOTE_SERVICE_LOCK = "lock"
REMOTE_SERVICE_UNLOCK = "unlock"
REMOTE_SERVICE_LIGHTS = "lights"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/subaru/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def extra_state_attributes(self) -> dict[str, Any] | None:
extra_attributes = {
"Position timestamp": self.coordinator.data[self.vin][
VEHICLE_STATUS
].get(sc.POSITION_TIMESTAMP)
].get(sc.TIMESTAMP)
}
return extra_attributes

Expand Down
17 changes: 14 additions & 3 deletions custom_components/subaru/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@

from typing import Any

from subarulink.const import LATITUDE, LONGITUDE, ODOMETER, VEHICLE_NAME
from subarulink.const import (
LATITUDE,
LONGITUDE,
ODOMETER,
RAW_API_FIELDS_TO_REDACT,
VEHICLE_NAME,
)

from homeassistant.components.diagnostics.util import async_redact_data
from homeassistant.config_entries import ConfigEntry
Expand All @@ -12,7 +18,7 @@
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceEntry

from .const import DOMAIN, ENTRY_COORDINATOR, VEHICLE_VIN
from .const import DOMAIN, ENTRY_CONTROLLER, ENTRY_COORDINATOR, VEHICLE_VIN

CONFIG_FIELDS_TO_REDACT = [CONF_USERNAME, CONF_PASSWORD, CONF_PIN, CONF_DEVICE_ID]
DATA_FIELDS_TO_REDACT = [VEHICLE_VIN, VEHICLE_NAME, LATITUDE, LONGITUDE, ODOMETER]
Expand Down Expand Up @@ -40,7 +46,9 @@ async def async_get_device_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry, device: DeviceEntry
) -> dict[str, Any]:
"""Return diagnostics for a device."""
coordinator = hass.data[DOMAIN][config_entry.entry_id][ENTRY_COORDINATOR]
entry = hass.data[DOMAIN][config_entry.entry_id]
coordinator = entry[ENTRY_COORDINATOR]
controller = entry[ENTRY_CONTROLLER]

vin = next(iter(device.identifiers))[1]

Expand All @@ -51,6 +59,9 @@ async def async_get_device_diagnostics(
),
"options": async_redact_data(config_entry.options, []),
"data": async_redact_data(info, DATA_FIELDS_TO_REDACT),
"raw_data": async_redact_data(
controller.get_raw_data(vin), RAW_API_FIELDS_TO_REDACT
),
}

raise HomeAssistantError("Device not found")
4 changes: 2 additions & 2 deletions custom_components/subaru/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"config_flow": true,
"documentation": "https://github.com/G-Two/homeassistant-subaru",
"issue_tracker": "https://github.com/G-Two/homeassistant-subaru/issues",
"requirements": ["subarulink==0.6.1"],
"requirements": ["subarulink==0.7.0"],
"codeowners": ["@G-Two"],
"version": "0.6.5",
"version": "0.7.0",
"iot_class": "cloud_polling"
}
Loading

0 comments on commit 3132114

Please sign in to comment.