Compare commits

..
5 Commits
Author SHA1 Message Date
Linus Dietz 8803f9ff1d Add api backend state sensor 2023-11-20 19:33:27 +01:00
Linus Dietz 843e00acd1 Move battery charge to v2 endpoint 2023-11-20 18:34:57 +01:00
Linus Dietz 3be0a4edbf Bump version 2023-11-20 07:49:34 +01:00
Linus Dietz 22cf71f007 Fix distance to empty sensor 2023-11-20 07:46:37 +01:00
Linus Dietz b7feb9713b Remove unused service warning trigger 2023-11-20 07:43:42 +01:00
5 changed files with 45 additions and 15 deletions
+12
View File
@@ -1,3 +1,15 @@
## v1.8.15
### 🚀 Features:
- Move `batteryChargeLevel` to the new v2 fuel endpoint
- Add api backend status sensor
## v1.8.14
### 🐛 Bug Fixes:
- Fix distance to empty sensor #127
- Remove unused service warning trigger sensor
## v1.8.13 ## v1.8.13
### 🐛 Bug Fixes: ### 🐛 Bug Fixes:
+1 -1
View File
@@ -1,6 +1,6 @@
name: "Volvo2Mqtt" name: "Volvo2Mqtt"
description: "Volvo AAOS MQTT bridge" description: "Volvo AAOS MQTT bridge"
version: "1.8.13" version: "1.8.15"
slug: "volvo2mqtt" slug: "volvo2mqtt"
init: false init: false
url: "https://github.com/Dielee/volvo2mqtt" url: "https://github.com/Dielee/volvo2mqtt"
+5 -4
View File
@@ -1,6 +1,6 @@
from config import settings from config import settings
VERSION = "v1.8.13" VERSION = "v1.8.15"
OAUTH_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2" OAUTH_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2"
VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles" VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles"
@@ -16,11 +16,12 @@ ODOMETER_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0
LOCATION_STATE_URL = "https://api.volvocars.com/location/v1/vehicles/{0}/location" LOCATION_STATE_URL = "https://api.volvocars.com/location/v1/vehicles/{0}/location"
TYRE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/tyres" TYRE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/tyres"
ENGINE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/engine-status" ENGINE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/engine-status"
BATTERY_CHARGE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles/{0}/battery-charge-level" BATTERY_CHARGE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/fuel"
FUEL_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/fuel" FUEL_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/fuel"
STATISTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/statistics" STATISTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/statistics"
ENGINE_DIAGNOSTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/engine" ENGINE_DIAGNOSTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/engine"
VEHICLE_DIAGNOSTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/diagnostics" VEHICLE_DIAGNOSTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/diagnostics"
API_BACKEND_STATUS = "https://oip-dev-bff.euwest1.production.volvo.care/api/v1/backend-status"
units = { units = {
"en_GB": { "en_GB": {
@@ -116,7 +117,7 @@ supported_entities = [
{"name": "Distance to Service", "domain": "sensor", "id": "km_to_service", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["distance_to_service"]["unit"], "icon": "wrench-clock", "url": VEHICLE_DIAGNOSTICS_URL}, {"name": "Distance to Service", "domain": "sensor", "id": "km_to_service", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["distance_to_service"]["unit"], "icon": "wrench-clock", "url": VEHICLE_DIAGNOSTICS_URL},
{"name": "Time to Service", "domain": "sensor", "id": "time_to_service", "icon": "wrench-clock", "url": VEHICLE_DIAGNOSTICS_URL}, {"name": "Time to Service", "domain": "sensor", "id": "time_to_service", "icon": "wrench-clock", "url": VEHICLE_DIAGNOSTICS_URL},
{"name": "Service warning status", "domain": "sensor", "id": "service_warning_status", "icon": "alert-outline", "url": VEHICLE_DIAGNOSTICS_URL}, {"name": "Service warning status", "domain": "sensor", "id": "service_warning_status", "icon": "alert-outline", "url": VEHICLE_DIAGNOSTICS_URL},
{"name": "Service warning trigger", "domain": "sensor", "id": "service_warning_trigger", "icon": "alert-outline", "url": VEHICLE_DIAGNOSTICS_URL} {"name": "API Backend status", "domain": "sensor", "id": "api_backend_status", "icon": "alert"}
] ]
old_entity_ids = ["months_to_service"] old_entity_ids = ["months_to_service", "service_warning_trigger"]
+3 -2
View File
@@ -243,6 +243,8 @@ def update_car_data(force_update=False, overwrite={}):
state = last_data_update state = last_data_update
elif entity["id"] == "active_schedules": elif entity["id"] == "active_schedules":
state = active_schedules[vin] state = active_schedules[vin]
elif entity["id"] == "api_backend_status":
state = volvo.backend_status
else: else:
if entity["id"] == ov_entity_id and vin == ov_vin: if entity["id"] == ov_entity_id and vin == ov_vin:
state = ov_state state = ov_state
@@ -265,8 +267,7 @@ def update_car_data(force_update=False, overwrite={}):
def update_ha_device(entity, vin, state): def update_ha_device(entity, vin, state):
icon_config = icon_states.get(entity["id"]) icon_config = icon_states.get(entity["id"])
if icon_config and state: if icon_config and state:
if state.replace(".", "").isnumeric(): if isinstance(state, float):
state = float(state)
icon = util.get_icon_between(icon_config, state) icon = util.get_icon_between(icon_config, state)
else: else:
icon = icon_config[state] icon = icon_config[state]
+24 -8
View File
@@ -4,7 +4,7 @@ import mqtt
import util import util
import time import time
import re import re
from threading import current_thread from threading import current_thread, Thread
from datetime import datetime, timedelta from datetime import datetime, timedelta
from config import settings from config import settings
from babel.dates import format_datetime from babel.dates import format_datetime
@@ -12,7 +12,7 @@ from json import JSONDecodeError
from const import charging_system_states, charging_connection_states, door_states, window_states, \ from const import charging_system_states, charging_connection_states, door_states, window_states, \
OAUTH_URL, VEHICLES_URL, VEHICLE_DETAILS_URL, RECHARGE_STATE_URL, CLIMATE_START_URL, \ OAUTH_URL, VEHICLES_URL, VEHICLE_DETAILS_URL, RECHARGE_STATE_URL, CLIMATE_START_URL, \
WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL, supported_entities, BATTERY_CHARGE_STATE_URL, \ WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL, supported_entities, BATTERY_CHARGE_STATE_URL, \
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, engine_states STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, API_BACKEND_STATUS, engine_states
session = requests.Session() session = requests.Session()
session.headers = { session.headers = {
@@ -27,6 +27,7 @@ vins = []
supported_endpoints = {} supported_endpoints = {}
cached_requests = {} cached_requests = {}
vcc_api_keys = [] vcc_api_keys = []
backend_status = ""
def authorize(): def authorize():
@@ -54,6 +55,7 @@ def authorize():
get_vcc_api_keys() get_vcc_api_keys()
get_vehicles() get_vehicles()
check_supported_endpoints() check_supported_endpoints()
Thread(target=get_backend_status).start()
else: else:
message = auth.json() message = auth.json()
raise Exception(message["error_description"]) raise Exception(message["error_description"])
@@ -314,6 +316,20 @@ def check_engine_status(vin):
time.sleep(5) time.sleep(5)
def get_backend_status():
global backend_status
while True:
response = session.get(API_BACKEND_STATUS, timeout=15)
try:
data = response.json()
backend_status = data["message"] if util.keys_exists(data, "message") else "No warnings"
except JSONDecodeError as e:
backend_status = "No warnings"
# Update every hour
time.sleep(3600)
def api_call(url, method, vin, sensor_id=None, force_update=False, key_change=False): def api_call(url, method, vin, sensor_id=None, force_update=False, key_change=False):
if datetime.now(util.TZ) >= token_expires_at: if datetime.now(util.TZ) >= token_expires_at:
refresh_auth() refresh_auth()
@@ -411,7 +427,9 @@ def cached_request(url, method, vin, force_update=False, key_change=False):
def parse_api_data(data, sensor_id=None): def parse_api_data(data, sensor_id=None):
data = data["data"] if sensor_id != "api_backend_status":
data = data["data"]
if sensor_id == "battery_charge_level": if sensor_id == "battery_charge_level":
return data["batteryChargeLevel"]["value"] if util.keys_exists(data, "batteryChargeLevel") else None return data["batteryChargeLevel"]["value"] if util.keys_exists(data, "batteryChargeLevel") else None
elif sensor_id == "electric_range": elif sensor_id == "electric_range":
@@ -536,10 +554,10 @@ def parse_api_data(data, sensor_id=None):
"gps_accuracy": 1} "gps_accuracy": 1}
return coordinates return coordinates
elif sensor_id == "distance_to_empty": elif sensor_id == "distance_to_empty":
if util.keys_exists(data, "distanceToEmpty"): if util.keys_exists(data, "distanceToEmptyTank"):
distance_to_empty = int(data["distanceToEmpty"]["value"]) distance_to_empty = int(data["distanceToEmptyTank"]["value"])
if distance_to_empty > 0: if distance_to_empty > 0:
return util.convert_metric_values(data["distanceToEmpty"]["value"]) return util.convert_metric_values(data["distanceToEmptyTank"]["value"])
return None return None
elif sensor_id == "hours_to_service": elif sensor_id == "hours_to_service":
return data["engineHoursToService"]["value"] if util.keys_exists(data, "engineHoursToService") else None return data["engineHoursToService"]["value"] if util.keys_exists(data, "engineHoursToService") else None
@@ -556,7 +574,5 @@ def parse_api_data(data, sensor_id=None):
return None return None
elif sensor_id == "service_warning_status": elif sensor_id == "service_warning_status":
return data["serviceWarning"]["value"] if util.keys_exists(data, "serviceWarning") else None return data["serviceWarning"]["value"] if util.keys_exists(data, "serviceWarning") else None
elif sensor_id == "service_warning_trigger":
return data["serviceTrigger"]["value"] if util.keys_exists(data, "serviceTrigger") else None
else: else:
return None return None