From a1881a87d8829b0dec509384c7be02abd8274229 Mon Sep 17 00:00:00 2001 From: Linus Dietz <45101649+Dielee@users.noreply.github.com> Date: Sat, 1 Jul 2023 15:06:23 +0200 Subject: [PATCH] Added dynamic icons lock, battery and window state (#45) #43 --- src/config.yaml | 2 +- src/const.py | 23 +++++++++++++++++++++- src/mqtt.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++-- src/util.py | 8 ++++++++ 4 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/config.yaml b/src/config.yaml index 1244e5e..d99579d 100644 --- a/src/config.yaml +++ b/src/config.yaml @@ -1,6 +1,6 @@ name: "Volvo2Mqtt" description: "Volvo AAOS MQTT bridge" -version: "1.6.3" +version: "1.6.4" slug: "volvo2mqtt" init: false url: "https://github.com/Dielee/volvo2mqtt" diff --git a/src/const.py b/src/const.py index 0f7784a..e8f5eca 100644 --- a/src/const.py +++ b/src/const.py @@ -1,6 +1,6 @@ from config import settings -VERSION = "v1.6.3" +VERSION = "v1.6.4" OAUTH_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2" VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles" @@ -46,6 +46,27 @@ charging_connection_states = {"CONNECTION_STATUS_DISCONNECTED": "Disconnected", window_states = {"CLOSED": "OFF", "OPEN": "ON"} door_states = {"CLOSED": "OFF", "OPEN": "ON"} +icon_states = { + "lock_status": {"UNLOCKED": "lock-open-alert", "LOCKED": "lock"}, + "door_front_left": {"ON": "car-door", "OFF": "car-door-lock"}, + "door_front_right": {"ON": "car-door", "OFF": "car-door-lock"}, + "door_rear_left": {"ON": "car-door", "OFF": "car-door-lock"}, + "door_rear_right": {"ON": "car-door", "OFF": "car-door-lock"}, + "battery_charge_level": [ + {"from": 100, "to": 100, "icon": "battery"}, + {"from": 99, "to": 90, "icon": "battery-90"}, + {"from": 89, "to": 80, "icon": "battery-80"}, + {"from": 79, "to": 70, "icon": "battery-70"}, + {"from": 69, "to": 60, "icon": "battery-60"}, + {"from": 59, "to": 50, "icon": "battery-50"}, + {"from": 49, "to": 40, "icon": "battery-40"}, + {"from": 39, "to": 30, "icon": "battery-30"}, + {"from": 29, "to": 20, "icon": "battery-20"}, + {"from": 19, "to": 10, "icon": "battery-10"}, + {"from": 9, "to": 0, "icon": "battery-alert-variant-outline"}, + ] +} + supported_entities = [ {"name": "Battery Charge Level", "domain": "sensor", "id": "battery_charge_level", "unit": "%", "icon": "car-battery", "url": RECHARGE_STATE_URL}, {"name": "Battery Charge Level", "domain": "sensor", "id": "battery_charge_level", "unit": "%", "icon": "car-battery", "url": BATTERY_CHARGE_STATE_URL}, diff --git a/src/mqtt.py b/src/mqtt.py index aa306f8..bc299d5 100644 --- a/src/mqtt.py +++ b/src/mqtt.py @@ -9,7 +9,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 + CAR_UNLOCK_URL, availability_topic, icon_states mqtt_client: mqtt.Client @@ -18,6 +18,7 @@ assumed_climate_state = {} last_data_update = None climate_timer = {} door_status = {} +devices = {} def connect(): @@ -154,12 +155,58 @@ def update_car_data(force_update=False, overwrite={}): topic, json.dumps(state) if isinstance(state, dict) else state ) + update_ha_device(entity, vin, state) + + +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) + icon = util.get_icon_between(icon_config, state) + else: + icon = icon_config[state] + else: + return None + + logging.debug("Updating icon to " + icon + " for " + entity["id"]) + config = { + "name": entity['name'], + "object_id": f"volvo_{vin}_{entity['id']}", + "schema": "state", + "icon": f"mdi:{icon}" if icon else f"mdi:{entity['icon']}", + "state_topic": f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/state", + "device": devices[vin], + "unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}", + "availability_topic": availability_topic + } + if entity.get("device_class"): + config["device_class"] = entity["device_class"] + + if entity.get("unit"): + config["unit_of_measurement"] = entity["unit"] + + if entity.get("domain") == "device_tracker": + config["json_attributes_topic"] = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes" + + if entity.get("domain") in ["switch", "lock", "button"]: + command_topic = f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/command" + config["command_topic"] = command_topic + subscribed_topics.append(command_topic) + mqtt_client.subscribe(command_topic) + + mqtt_client.publish( + f"homeassistant/{entity['domain']}/volvoAAOS2mqtt/{vin}_{entity['id']}/config", + json.dumps(config), + retain=True + ) def create_ha_devices(): - global subscribed_topics + global subscribed_topics, devices for vin in volvo.vins: device = volvo.get_vehicle_details(vin) + devices[vin] = device for entity in volvo.supported_endpoints[vin]: config = { "name": entity['name'], diff --git a/src/util.py b/src/util.py index 44bc1cf..78d379d 100644 --- a/src/util.py +++ b/src/util.py @@ -11,6 +11,14 @@ from pathlib import Path TZ = None +def get_icon_between(icon_list, state): + icon = None + for s in icon_list: + if s["to"] <= state <= s["from"]: + icon = s["icon"] + return icon + + def setup_logging(): log_location = "volvo2mqtt.log" if os.environ.get("IS_HA_ADDON"):