Compare commits

...
Author SHA1 Message Date
Linus Dietz 3d2285f59e Add option to disable updates #160 2024-01-23 09:25:25 +01:00
Linus Dietz e444b6a838 Bump version 2024-01-23 08:44:57 +01:00
Linus Dietz ce856d91c4 Fix #165 2024-01-23 08:42:37 +01:00
9c749001c9 V90 B5 Mildhybrid (2023) added (#164)
Co-authored-by: Anthony <anthony@betts.sh>
2024-01-23 06:38:36 +01:00
Linus Dietz 390df68203 Add warnings endpoint #151 2024-01-22 09:17:01 +01:00
Linus Dietz fff2ccd6f4 Add option for dynamic interval settings #160 2024-01-22 08:08:13 +01:00
Linus DietzandGitHub 2622fc5e67 Update maintenance shield 2024-01-03 08:35:17 +01:00
Linus Dietz 776564b8b7 Add new charging system states #152 2024-01-02 15:04:41 +01:00
Dielee b55e7ef6fb Change units to HA default #148 2023-12-18 14:00:40 +01:00
Dielee 25e90091ab Merge remote-tracking branch 'origin/main' into main 2023-12-14 08:54:50 +01:00
Dielee c4c801e46a Try to fix addon build #146 2023-12-14 08:53:40 +01:00
Dielee 8326ed3c88 Fix unknown state for icon update 2023-12-14 08:52:53 +01:00
Linus DietzandGitHub 3166a1c6ab Add country info 2023-12-01 11:43:03 +01:00
Linus Dietz 80646bbf51 Fix unknown state for icon update 2023-11-28 12:47:42 +01:00
Linus Dietz 7401ebfc53 Add UNSPECIFIED state for windows 2023-11-27 14:30:07 +01:00
Linus DietzandGitHub bdbb6bd5f8 Add V90 PHEV 2024 2023-11-23 06:43:02 +01:00
7 changed files with 150 additions and 47 deletions
+5 -1
View File
@@ -15,6 +15,8 @@ Maybe this component works also with other Volvo cars. Please try out the native
Home Assistant thread can be found [here](https://community.home-assistant.io/t/volvo2mqtt-connect-your-aaos-volvo/585699). Home Assistant thread can be found [here](https://community.home-assistant.io/t/volvo2mqtt-connect-your-aaos-volvo/585699).
<b>Important note: The Volvo api currently ONLY works in these [countries](https://developer.volvocars.com/terms-and-conditions/apis-supported-locations/)</b>
If you like my work:<br> If you like my work:<br>
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/U7U8MFXCF) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/U7U8MFXCF)
@@ -34,6 +36,8 @@ If you like my work:<br>
- XC90 PHEV T8 (2024) - XC90 PHEV T8 (2024)
- XC90 B5 Mildhybrid (2024) - XC90 B5 Mildhybrid (2024)
- V90 PHEV T8 (2019)* - V90 PHEV T8 (2019)*
- V90 PHEV T6 (2024)
- V90 B5 Mildhybrid (2023)
*only partly working *only partly working
@@ -108,6 +112,6 @@ Here is what every option means:
[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg [i386-shield]: https://img.shields.io/badge/i386-yes-green.svg
[releases]: https://github.com/Dielee/volvo2mqtt/releases [releases]: https://github.com/Dielee/volvo2mqtt/releases
[releases-shield]: https://img.shields.io/github/release/Dielee/volvo2mqtt.svg [releases-shield]: https://img.shields.io/github/release/Dielee/volvo2mqtt.svg
[maintenance-shield]: https://img.shields.io/maintenance/yes/2023.svg [maintenance-shield]: https://img.shields.io/maintenance/yes/2024.svg
[commits-shield]: https://img.shields.io/github/commit-activity/y/Dielee/volvo2mqtt.svg [commits-shield]: https://img.shields.io/github/commit-activity/y/Dielee/volvo2mqtt.svg
[commits]: https://github.com/Dielee/volvo2mqtt/commits/main [commits]: https://github.com/Dielee/volvo2mqtt/commits/main
+38
View File
@@ -1,3 +1,41 @@
## v1.8.26
### 🚀 Features:
- Add option to disable updates #160
## v1.8.25
### 🚀 Features:
- Fix INTERNAL_SERVER_ERROR #165
## v1.8.24
### 🚀 Features:
- Add option for dynamic interval settings #160
- Add warnings endpoint #151
## v1.8.23
### 🚀 Features:
- Add new charging system states #152
## v1.8.22
### 🚀 Features:
- Change units to HA default #148
## v1.8.21
### 🐛 Bug Fixes:
- Try to fix addon build #146
## v1.8.20
### 🐛 Bug Fixes:
- Fix Addon crash if icon state is `UNKOWN`
- Add `UNSPECIFIED` state for windows
## v1.8.19 ## v1.8.19
### 🐛 Bug Fixes: ### 🐛 Bug Fixes:
+1 -1
View File
@@ -11,7 +11,7 @@ WORKDIR /volvoAAOS2mqtt
RUN wget --no-cache https://raw.githubusercontent.com/Dielee/volvo2mqtt/main/requirements.txt RUN wget --no-cache https://raw.githubusercontent.com/Dielee/volvo2mqtt/main/requirements.txt
# install dependencies # install dependencies
RUN pip install -r requirements.txt RUN pip install -r requirements.txt --break-system-packages
# copy the content of the local src directory to the working directory # copy the content of the local src directory to the working directory
COPY / . COPY / .
+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.19" version: "1.8.26"
slug: "volvo2mqtt" slug: "volvo2mqtt"
init: false init: false
url: "https://github.com/Dielee/volvo2mqtt" url: "https://github.com/Dielee/volvo2mqtt"
+39 -25
View File
@@ -1,6 +1,6 @@
from config import settings from config import settings
VERSION = "v1.8.19" VERSION = "v1.8.26"
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/v2/vehicles" VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles"
@@ -20,37 +20,49 @@ FUEL_BATTERY_STATE_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicle
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"
WARNINGS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/warnings"
API_BACKEND_STATUS = "https://oip-dev-bff.euwest1.production.volvo.care/api/v1/backend-status" API_BACKEND_STATUS = "https://oip-dev-bff.euwest1.production.volvo.care/api/v1/backend-status"
LENGTH_KILOMETERS = "km"
SPEED_KILOMETERS_PER_HOUR = "km/h"
TIME_MINUTES = "min"
LENGTH_MILES = "mi"
SPEED_MILES_PER_HOUR = "mph"
VOLUME_LITERS = "L"
ENERGY_KILO_WATT_HOUR = "kWh"
TIME_HOURS = "h"
TIME_MONTHS = "m"
units = { units = {
"en_GB": { "en_GB": {
"divider": 1.60934, "divider": 1.60934,
"electric_range": {"unit": "mi"}, "electric_range": {"unit": LENGTH_MILES},
"odometer": {"unit": "mi"}, "odometer": {"unit": LENGTH_MILES},
"average_speed": {"unit": "mph"}, "average_speed": {"unit": SPEED_MILES_PER_HOUR},
"distance_to_empty": {"unit": "mi"}, "distance_to_empty": {"unit": LENGTH_MILES},
"distance_to_service": {"unit": "mi"} "distance_to_service": {"unit": LENGTH_MILES}
}, },
"en_US": { "en_US": {
"divider": 1.60934, "divider": 1.60934,
"electric_range": {"unit": "mi"}, "electric_range": {"unit": LENGTH_MILES},
"odometer": {"unit": "mi"}, "odometer": {"unit": LENGTH_MILES},
"average_speed": {"unit": "mph"}, "average_speed": {"unit": SPEED_MILES_PER_HOUR},
"distance_to_empty": {"unit": "mi"}, "distance_to_empty": {"unit": LENGTH_MILES},
"distance_to_service": {"unit": "mi"} "distance_to_service": {"unit": LENGTH_MILES}
} }
} }
availability_topic = "volvoAAOS2mqtt/availability" availability_topic = "volvoAAOS2mqtt/availability"
charging_system_states = {"CHARGING_SYSTEM_CHARGING": "Charging", "CHARGING_SYSTEM_IDLE": "Idle", charging_system_states = {"CHARGING_SYSTEM_CHARGING": "Charging", "CHARGING_SYSTEM_IDLE": "Idle",
"CHARGING_SYSTEM_FAULT": "Fault", "CHARGING_SYSTEM_UNSPECIFIED": "Unspecified"} "CHARGING_SYSTEM_FAULT": "Fault", "CHARGING_SYSTEM_UNSPECIFIED": "Unspecified",
"CHARGING_SYSTEM_DONE": "Done", "CHARGING_SYSTEM_SCHEDULED": "Scheduled"}
charging_connection_states = {"CONNECTION_STATUS_DISCONNECTED": "Disconnected", "CONNECTION_STATUS_UNSPECIFIED": "Unspecified", charging_connection_states = {"CONNECTION_STATUS_DISCONNECTED": "Disconnected", "CONNECTION_STATUS_UNSPECIFIED": "Unspecified",
"CONNECTION_STATUS_CONNECTED_DC": "Connected DC", "CONNECTION_STATUS_CONNECTED_AC": "Connected AC", "CONNECTION_STATUS_CONNECTED_DC": "Connected DC", "CONNECTION_STATUS_CONNECTED_AC": "Connected AC",
"CONNECTION_STATUS_FAULT": "Fault"} "CONNECTION_STATUS_FAULT": "Fault"}
window_states = {"CLOSED": "OFF", "OPEN": "ON", "AJAR": "ON"} window_states = {"CLOSED": "OFF", "OPEN": "ON", "UNSPECIFIED": "UNKNOWN", "AJAR": "ON"}
door_states = {"CLOSED": "OFF", "OPEN": "ON", "UNSPECIFIED": "UNKNOWN", "AJAR": "ON"} door_states = {"CLOSED": "OFF", "OPEN": "ON", "UNSPECIFIED": "UNKNOWN", "AJAR": "ON"}
engine_states = {"RUNNING": "ON", "STOPPED": "OFF", "true": "ON", "false": "OFF"} engine_states = {"RUNNING": "ON", "STOPPED": "OFF", "true": "ON", "false": "OFF"}
@@ -79,12 +91,12 @@ icon_states = {
supported_entities = [ 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": RECHARGE_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": "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": "Electric Range", "domain": "sensor", "id": "electric_range", "unit": LENGTH_KILOMETERS 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": "Estimated Charging Time", "domain": "sensor", "id": "estimated_charging_time", "unit": TIME_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}, {"name": "Charging System Status", "domain": "sensor", "id": "charging_system_status", "icon": "ev-station", "url": RECHARGE_STATE_URL},
{"name": "Charging Connection Status", "domain": "sensor", "id": "charging_connection_status", "icon": "ev-plug-ccs2", "url": RECHARGE_STATE_URL}, {"name": "Charging Connection Status", "domain": "sensor", "id": "charging_connection_status", "icon": "ev-plug-ccs2", "url": RECHARGE_STATE_URL},
{"name": "Estimated Charging Finish Time", "domain": "sensor", "id": "estimated_charging_finish_time", "icon": "timer-sync-outline", "url": RECHARGE_STATE_URL}, {"name": "Estimated Charging Finish Time", "domain": "sensor", "id": "estimated_charging_finish_time", "icon": "timer-sync-outline", "url": RECHARGE_STATE_URL},
{"name": "Odometer", "domain": "sensor", "id": "odometer", "unit": "km" if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["odometer"]["unit"], "icon": "counter", "url": ODOMETER_STATE_URL, "state_class":"total_increasing"}, {"name": "Odometer", "domain": "sensor", "id": "odometer", "unit": LENGTH_KILOMETERS if not units.get(settings["babelLocale"]) else units[settings["babelLocale"]]["odometer"]["unit"], "icon": "counter", "url": ODOMETER_STATE_URL, "state_class":"total_increasing"},
{"name": "Last Data Update", "domain": "sensor", "id": "last_data_update", "icon": "timer", "url": ""}, {"name": "Last Data Update", "domain": "sensor", "id": "last_data_update", "icon": "timer", "url": ""},
{"name": "Active schedules", "domain": "sensor", "id": "active_schedules", "icon": "timer", "url": ""}, {"name": "Active schedules", "domain": "sensor", "id": "active_schedules", "icon": "timer", "url": ""},
{"name": "Window Front Left", "domain": "binary_sensor", "device_class": "window", "id": "window_front_left", "icon": "car-door-lock", "url": WINDOWS_STATE_URL}, {"name": "Window Front Left", "domain": "binary_sensor", "device_class": "window", "id": "window_front_left", "icon": "car-door-lock", "url": WINDOWS_STATE_URL},
@@ -108,18 +120,20 @@ supported_entities = [
{"name": "Tire Rear Left", "domain": "sensor", "id": "tyre_rear_left", "icon": "car-tire-alert", "url": TYRE_STATE_URL}, {"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": "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_STATE_URL},
{"name": "Fuel Level", "domain": "sensor", "id": "fuel_level", "unit": "liters", "icon": "fuel", "url": FUEL_BATTERY_STATE_URL, "state_class": "measurement"}, {"name": "Fuel Level", "domain": "sensor", "id": "fuel_level", "unit": VOLUME_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": "Average Fuel Consumption", "domain": "sensor", "id": "average_fuel_consumption", "unit": VOLUME_LITERS, "icon": "fuel", "url": STATISTICS_URL},
{"name": "Average Energy Consumption", "domain": "sensor", "id": "average_energy_consumption", "unit": "kwh", "icon": "car-electric", "url": STATISTICS_URL}, {"name": "Average Energy Consumption", "domain": "sensor", "id": "average_energy_consumption", "unit": ENERGY_KILO_WATT_HOUR, "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 Tank", "domain": "sensor", "id": "distance_to_empty_tank", "unit": LENGTH_KILOMETERS 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": "Distance to Empty Battery", "domain": "sensor", "id": "distance_to_empty_battery", "unit": LENGTH_KILOMETERS 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": "Average Speed", "domain": "sensor", "id": "average_speed", "unit": SPEED_KILOMETERS_PER_HOUR 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": "Hours to Service", "domain": "sensor", "id": "hours_to_service", "unit": TIME_HOURS, "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": "Distance to Service", "domain": "sensor", "id": "km_to_service", "unit": LENGTH_KILOMETERS 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": "Washer Fluid Level warning", "domain": "sensor", "id": "washer_fluid_warning", "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"} {"name": "API Backend status", "domain": "sensor", "id": "api_backend_status", "icon": "alert"},
{"name": "Update Interval", "domain": "number", "id": "update_interval", "unit": "seconds", "icon": "timer", "min": -1, "max": 600, "mode": "box"},
{"name": "Warnings", "domain": "sensor", "id": "warnings", "icon": "alert", "url": WARNINGS_URL}
] ]
old_entity_ids = ["months_to_service", "service_warning_trigger", "distance_to_empty"] old_entity_ids = ["months_to_service", "service_warning_trigger", "distance_to_empty"]
+52 -17
View File
@@ -114,6 +114,13 @@ def on_message(client, userdata, msg):
elif "update_data" in msg.topic: elif "update_data" in msg.topic:
if payload == "PRESS": if payload == "PRESS":
update_car_data(True) update_car_data(True)
elif "update_interval" in msg.topic:
update_interval = int(payload)
if update_interval >= 60 or update_interval == -1:
settings.update({"updateInterval": int(update_interval)})
else:
logging.warning("Interval " + str(update_interval) + " seconds is to low. Doing nothing!")
update_car_data()
elif "schedule" in msg.topic: elif "schedule" in msg.topic:
try: try:
d = json.loads(payload) d = json.loads(payload)
@@ -214,11 +221,15 @@ def start_climate(vin):
def update_loop(): def update_loop():
create_ha_devices() create_ha_devices()
while True: while True:
logging.info("Sending mqtt update...") if settings["updateInterval"] > 0:
send_heartbeat() logging.info("Sending mqtt update...")
update_car_data() send_heartbeat()
logging.info("Mqtt update done. Next run in " + str(settings["updateInterval"]) + " seconds.") update_car_data()
time.sleep(settings["updateInterval"]) logging.info("Mqtt update done. Next run in " + str(settings["updateInterval"]) + " seconds.")
time.sleep(settings["updateInterval"])
else:
logging.info("Data update is disabled, doing nothing for 30 seconds")
time.sleep(30)
def update_car_data(force_update=False, overwrite={}): def update_car_data(force_update=False, overwrite={}):
@@ -226,7 +237,7 @@ def update_car_data(force_update=False, overwrite={}):
last_data_update = format_datetime(datetime.now(util.TZ), format="medium", locale=settings["babelLocale"]) last_data_update = format_datetime(datetime.now(util.TZ), format="medium", locale=settings["babelLocale"])
for vin in volvo.vins: for vin in volvo.vins:
for entity in volvo.supported_endpoints[vin]: for entity in volvo.supported_endpoints[vin]:
if entity["domain"] == "button": if entity["domain"] in ["button"]:
continue continue
ov_entity_id = "" ov_entity_id = ""
@@ -243,6 +254,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"] == "update_interval":
state = settings["updateInterval"]
elif entity["id"] == "api_backend_status": elif entity["id"] == "api_backend_status":
if force_update: if force_update:
state = volvo.get_backend_status() state = volvo.get_backend_status()
@@ -256,6 +269,17 @@ def update_car_data(force_update=False, overwrite={}):
if entity["domain"] == "device_tracker" or entity["id"] == "active_schedules": if entity["domain"] == "device_tracker" or entity["id"] == "active_schedules":
topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes" topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes"
elif entity["id"] == "warnings":
mqtt_client.publish(
f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes",
json.dumps(state)
)
if state:
state = sum(value == "FAILURE" for value in state.values())
else:
state = 0
topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state"
else: else:
topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state" topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state"
@@ -269,16 +293,19 @@ 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: try:
logging.debug("Entity " + entity["id"] + " state " + str(state)) if icon_config and state:
if isinstance(state, float): logging.debug("Entity " + entity["id"] + " state " + str(state))
icon = util.get_icon_between(icon_config, state) if isinstance(state, float):
elif state.replace(".", "").isnumeric(): icon = util.get_icon_between(icon_config, state)
state = float(state) elif state.replace(".", "").isnumeric():
icon = util.get_icon_between(icon_config, state) state = float(state)
icon = util.get_icon_between(icon_config, state)
else:
icon = icon_config[state]
else: else:
icon = icon_config[state] return None
else: except:
return None return None
logging.debug("Updating icon to " + icon + " for " + entity["id"]) logging.debug("Updating icon to " + icon + " for " + entity["id"])
@@ -333,6 +360,7 @@ def create_ha_devices():
"unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}", "unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}",
"availability_topic": availability_topic "availability_topic": availability_topic
} }
if entity.get("device_class"): if entity.get("device_class"):
config["device_class"] = entity["device_class"] config["device_class"] = entity["device_class"]
@@ -342,13 +370,20 @@ def create_ha_devices():
if entity.get("state_class"): if entity.get("state_class"):
config["state_class"] = entity["state_class"] config["state_class"] = entity["state_class"]
if entity.get("domain") == "device_tracker" or entity.get("id") == "active_schedules": if (entity.get("domain") == "device_tracker" or entity.get("id") == "active_schedules"
or entity.get("id") == "warnings"):
config["json_attributes_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes" config["json_attributes_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes"
elif entity.get("domain") in ["switch", "lock", "button"]:
if entity.get("domain") in ["switch", "lock", "button", "number"]:
command_topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/command" command_topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/command"
config["command_topic"] = command_topic config["command_topic"] = command_topic
subscribed_topics.append(command_topic) subscribed_topics.append(command_topic)
mqtt_client.subscribe(command_topic) mqtt_client.subscribe(command_topic)
if entity["domain"] == "number":
config["min"] = entity["min"]
config["max"] = entity["max"]
config["mode"] = entity["mode"]
elif entity.get("domain") == "image": elif entity.get("domain") == "image":
config["url_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/image_url" config["url_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/image_url"
+14 -2
View File
@@ -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, FUEL_BATTERY_STATE_URL, \ 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 STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, API_BACKEND_STATUS, WARNINGS_URL, engine_states
session = requests.Session() session = requests.Session()
session.headers = { session.headers = {
@@ -346,7 +346,7 @@ def api_call(url, method, vin, sensor_id=None, force_update=False, key_change=Fa
refresh_auth() refresh_auth()
if url in [RECHARGE_STATE_URL, WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL, if url in [RECHARGE_STATE_URL, WINDOWS_STATE_URL, LOCK_STATE_URL, TYRE_STATE_URL,
STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, FUEL_BATTERY_STATE_URL]: STATISTICS_URL, ENGINE_DIAGNOSTICS_URL, FUEL_BATTERY_STATE_URL, WARNINGS_URL]:
# Minimize API calls for endpoints with multiple values # Minimize API calls for endpoints with multiple values
response = cached_request(url, method, vin, force_update, key_change) response = cached_request(url, method, vin, force_update, key_change)
if response is None: if response is None:
@@ -595,5 +595,17 @@ def parse_api_data(data, sensor_id=None):
return data["averageEnergyConsumption"]["value"] if util.keys_exists(data, "averageEnergyConsumption") else None return data["averageEnergyConsumption"]["value"] if util.keys_exists(data, "averageEnergyConsumption") else None
elif sensor_id == "washer_fluid_warning": elif sensor_id == "washer_fluid_warning":
return data["washerFluidLevelWarning"]["value"] if util.keys_exists(data, "washerFluidLevelWarning") else None return data["washerFluidLevelWarning"]["value"] if util.keys_exists(data, "washerFluidLevelWarning") else None
elif sensor_id == "warnings":
warnings = 0
cleaned_data = {}
for key, dicts in data.items():
contains_data = sum(value == "NO_WARNING" or value == "FAILURE" for value in dicts.values())
if contains_data:
warnings = warnings + 1
cleaned_data[key] = dicts["value"]
return cleaned_data if warnings > 0 else None
else: else:
return None return None