Compare commits

...
20 Commits
Author SHA1 Message Date
Linus Dietz 1223853208 Bump version 2023-11-21 08:59:25 +01:00
Linus Dietz 1f0c52b5a7 Add average energy consumption, distance to empty battery and washer fluid level sensor 2023-11-21 08:55:27 +01:00
Linus Dietz 161c02fc11 Support force update for backend state 2023-11-21 08:25:33 +01:00
Linus Dietz be4a1b6791 Use cached requests for fuel endpoints 2023-11-21 08:19:26 +01:00
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
Linus DietzandGitHub 1f53ef0198 Update CHANGELOG.md 2023-11-17 17:58:31 +01:00
Linus Dietz d07e6dfe6e Add "Time to Service" sensor 2023-11-17 17:57:30 +01:00
Linus Dietz 80473d5120 Fix apparmor for Debian 12 2023-11-11 14:56:41 +01:00
Linus Dietz 81b2771c80 Fix AJAR state for windows 2023-11-11 14:51:52 +01:00
Linus Dietz f1953e1baa Quality optimizations 2023-11-10 09:21:00 +01:00
Linus Dietz 459c2dc1af Add AJAR state for sunroof #123 2023-11-10 09:05:03 +01:00
Linus Dietz be09c7953e Merge remote-tracking branch 'origin/main' into main 2023-11-09 18:27:51 +01:00
Linus Dietz fa68c4ba2c Fix api changes from volvo 2023-11-09 18:27:31 +01:00
Linus DietzandGitHub d7a79f84a4 add XC90 mild 2023-10-23 20:16:01 +02:00
Linus Dietz 2c8effd746 Fix version for HA addon 2023-10-09 10:29:12 +02:00
Linus Dietz cef28f7d0b Fix 'ACL denying access to client with dangerous client id' 2023-09-21 15:22:18 +02:00
7 changed files with 167 additions and 74 deletions
+1
View File
@@ -32,6 +32,7 @@ If you like my work:<br>
- XC60 PHEV (2022)
- XC90 PHEV T8 (2023)
- XC90 PHEV T8 (2024)
- XC90 B5 Mildhybrid (2024)
- V90 PHEV T8 (2019)*
*only partly working
+49 -1
View File
@@ -1,3 +1,51 @@
## v1.8.16
### 🚀 Features:
- Add `Average energy consumption`, `Distance to empty battery` and `Washer fluid level` sensors
- Support force update for `Backend state` Sensor
- Use cached requests for fuel endpoint
## 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
### 🐛 Bug Fixes:
- Add "Time to Service" sensor #125<p>
<b>Breaking change: The "Months to Service" sensor will be automatically deleted.<br>
"Time to Service" contains this information now.
## v1.8.12
### 🐛 Bug Fixes:
- Fix `AJAR` state for windows
- Fix deprecation from `currentThread` to `current_thread`
## v1.8.11
### 🐛 Bug Fixes:
- Remove old code from checks for running engine sensor
- Move battery charge level sensor from v2 to v1, as v2 returns 404
## v1.8.10
### 🐛 Bug Fixes:
- Add `AJAR` state for sunroof #123
## v1.8.9
### 🐛 Bug Fixes:
- Fix api changes from volvo #121
## v1.8.8
### 🐛 Bug Fixes:
@@ -48,7 +96,7 @@
### 🚀 Features:
- <b>Breaking change: The `vccapikey` setting is now a list. It is possible to
add multiple VCCAPIKEYs. This will be helpful if you are extending your 10.000 call limit some times.
add multiple VCCAPIKEYs. This will be helpful if you are extending your 10.000 call limit sometimes.
Change your vccapikey config like this:
Old:
+2
View File
@@ -4,8 +4,10 @@ profile volvo2mqtt flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# Capabilities
capability,
file,
signal (send) set=(kill,term,int,hup,cont),
network,
# S6-Overlay
/init ix,
+1 -1
View File
@@ -1,6 +1,6 @@
name: "Volvo2Mqtt"
description: "Volvo AAOS MQTT bridge"
version: "1.8.7"
version: "1.8.16"
slug: "volvo2mqtt"
init: false
url: "https://github.com/Dielee/volvo2mqtt"
+15 -11
View File
@@ -1,6 +1,6 @@
from config import settings
VERSION = "v1.8.8"
VERSION = "v1.8.16"
OAUTH_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2"
VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles"
@@ -16,11 +16,11 @@ ODOMETER_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0
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"
ENGINE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/engine-status"
BATTERY_CHARGE_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/battery-charge-level"
FUEL_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/fuel"
FUEL_BATTERY_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/fuel"
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"
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 = {
"en_GB": {
@@ -50,8 +50,8 @@ charging_connection_states = {"CONNECTION_STATUS_DISCONNECTED": "Disconnected",
"CONNECTION_STATUS_CONNECTED_DC": "Connected DC", "CONNECTION_STATUS_CONNECTED_AC": "Connected AC",
"CONNECTION_STATUS_FAULT": "Fault"}
window_states = {"CLOSED": "OFF", "OPEN": "ON"}
door_states = {"CLOSED": "OFF", "OPEN": "ON"}
window_states = {"CLOSED": "OFF", "OPEN": "ON", "AJAR": "ON"}
door_states = {"CLOSED": "OFF", "OPEN": "ON", "UNSPECIFIED": "UNKNOWN", "AJAR": "ON"}
engine_states = {"RUNNING": "ON", "STOPPED": "OFF", "true": "ON", "false": "OFF"}
icon_states = {
@@ -78,7 +78,7 @@ icon_states = {
supported_entities = [
{"name": "Battery Charge Level", "domain": "sensor", "device_class": "battery", "id": "battery_charge_level", "unit": "%", "icon": "car-battery", "url": RECHARGE_STATE_URL, "state_class": "measurement"},
{"name": "Battery Charge Level", "domain": "sensor", "device_class": "battery", "id": "battery_charge_level", "unit": "%", "icon": "car-battery", "url": BATTERY_CHARGE_STATE_URL, "state_class": "measurement"},
{"name": "Battery Charge Level", "domain": "sensor", "device_class": "battery", "id": "battery_charge_level", "unit": "%", "icon": "car-battery", "url": FUEL_BATTERY_STATE_URL, "state_class": "measurement"},
{"name": "Electric Range", "domain": "sensor", "id": "electric_range", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["electric_range"]["unit"], "icon": "map-marker-distance", "url": RECHARGE_STATE_URL, "state_class": "measurement"},
{"name": "Estimated Charging Time", "domain": "sensor", "id": "estimated_charging_time", "unit": "minutes", "icon": "timer-sync-outline", "url": RECHARGE_STATE_URL, "state_class": "measurement"},
{"name": "Charging System Status", "domain": "sensor", "id": "charging_system_status", "icon": "ev-station", "url": RECHARGE_STATE_URL},
@@ -108,14 +108,18 @@ supported_entities = [
{"name": "Tire Rear Left", "domain": "sensor", "id": "tyre_rear_left", "icon": "car-tire-alert", "url": TYRE_STATE_URL},
{"name": "Tire Rear Right", "domain": "sensor", "id": "tyre_rear_right", "icon": "car-tire-alert", "url": TYRE_STATE_URL},
{"name": "Engine State", "domain": "binary_sensor", "device_class": "running", "id": "engine_state", "icon": "engine", "url": ENGINE_STATE_URL},
{"name": "Engine State", "domain": "binary_sensor", "device_class": "running", "id": "engine_state", "icon": "engine", "url": ENGINE_DIAGNOSTICS_URL},
{"name": "Fuel Level", "domain": "sensor", "id": "fuel_level", "unit": "liters", "icon": "fuel", "url": FUEL_STATE_URL, "state_class": "measurement"},
{"name": "Fuel Level", "domain": "sensor", "id": "fuel_level", "unit": "liters", "icon": "fuel", "url": FUEL_BATTERY_STATE_URL, "state_class": "measurement"},
{"name": "Average Fuel Consumption", "domain": "sensor", "id": "average_fuel_consumption", "unit": "liters", "icon": "fuel", "url": STATISTICS_URL},
{"name": "Distance to Empty", "domain": "sensor", "id": "distance_to_empty", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["distance_to_empty"]["unit"], "icon": "map-marker-distance", "url": STATISTICS_URL, "state_class": "measurement"},
{"name": "Average Energy Consumption", "domain": "sensor", "id": "average_energy_consumption", "unit": "kwh", "icon": "car-electric", "url": STATISTICS_URL},
{"name": "Distance to Empty Tank", "domain": "sensor", "id": "distance_to_empty_tank", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["distance_to_empty"]["unit"], "icon": "map-marker-distance", "url": STATISTICS_URL, "state_class": "measurement"},
{"name": "Distance to Empty Battery", "domain": "sensor", "id": "distance_to_empty_battery", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["distance_to_empty"]["unit"], "icon": "map-marker-distance", "url": STATISTICS_URL, "state_class": "measurement"},
{"name": "Average Speed", "domain": "sensor", "id": "average_speed", "unit": "km/h" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["average_speed"]["unit"], "icon": "speedometer", "url": STATISTICS_URL, "state_class": "measurement"},
{"name": "Hours to Service", "domain": "sensor", "id": "hours_to_service", "unit": "hour", "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": "Months to Service", "domain": "sensor", "id": "months_to_service", "unit": "month", "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 trigger", "domain": "sensor", "id": "service_warning_trigger", "icon": "alert-outline", "url": VEHICLE_DIAGNOSTICS_URL}
{"name": "Washer Fluid Level warning", "domain": "sensor", "id": "washer_fluid_warning", "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", "service_warning_trigger", "distance_to_empty"]
+26 -17
View File
@@ -10,8 +10,7 @@ from datetime import datetime
from babel.dates import format_datetime
from config import settings
from const import CLIMATE_START_URL, CLIMATE_STOP_URL, CAR_LOCK_URL, \
CAR_UNLOCK_URL, availability_topic, icon_states
CAR_UNLOCK_URL, availability_topic, icon_states, old_entity_ids
mqtt_client: mqtt.Client
subscribed_topics = []
@@ -25,7 +24,7 @@ active_schedules = {}
def connect():
client = mqtt.Client("volvoAAOS2mqtt") if os.environ.get("IS_HA_ADDON") \
else mqtt.Client("volvoAAOS2mqtt_" + settings.volvoData["username"])
else mqtt.Client("volvoAAOS2mqtt_" + settings.volvoData["username"].replace("+", ""))
client.will_set(availability_topic, "offline", 0, False)
if settings["mqtt"]["username"] and settings["mqtt"]["password"]:
@@ -90,7 +89,7 @@ def on_connect(client, userdata, flags, rc):
mqtt_client.subscribe(topic)
def on_disconnect(client, userdata, rc):
def on_disconnect(client, userdata, rc):
logging.warning("MQTT disconnected, reconnecting automatically")
@@ -141,7 +140,7 @@ def start_climate_timer(d, vin):
return None
if timer_seconds > 0:
Timer(timer_seconds, activate_climate_timer, (vin, start_datetime.isoformat(), )).start()
Timer(timer_seconds, activate_climate_timer, (vin, start_datetime.isoformat(),)).start()
active_schedules[vin]["timers"].append(start_datetime.isoformat())
logging.debug("Climate timer set to " + str(start_datetime))
update_car_data()
@@ -244,6 +243,11 @@ def update_car_data(force_update=False, overwrite={}):
state = last_data_update
elif entity["id"] == "active_schedules":
state = active_schedules[vin]
elif entity["id"] == "api_backend_status":
if force_update:
state = volvo.get_backend_status()
else:
state = volvo.backend_status
else:
if entity["id"] == ov_entity_id and vin == ov_vin:
state = ov_state
@@ -266,8 +270,7 @@ def update_car_data(force_update=False, overwrite={}):
def update_ha_device(entity, vin, state):
icon_config = icon_states.get(entity["id"])
if icon_config and state:
if state.replace(".", "").isnumeric():
state = float(state)
if isinstance(state, float):
icon = util.get_icon_between(icon_config, state)
else:
icon = icon_config[state]
@@ -293,7 +296,7 @@ def update_ha_device(entity, vin, state):
if entity.get("state_class"):
config["state_class"] = entity["state_class"]
if entity.get("domain") == "device_tracker":
config["json_attributes_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes"
@@ -317,15 +320,15 @@ def create_ha_devices():
devices[vin] = device
for entity in volvo.supported_endpoints[vin]:
config = {
"name": entity['name'],
"object_id": f"volvo_{vin}_{entity['id']}",
"schema": "state",
"icon": f"mdi:{entity['icon']}",
"state_topic": f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state",
"device": device,
"unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}",
"availability_topic": availability_topic
}
"name": entity['name'],
"object_id": f"volvo_{vin}_{entity['id']}",
"schema": "state",
"icon": f"mdi:{entity['icon']}",
"state_topic": f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state",
"device": device,
"unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}",
"availability_topic": availability_topic
}
if entity.get("device_class"):
config["device_class"] = entity["device_class"]
@@ -361,3 +364,9 @@ def send_heartbeat():
def send_offline():
mqtt_client.publish(availability_topic, "offline")
def delete_old_entities():
for vin in volvo.vins:
for entity in old_entity_ids:
topic = f"homeassistant/sensor/volvoAAOS2mqtt/{vin}_{entity}/config"
mqtt_client.publish(topic, payload="", retain=True)
+73 -44
View File
@@ -4,15 +4,15 @@ import mqtt
import util
import time
import re
from threading import currentThread
from threading import current_thread, Thread
from datetime import datetime, timedelta
from config import settings
from babel.dates import format_datetime
from json import JSONDecodeError
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, \
WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL, supported_entities, BATTERY_CHARGE_STATE_URL, \
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, engine_states
WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL, supported_entities, FUEL_BATTERY_STATE_URL, \
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, API_BACKEND_STATUS, engine_states
session = requests.Session()
session.headers = {
@@ -27,6 +27,7 @@ vins = []
supported_endpoints = {}
cached_requests = {}
vcc_api_keys = []
backend_status = ""
def authorize():
@@ -54,6 +55,7 @@ def authorize():
get_vcc_api_keys()
get_vehicles()
check_supported_endpoints()
Thread(target=backend_status_loop).start()
else:
message = auth.json()
raise Exception(message["error_description"])
@@ -116,6 +118,7 @@ def get_vehicles():
else:
initialize_climate(vins)
initialize_scheduler(vins)
mqtt.delete_old_entities()
logging.info("Vin: " + str(vins) + " found!")
@@ -240,16 +243,11 @@ def check_supported_endpoints():
for vin in vins:
supported_endpoints[vin] = []
for entity in supported_entities:
if entity["id"] == "battery_charge_level" and entity["url"] == BATTERY_CHARGE_STATE_URL \
if entity["id"] == "battery_charge_level" and entity["url"] == FUEL_BATTERY_STATE_URL \
and any("battery_charge_level" in d["id"] for d in supported_endpoints[vin]):
# If battery charge level could be found in recharge-api, skip the second battery charge sensor
continue
if entity["id"] == "engine_state" and entity["url"] == ENGINE_DIAGNOSTICS_URL \
and any("engine_state" in d["id"] for d in supported_endpoints[vin]):
# If engine state could be found in engine state endpoint, skip the second engine running sensor
continue
if entity.get('url'):
state = api_call(entity["url"], "GET", vin, entity["id"])
else:
@@ -308,7 +306,7 @@ def check_engine_status(vin):
# Exit thread as engine state is unsupported by car
return None
t = currentThread()
t = current_thread()
while getattr(t, "do_run", True):
engine_state = api_call(endpoint_url, "GET", vin, "engine_state", True)
if engine_state == "ON":
@@ -318,12 +316,30 @@ def check_engine_status(vin):
time.sleep(5)
def backend_status_loop():
while True:
get_backend_status()
# Update every hour
time.sleep(3600)
def get_backend_status():
global backend_status
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"
return backend_status
def api_call(url, method, vin, sensor_id=None, force_update=False, key_change=False):
if datetime.now(util.TZ) >= token_expires_at:
refresh_auth()
if url in [RECHARGE_STATE_URL, WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL,
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL]:
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, FUEL_BATTERY_STATE_URL]:
# Minimize API calls for endpoints with multiple values
response = cached_request(url, method, vin, force_update, key_change)
if response is None:
@@ -369,7 +385,7 @@ def api_call(url, method, vin, sensor_id=None, force_update=False, key_change=Fa
return None
elif response.status_code == 403 and "message" in data:
if "Out of call volume quota" in data["message"]:
logging.warn("Quota extended. Try to change VCCAPIKEY!")
logging.warning("Quota extended. Try to change VCCAPIKEY!")
change_vcc_api_key()
api_call(url, method, vin, sensor_id, force_update, True)
else:
@@ -415,7 +431,9 @@ def cached_request(url, method, vin, force_update=False, key_change=False):
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":
return data["batteryChargeLevel"]["value"] if util.keys_exists(data, "batteryChargeLevel") else None
elif sensor_id == "electric_range":
@@ -448,7 +466,7 @@ def parse_api_data(data, sensor_id=None):
return ""
return None
elif sensor_id == "lock_status":
return data["carLocked"]["value"] if util.keys_exists(data, "carLocked") else None
return data["centralLock"]["value"] if util.keys_exists(data, "centralLock") else None
elif sensor_id == "odometer":
multiplier = 1
if util.keys_exists(settings["volvoData"], "odometerMultiplier"):
@@ -460,44 +478,44 @@ def parse_api_data(data, sensor_id=None):
return util.convert_metric_values(int(data["odometer"]["value"]) * multiplier) \
if util.keys_exists(data, "odometer") else None
elif sensor_id == "window_front_left":
return window_states[data["frontLeftWindowOpen"]["value"]] if util.keys_exists(data, "frontLeftWindowOpen") \
return window_states[data["frontLeftWindow"]["value"]] if util.keys_exists(data, "frontLeftWindow") \
else None
elif sensor_id == "window_front_right":
return window_states[data["frontRightWindowOpen"]["value"]] if util.keys_exists(data, "frontRightWindowOpen") \
return window_states[data["frontRightWindow"]["value"]] if util.keys_exists(data, "frontRightWindow") \
else None
elif sensor_id == "window_rear_left":
return window_states[data["rearLeftWindowOpen"]["value"]] if util.keys_exists(data, "rearLeftWindowOpen") \
return window_states[data["rearLeftWindow"]["value"]] if util.keys_exists(data, "rearLeftWindow") \
else None
elif sensor_id == "window_rear_right":
return window_states[data["rearRightWindowOpen"]["value"]] if util.keys_exists(data, "rearRightWindowOpen") \
return window_states[data["rearRightWindow"]["value"]] if util.keys_exists(data, "rearRightWindow") \
else None
elif sensor_id == "door_front_left":
return door_states[data["frontLeftDoorOpen"]["value"]] if util.keys_exists(data, "frontLeftDoorOpen") else None
return door_states[data["frontLeftDoor"]["value"]] if util.keys_exists(data, "frontLeftDoor") else None
elif sensor_id == "door_front_right":
return door_states[data["frontRightDoorOpen"]["value"]] \
if util.keys_exists(data, "frontRightDoorOpen") else None
return door_states[data["frontRightDoor"]["value"]] \
if util.keys_exists(data, "frontRightDoor") else None
elif sensor_id == "door_rear_left":
return door_states[data["rearLeftDoorOpen"]["value"]] if util.keys_exists(data, "rearLeftDoorOpen") else None
return door_states[data["rearLeftDoor"]["value"]] if util.keys_exists(data, "rearLeftDoor") else None
elif sensor_id == "door_rear_right":
return door_states[data["rearRightDoorOpen"]["value"]] if util.keys_exists(data, "rearRightDoorOpen") else None
return door_states[data["rearRightDoor"]["value"]] if util.keys_exists(data, "rearRightDoor") else None
elif sensor_id == "tailgate":
return door_states[data["tailGateOpen"]["value"]] if util.keys_exists(data, "tailGateOpen") else None
return door_states[data["tailgate"]["value"]] if util.keys_exists(data, "tailgate") else None
elif sensor_id == "sunroof":
return door_states[data["sunRoofOpen"]["value"]] if util.keys_exists(data, "sunRoofOpen") else None
return door_states[data["sunroof"]["value"]] if util.keys_exists(data, "sunroof") else None
elif sensor_id == "engine_hood":
return door_states[data["hoodOpen"]["value"]] if util.keys_exists(data, "hoodOpen") else None
return door_states[data["hood"]["value"]] if util.keys_exists(data, "hood") else None
elif sensor_id == "tank_lid":
return door_states[data["tankLidOpen"]["value"]] if util.keys_exists(data, "tankLidOpen") else None
return door_states[data["tankLid"]["value"]] if util.keys_exists(data, "tankLid") else None
elif sensor_id == "tyre_front_left":
return data["frontLeftTyrePressure"]["value"] if util.keys_exists(data, "frontLeftTyrePressure") else None
return data["frontLeft"]["value"] if util.keys_exists(data, "frontLeft") else None
elif sensor_id == "tyre_front_right":
return data["frontRightTyrePressure"]["value"] if util.keys_exists(data, "frontRightTyrePressure") else None
return data["frontRight"]["value"] if util.keys_exists(data, "frontRight") else None
elif sensor_id == "tyre_rear_left":
return data["rearLeftTyrePressure"]["value"] if util.keys_exists(data, "rearLeftTyrePressure") else None
return data["rearLeft"]["value"] if util.keys_exists(data, "rearLeft") else None
elif sensor_id == "tyre_rear_right":
return data["rearRightTyrePressure"]["value"] if util.keys_exists(data, "rearRightTyrePressure") else None
return data["rearRight"]["value"] if util.keys_exists(data, "rearRight") else None
elif sensor_id == "engine_state":
return engine_states[data["engineRunning"]["value"]] if util.keys_exists(data, "engineRunning") else None
return engine_states[data["engineStatus"]["value"]] if util.keys_exists(data, "engineStatus") else None
elif sensor_id == "fuel_level":
if util.keys_exists(data, "fuelAmount"):
fuel_amount = float(data["fuelAmount"]["value"])
@@ -539,25 +557,36 @@ def parse_api_data(data, sensor_id=None):
"latitude": raw_data["coordinates"][1],
"gps_accuracy": 1}
return coordinates
elif sensor_id == "distance_to_empty":
if util.keys_exists(data, "distanceToEmpty"):
distance_to_empty = int(data["distanceToEmpty"]["value"])
elif sensor_id == "distance_to_empty_tank":
if util.keys_exists(data, "distanceToEmptyTank"):
distance_to_empty = int(data["distanceToEmptyTank"]["value"])
if distance_to_empty > 0:
return util.convert_metric_values(data["distanceToEmpty"]["value"])
return util.convert_metric_values(data["distanceToEmptyTank"]["value"])
return None
elif sensor_id == "distance_to_empty_battery":
if util.keys_exists(data, "distanceToEmptyBattery"):
distance_to_empty = int(data["distanceToEmptyBattery"]["value"])
if distance_to_empty > 0:
return util.convert_metric_values(data["distanceToEmptyBattery"]["value"])
return None
elif sensor_id == "hours_to_service":
return data["engineHoursToService"]["value"] if util.keys_exists(data, "engineHoursToService") else None
elif sensor_id == "km_to_service":
if util.keys_exists(data, "kmToService"):
km_to_service = int(data["kmToService"]["value"])
if util.keys_exists(data, "distanceToService"):
km_to_service = int(data["distanceToService"]["value"])
if km_to_service > 0:
return util.convert_metric_values(data["kmToService"]["value"])
return util.convert_metric_values(data["distanceToService"]["value"])
return None
elif sensor_id == "months_to_service":
return data["monthsToService"]["value"] if util.keys_exists(data, "monthsToService") else None
elif sensor_id == "time_to_service":
if util.keys_exists(data, "timeToService"):
return str(data["timeToService"]["value"]) + " " + data["timeToService"]["unit"]
else:
return None
elif sensor_id == "service_warning_status":
return data["serviceWarningStatus"]["value"] if util.keys_exists(data, "serviceWarningStatus") else None
elif sensor_id == "service_warning_trigger":
return data["serviceWarningTrigger"]["value"] if util.keys_exists(data, "serviceWarningTrigger") else None
return data["serviceWarning"]["value"] if util.keys_exists(data, "serviceWarning") else None
elif sensor_id == "average_energy_consumption":
return data["averageEnergyConsumption"]["value"] if util.keys_exists(data, "averageEnergyConsumption") else None
elif sensor_id == "washer_fluid_warning":
return data["washerFluidLevelWarning"]["value"] if util.keys_exists(data, "washerFluidLevelWarning") else None
else:
return None