This commit is contained in:
2023-02-26 11:43:30 +01:00
parent 5128fa7358
commit 29a74e2546
198 changed files with 17865 additions and 20642 deletions

View File

@@ -10,7 +10,8 @@ from homeassistant.const import (
CONF_SCAN_INTERVAL,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.exceptions import ConfigEntryNotReady, ConfigEntryAuthFailed
from hyundai_kia_connect_api.exceptions import *
import hashlib
from .const import (
@@ -52,9 +53,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
await coordinator.async_config_entry_first_refresh()
except Exception as ex:
raise ConfigEntryNotReady(f"Config Not Ready: {ex}")
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.unique_id] = coordinator
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)
await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
async_setup_services(hass)
return True

View File

@@ -117,6 +117,38 @@ SENSOR_DESCRIPTIONS: Final[tuple[HyundaiKiaBinarySensorEntityDescription, ...]]
off_icon="mdi:car",
device_class=BinarySensorDeviceClass.DOOR,
),
HyundaiKiaBinarySensorEntityDescription(
key="front_left_window_is_open",
name="Front Left Window",
is_on=lambda vehicle: vehicle.front_left_window_is_open,
on_icon="mdi:car-door",
off_icon="mdi:car-door",
device_class=BinarySensorDeviceClass.WINDOW,
),
HyundaiKiaBinarySensorEntityDescription(
key="front_right_window_is_open",
name="Front Right Window",
is_on=lambda vehicle: vehicle.front_right_window_is_open,
on_icon="mdi:car-door",
off_icon="mdi:car-door",
device_class=BinarySensorDeviceClass.WINDOW,
),
HyundaiKiaBinarySensorEntityDescription(
key="back_left_window_is_open",
name="Back Left Window",
is_on=lambda vehicle: vehicle.back_left_window_is_open,
on_icon="mdi:car-door",
off_icon="mdi:car-door",
device_class=BinarySensorDeviceClass.WINDOW,
),
HyundaiKiaBinarySensorEntityDescription(
key="back_right_window_is_open",
name="Back Right Window",
is_on=lambda vehicle: vehicle.back_right_window_is_open,
on_icon="mdi:car-door",
off_icon="mdi:car-door",
device_class=BinarySensorDeviceClass.WINDOW,
),
HyundaiKiaBinarySensorEntityDescription(
key="ev_battery_is_charging",
name="EV Battery Charge",
@@ -207,6 +239,20 @@ SENSOR_DESCRIPTIONS: Final[tuple[HyundaiKiaBinarySensorEntityDescription, ...]]
off_icon="mdi:ev-station",
device_class=BinarySensorDeviceClass.DOOR,
),
HyundaiKiaBinarySensorEntityDescription(
key="ev_first_departure_enabled",
name="EV First Scheduled Departure",
is_on=lambda vehicle: vehicle.ev_first_departure_enabled,
on_icon="mdi:clock-outline",
off_icon="mdi:clock-outline",
),
HyundaiKiaBinarySensorEntityDescription(
key="ev_second_departure_enabled",
name="EV Second Scheduled Departure",
is_on=lambda vehicle: vehicle.ev_second_departure_enabled,
on_icon="mdi:clock-outline",
off_icon="mdi:clock-outline",
),
)

View File

@@ -83,13 +83,13 @@ class HyundaiKiaConnectOptionFlowHandler(config_entries.OptionsFlow):
default=self.config_entry.options.get(
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
),
): vol.All(vol.Coerce(int), vol.Range(min=5, max=999)),
): vol.All(vol.Coerce(int), vol.Range(min=15, max=999)),
vol.Required(
CONF_FORCE_REFRESH_INTERVAL,
default=self.config_entry.options.get(
CONF_FORCE_REFRESH_INTERVAL, DEFAULT_FORCE_REFRESH_INTERVAL
),
): vol.All(vol.Coerce(int), vol.Range(min=30, max=999)),
): vol.All(vol.Coerce(int), vol.Range(min=45, max=999)),
vol.Required(
CONF_NO_FORCE_REFRESH_HOUR_START,
default=self.config_entry.options.get(
@@ -163,12 +163,19 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
title = f"{BRANDS[user_input[CONF_BRAND]]} {REGIONS[user_input[CONF_REGION]]} {user_input[CONF_USERNAME]}"
await self.async_set_unique_id(
hashlib.sha256(title.encode("utf-8")).hexdigest()
)
self._abort_if_unique_id_configured()
return self.async_create_entry(title=title, data=user_input)
if self.reauth_entry is None:
title = f"{BRANDS[user_input[CONF_BRAND]]} {REGIONS[user_input[CONF_REGION]]} {user_input[CONF_USERNAME]}"
await self.async_set_unique_id(
hashlib.sha256(title.encode("utf-8")).hexdigest()
)
self._abort_if_unique_id_configured()
return self.async_create_entry(title=title, data=user_input)
else:
self.hass.config_entries.async_update_entry(
self.reauth_entry, data=user_input
)
await self.hass.config_entries.async_reload(self.reauth_entry.entry_id)
return self.async_abort(reason="reauth_successful")
return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
@@ -188,7 +195,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
step_id="reauth_confirm",
data_schema=vol.Schema({}),
)
self._reauth = True
self._reauth_config = True
return await self.async_step_user()

View File

@@ -10,6 +10,9 @@ from hyundai_kia_connect_api import (
VehicleManager,
ClimateRequestOptions,
)
from hyundai_kia_connect_api.exceptions import *
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
@@ -19,6 +22,7 @@ from homeassistant.const import (
CONF_SCAN_INTERVAL,
CONF_USERNAME,
)
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.util import dt as dt_util
@@ -99,7 +103,10 @@ class HyundaiKiaConnectDataUpdateCoordinator(DataUpdateCoordinator):
Allow to update for the first time without further checking
Allow force update, if time diff between latest update and `now` is greater than force refresh delta
"""
await self.async_check_and_refresh_token()
try:
await self.async_check_and_refresh_token()
except AuthenticationError as AuthError:
raise ConfigEntryAuthFailed(AuthError) from AuthError
current_hour = dt_util.now().hour
if (
@@ -126,7 +133,7 @@ class HyundaiKiaConnectDataUpdateCoordinator(DataUpdateCoordinator):
self.vehicle_manager.update_all_vehicles_with_cached_state
)
_LOGGER.exception(
"Force update failed, falling back to cached: {err}"
f"Force update failed, falling back to cached: {err}"
)
except Exception as err_nested:
raise UpdateFailed(f"Error communicating with API: {err_nested}")

View File

@@ -47,8 +47,8 @@ class HyundaiKiaConnectLock(LockEntity, HyundaiKiaConnectEntity):
def is_locked(self):
return getattr(self.vehicle, "is_locked")
async def async_lock(self):
async def async_lock(self, **kwargs: Any):
await self.coordinator.async_lock_vehicle(self.vehicle.id)
async def async_unlock(self):
async def async_unlock(self, **kwargs: Any):
await self.coordinator.async_unlock_vehicle(self.vehicle.id)

View File

@@ -4,8 +4,8 @@
"documentation": "https://github.com/fuatakgun/kia_uvo",
"issue_tracker": "https://github.com/fuatakgun/kia_uvo/issues",
"codeowners": ["@fuatakgun"],
"requirements": ["hyundai_kia_connect_api==1.50.3"],
"version": "2.2.1",
"requirements": ["hyundai_kia_connect_api==3.1.0"],
"version": "2.6.0",
"config_flow": true,
"iot_class": "cloud_polling",
"integration_type": "hub"

View File

@@ -6,7 +6,11 @@ from typing import Final
from hyundai_kia_connect_api import Vehicle, VehicleManager
from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.components.number import (
NumberEntity,
NumberEntityDescription,
NumberMode,
)
from homeassistant.const import PERCENTAGE
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@@ -74,6 +78,7 @@ class HyundaiKiaConnectNumber(NumberEntity, HyundaiKiaConnectEntity):
self._key = self._description.key
self._attr_unique_id = f"{DOMAIN}_{vehicle.id}_{self._key}"
self._attr_icon = self._description.icon
self._attr_mode = NumberMode.BOX
self._attr_name = f"{vehicle.name} {self._description.name}"
self._attr_device_class = self._description.device_class

View File

@@ -190,6 +190,26 @@ SENSOR_DESCRIPTIONS: Final[tuple[SensorEntityDescription, ...]] = (
name="DTC Count",
icon="mdi:alert-circle",
),
SensorEntityDescription(
key="ev_first_departure_time",
name="EV First Scheduled Depature Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_second_departure_time",
name="EV Second Scheduled Depature Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_off_peak_start_time",
name="EV Off Peak Start Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_off_peak_end_time",
name="EV Off Peak End Time",
icon="mdi:clock-outline",
),
)

View File

@@ -110,8 +110,12 @@ def async_setup_services(hass: HomeAssistant) -> bool:
ac = call.data.get("ac_limit")
dc = call.data.get("dc_limit")
if ac is not None or dc is not None:
await coordinator.set_charge_limits(vehicle_id, ac, dc)
if ac is not None and dc is not None:
await coordinator.set_charge_limits(vehicle_id, int(ac), int(dc))
else:
_LOGGER.error(
f"{DOMAIN} - Enable to set charge limits. Both AC and DC value required, but not provided."
)
services = {
SERVICE_FORCE_UPDATE: async_handle_force_update,
@@ -139,6 +143,13 @@ def async_unload_services(hass) -> None:
def _get_vehicle_id_from_device(hass: HomeAssistant, call: ServiceCall) -> str:
coordinators = list(hass.data[DOMAIN].keys())
if len(coordinators) == 1:
coordinator = hass.data[DOMAIN][coordinators[0]]
vehicles = coordinator.vehicle_manager.vehicles
if len(vehicles) == 1:
return list(vehicles.keys())[0]
device_entry = device_registry.async_get(hass).async_get(call.data[ATTR_DEVICE_ID])
for entry in device_entry.identifiers:
if entry[0] == DOMAIN:
@@ -149,21 +160,27 @@ def _get_vehicle_id_from_device(hass: HomeAssistant, call: ServiceCall) -> str:
def _get_coordinator_from_device(
hass: HomeAssistant, call: ServiceCall
) -> HyundaiKiaConnectDataUpdateCoordinator:
device_entry = device_registry.async_get(hass).async_get(call.data[ATTR_DEVICE_ID])
config_entry_ids = device_entry.config_entries
config_entry_id = next(
(
coordinators = list(hass.data[DOMAIN].keys())
if len(coordinators) == 1:
return hass.data[DOMAIN][coordinators[0]]
else:
device_entry = device_registry.async_get(hass).async_get(
call.data[ATTR_DEVICE_ID]
)
config_entry_ids = device_entry.config_entries
config_entry_id = next(
(
config_entry_id
for config_entry_id in config_entry_ids
if cast(
ConfigEntry,
hass.config_entries.async_get_entry(config_entry_id),
).domain
== DOMAIN
),
None,
)
config_entry_unique_id = hass.config_entries.async_get_entry(
config_entry_id
for config_entry_id in config_entry_ids
if cast(
ConfigEntry,
hass.config_entries.async_get_entry(config_entry_id),
).domain
== DOMAIN
),
None,
)
config_entry_unique_id = hass.config_entries.async_get_entry(
config_entry_id
).unique_id
return hass.data[DOMAIN][config_entry_unique_id]
).unique_id
return hass.data[DOMAIN][config_entry_unique_id]

View File

@@ -4,7 +4,7 @@ force_update:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -14,7 +14,7 @@ update:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -23,8 +23,8 @@ start_climate:
fields:
device_id:
name: Vehicle
description: Target vehicle
required: true
description: Target vehicle, if a single vehicle will use that by default.
required: false
selector:
device:
integration: kia_uvo
@@ -182,7 +182,7 @@ stop_climate:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -192,7 +192,7 @@ start_charge:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -202,7 +202,7 @@ stop_charge:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -212,7 +212,7 @@ lock:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -222,7 +222,7 @@ unlock:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -232,7 +232,7 @@ close_charge_port:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -242,7 +242,7 @@ open_charge_port:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo
@@ -252,7 +252,7 @@ set_charge_limits:
device_id:
name: Vehicle
description: Target vehicle
required: true
required: false
selector:
device:
integration: kia_uvo

View File

@@ -11,8 +11,8 @@
}
},
"reauth_confirm": {
"title": "[%key:common::config_flow::title::reauth%]",
"description": "The Hyundai / Kia Connect integration needs to re-authenticate your account"
"title": "[%key:component::hyundai_kia_connect::config::step::reauth_confirm::title%]",
"description": "[%key:component::hyundai_kia_connect::config::step::reauth_confirm::description%]"
}
},
"error": {
@@ -31,9 +31,11 @@
"scan_interval": "[%key:component::hyundai_kia_connect::options::step::init::data::scan_interval%]",
"force_refresh": "[%key:component::hyundai_kia_connect::options::step::init::data::force_refresh%]",
"no_force_refresh_hour_start": "[%key:component::hyundai_kia_connect::options::step::init::data::no_force_refresh_hour_start%]",
"no_force_refresh_hour_finish": "[%key:component::hyundai_kia_connect::options::step::init::data::no_force_refresh_hour_finish%]"
"no_force_refresh_hour_finish": "[%key:component::hyundai_kia_connect::options::step::init::data::no_force_refresh_hour_finish%]",
"enable_geolocation_entity": "[%key:component::hyundai_kia_connect::options::step::init::data::enable_geolocation_entity%]",
"use_email_with_geocode_api": "[%key:component::hyundai_kia_connect::options::step::init::data::use_email_with_geocode_api%]"
}
}
}
}
}
}

View File

@@ -1,40 +1,44 @@
{
"title": "Hyundai / Kia Connect",
"config": {
"step": {
"user": {
"title": "Hyundai / Kia Connect - Authentication",
"description": "Set up your Hyundai (Bluelink) / Kia (Uvo) Connect to integrate with Home Assistant.",
"data": {
"username": "Username",
"password": "Password",
"region": "Region",
"brand": "Brand",
"pin": "Pin (Required for CA)"
}
}
"title":"Hyundai / Kia Connect",
"config":{
"step":{
"user":{
"title":"Hyundai / Kia Connect - Authentication",
"description":"Set up your Hyundai (Bluelink) / Kia (Uvo) Connect to integrate with Home Assistant.",
"data":{
"username":"Username",
"password":"Password",
"region":"Region",
"brand":"Brand",
"pin":"Pin (Required for CA)"
}
},
"reauth_confirm":{
"title":"Hyundai / Kia Connect - Reauthentication",
"description":"Your account is unable to authenticate. Click Submit to re-setup."
}
},
"abort":{
"already_configured":"Device is already configured"
},
"abort": {
"already_configured": "Device is already configured"
},
"error": {
"invalid_auth": "Login failed into Hyundai (Bluelink) / Kia (Uvo) Connect Servers. Please use official app to logout and log back in and try again!",
"unknown": "Unexpected error"
}
"error":{
"invalid_auth":"Login failed into Hyundai (Bluelink) / Kia (Uvo) Connect Servers. Please use official app to logout and log back in and try again!",
"unknown":"Unexpected error"
}
},
"options": {
"step": {
"init": {
"title": "Hyundai / Kia Connect - Configuration",
"data": {
"scan_interval": "Scan Interval (min)",
"force_refresh": "Force Refresh Interval (min)",
"no_force_refresh_hour_start": "No Force Refresh Start Hour",
"no_force_refresh_hour_finish": "No Force Refresh Finish Hour",
"enable_geolocation_entity": "Enable Geolocation Entity using OpenStreetMap",
"use_email_with_geocode_api": "Use your Kia email address for Geocode API - More Information: https://nominatim.org/release-docs/develop/api/Reverse/#other"
}
}
}
"options":{
"step":{
"init":{
"title":"Hyundai / Kia Connect - Configuration",
"data":{
"scan_interval":"Scan Interval (min)",
"force_refresh":"Force Refresh Interval (min)",
"no_force_refresh_hour_start":"No Force Refresh Start Hour",
"no_force_refresh_hour_finish":"No Force Refresh Finish Hour",
"enable_geolocation_entity":"Enable Geolocation Entity using OpenStreetMap",
"use_email_with_geocode_api":"Use your Kia email address for Geocode API - More Information: https://nominatim.org/release-docs/develop/api/Reverse/#other"
}
}
}
}
}
}