Skip to content

Commit

Permalink
v0.6.3 (#54)
Browse files Browse the repository at this point in the history
* Add option to disable error notifications
* Add option to poll during EV charging
  • Loading branch information
G-Two authored Oct 1, 2022
1 parent b53584c commit 32e8c81
Show file tree
Hide file tree
Showing 25 changed files with 915 additions and 396 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/hassfest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ name: Validate with hassfest

on:
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: "0 0 * * *"

Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Run pre-commit checks

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
- name: Install dependencies
run: |
pip install -r requirements.test.txt
- uses: pre-commit/[email protected]
17 changes: 7 additions & 10 deletions .github/workflows/ci.yml → .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@

name: Test with pytest and flake8
name: Test code with pytest

on:
push:
branches: [ main ]
branches:
- main
pull_request:
branches: [ main ]
branches:
- main
schedule:
- cron: '0 3 * * *'
- cron: '0 0 * * *'

jobs:
test:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10"]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -25,11 +25,8 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.test.txt
- name: Lint with flake8
run: |
flake8
- name: Test with pytest
run: |
pytest
33 changes: 24 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.3.0
rev: v2.38.2
hooks:
- id: pyupgrade
args: [--py37-plus]

- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
Expand All @@ -12,42 +13,46 @@ repos:
- --safe
- --quiet
files: ^((custom_components|tests)/.+)?[^/]+\.py$

- repo: https://github.com/codespell-project/codespell
rev: v1.16.0
rev: v2.0.0
hooks:
- id: codespell
args:
- --ignore-words-list=hass,alot,datas,dof,dur,farenheit,hist,iff,ines,ist,lightsensor,mut,nd,pres,referer,ser,serie,te,technik,ue,uint,visability,wan,wanna,withing
- --skip="./.*,*.csv,*.json"
- --ignore-words-list=hass,spawnve
- --quiet-level=2
exclude_types: [csv, json]

- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.1
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies:
- flake8-docstrings==1.5.0
- pydocstyle==5.0.2
files: ^(custom_components|tests)/.+\.py$

- repo: https://github.com/PyCQA/bandit
rev: 1.6.2
rev: 1.7.0
hooks:
- id: bandit
args:
- --quiet
- --format=custom
- --configfile=tests/bandit.yaml
files: ^(custom_components||tests)/.+\.py$

- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
rev: v5.10.1
hooks:
- id: isort

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
rev: v3.2.0
hooks:
- id: check-executables-have-shebangs
stages: [manual]
- id: check-json

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.941
hooks:
Expand All @@ -56,3 +61,13 @@ repos:
- --pretty
- --show-error-codes
- --show-error-context

- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
files: ^((custom_components|tests)/.+)?[^/]+\.py$


8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@ Subaru integration options are set via:
All options involve remote commands, thus only apply to vehicles with Security Plus subscriptions:

- **Enable vehicle polling:** Sensor data reported by the Subaru API only returns what is cached on Subaru servers, and does not necessarily reflect current conditions. The cached data is updated when the engine is shutdown, or when a location update is requested. This options enables automatic periodic updates.
- **Disabled *[Default]*:** New sensor data is only received when the vehicle automatically pushes data (normally after engine shutdown). The user may still manually poll the vehicle anytime with the `subaru.update` service.
- **Enabled:** Every 2 hours, the integration will send a remote command (equivalent to running the `subaru.update` service), "waking" your vehicle obtain new sensor data. *WARNING:* Vehicle polling draws power from the 12V battery. Long term use without driving may drain the battery resulting in the inability to start your vehicle.
- **Disable *[Default]*:** New sensor data is only received when the vehicle automatically pushes data (normally after engine shutdown). The user may still manually poll the vehicle anytime with the Locate button.
- **Charging:** For PHEVs, during charging, the integration will poll every 30 minutes to obtain updated charging status. Polling will only occur during charging.
- **Enable:** Every 2 hours, the integration will send a remote command (equivalent to pressing the Locate button), "waking" your vehicle obtain new sensor data. *WARNING:* Vehicle polling draws power from the 12V battery. Long term use without driving may drain the battery resulting in the inability to start your vehicle.

- **Lovelace UI notifications for remote commands:** It takes 10-15 seconds for remote commands to be processed by the Subaru API and transmitted over the cellular network to your vehicle. Some users may desire UI feedback that the integration is working. This option provides three levels of increasing verbosity:
- **Failure *[Default]*:** Only notify when the remote command has failed.
- **Disable *[Default]*:** Lovelace notifications are disabled. Errors will still be logged.
- **Failure :** Only notify when the remote command has failed.
- **Pending:** Failure + temporary notification that the command is "working" that will automatically disappear when the Subaru API confirms success (10 to 15 seconds).
- **Success:** Pending + persistent notification of success in Lovelace. This is the same behavior as v0.5.1 and earlier releases.

Expand Down
1 change: 1 addition & 0 deletions custom_components/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Subaru custom component for Home Assistant."""
50 changes: 39 additions & 11 deletions custom_components/subaru/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,35 @@
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
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import (
aiohttp_client,
config_validation as cv,
device_registry,
entity_registry,
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
CONF_COUNTRY,
CONF_NOTIFICATION_OPTION,
CONF_UPDATE_ENABLED,
CONF_POLLING_OPTION,
COORDINATOR_NAME,
DOMAIN,
ENTRY_CONTROLLER,
Expand All @@ -40,6 +47,7 @@
REMOTE_SERVICE_REMOTE_START,
SUPPORTED_PLATFORMS,
UPDATE_INTERVAL,
UPDATE_INTERVAL_CHARGING,
VEHICLE_API_GEN,
VEHICLE_HAS_EV,
VEHICLE_HAS_REMOTE_SERVICE,
Expand All @@ -52,11 +60,12 @@
VEHICLE_NAME,
VEHICLE_VIN,
)
from .options import PollingOptions
from .remote_service import (
async_call_remote_service,
get_supported_services,
poll_subaru,
refresh_subaru,
update_subaru,
)

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -105,7 +114,7 @@ async def async_setup_entry(hass, entry):
async def async_update_data():
"""Fetch data from API endpoint."""
try:
return await refresh_subaru_data(entry, vehicles, controller)
return await refresh_subaru_data(hass, entry, vehicles, controller)
except SubaruException as err:
raise UpdateFailed(err.message) from err

Expand All @@ -132,7 +141,7 @@ async def async_update_data():

async def async_call_service(call):
"""Execute subaru service."""
_LOGGER.warn(
_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()
Expand All @@ -150,9 +159,6 @@ async def async_call_service(call):
await coordinator.async_refresh()
return

hass.components.persistent_notification.create(
f"ERROR - Invalid VIN provided while calling {call.service}", "Subaru"
)
raise HomeAssistantError(f"Invalid VIN provided while calling {call.service}")

async def async_remote_start(call):
Expand Down Expand Up @@ -219,7 +225,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
return unload_ok


async def refresh_subaru_data(config_entry, vehicle_info, controller):
async def refresh_subaru_data(hass, config_entry, vehicle_info, controller):
"""
Refresh local data with data fetched via Subaru API.
Expand All @@ -235,9 +241,31 @@ async def refresh_subaru_data(config_entry, vehicle_info, controller):
if not vehicle[VEHICLE_HAS_SAFETY_SERVICE]:
continue

# Send an "update" remote command to vehicle, if supported (throttled with update_interval)
if config_entry.options.get(CONF_UPDATE_ENABLED, False):
await update_subaru(vehicle, controller)
# Poll vehicle, if option is enabled
polling_option = PollingOptions.get_by_value(
config_entry.options.get(CONF_POLLING_OPTION, PollingOptions.DISABLE.value)
)
if polling_option == PollingOptions.CHARGING:
# Is there a better way to check if the subaru is charging?
e_registry = entity_registry.async_get(hass)
battery_charging = e_registry.async_get_device_class_lookup(
{(Platform.BINARY_SENSOR, BinarySensorDeviceClass.BATTERY_CHARGING)}
)
for item in battery_charging.values():
entity_id = item[
(BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING)
]
entity = e_registry.async_get(entity_id)
state = hass.states.get(entity_id)
if entity and state:
if entity.platform == DOMAIN and state.state == STATE_ON:
await poll_subaru(
vehicle,
controller,
update_interval=UPDATE_INTERVAL_CHARGING,
)
elif polling_option == PollingOptions.ENABLE:
await poll_subaru(vehicle, controller)

# Fetch data from Subaru servers
await refresh_subaru(vehicle, controller)
Expand Down
6 changes: 5 additions & 1 deletion custom_components/subaru/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ def _create_sensor_entities(entities, vehicle_info, coordinator):
not in sc.BAD_BINARY_SENSOR_VALUES
):
entities.append(
SubaruBinarySensor(vehicle_info, coordinator, sensor_description,)
SubaruBinarySensor(
vehicle_info,
coordinator,
sensor_description,
)
)


Expand Down
6 changes: 5 additions & 1 deletion custom_components/subaru/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ def create_vehicle_buttons(vehicle_info, coordinator, config_entry):

return [
SubaruButton(
vehicle_info, config_entry, coordinator, b[BUTTON_TYPE], b[BUTTON_SERVICE],
vehicle_info,
config_entry,
coordinator,
b[BUTTON_TYPE],
b[BUTTON_SERVICE],
)
for b in buttons_to_add
]
Expand Down
23 changes: 10 additions & 13 deletions custom_components/subaru/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,10 @@
from homeassistant import config_entries
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_PIN, CONF_USERNAME
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client, config_validation as cv

from .const import (
CONF_COUNTRY,
CONF_NOTIFICATION_OPTION,
CONF_UPDATE_ENABLED,
DOMAIN,
NotificationOptions,
)
from homeassistant.helpers import aiohttp_client

from .const import CONF_COUNTRY, CONF_NOTIFICATION_OPTION, CONF_POLLING_OPTION, DOMAIN
from .options import NotificationOptions, PollingOptions

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -206,13 +201,15 @@ async def async_step_init(self, user_input=None):
data_schema = vol.Schema(
{
vol.Required(
CONF_UPDATE_ENABLED,
default=self.config_entry.options.get(CONF_UPDATE_ENABLED, False),
): cv.boolean,
CONF_POLLING_OPTION,
default=self.config_entry.options.get(
CONF_POLLING_OPTION, PollingOptions.DISABLE.value
),
): vol.In(sorted(PollingOptions.list())),
vol.Required(
CONF_NOTIFICATION_OPTION,
default=self.config_entry.options.get(
CONF_NOTIFICATION_OPTION, NotificationOptions.FAILURE.value
CONF_NOTIFICATION_OPTION, NotificationOptions.DISABLE.value
),
): vol.In(sorted(NotificationOptions.list())),
}
Expand Down
Loading

0 comments on commit 32e8c81

Please sign in to comment.