From 67320c32f6c685aaae52797e80c9b47b78c6c194 Mon Sep 17 00:00:00 2001 From: Linus Dietz <45101649+Dielee@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:46:34 +0200 Subject: [PATCH] Optimize climate timer (#40) * Add logic to turn climate switch off if driver door is opened * Update car data after climate state change * Climate stop on left or right door open * Bump version --- src/config.yaml | 2 +- src/const.py | 2 +- src/mqtt.py | 36 ++++++++++++++++++++++++++++-------- src/volvo.py | 18 +++++++++++++++++- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/config.yaml b/src/config.yaml index 50dafe5..fdebd89 100644 --- a/src/config.yaml +++ b/src/config.yaml @@ -1,6 +1,6 @@ name: "Volvo2Mqtt" description: "Volvo AAOS MQTT bridge" -version: "1.6.0" +version: "1.6.1" slug: "volvo2mqtt" init: false url: "https://github.com/Dielee/volvo2mqtt" diff --git a/src/const.py b/src/const.py index 2e40068..54f5fbd 100644 --- a/src/const.py +++ b/src/const.py @@ -1,6 +1,6 @@ from config import settings -VERSION = "v1.6.0" +VERSION = "v1.6.1" OAUTH_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2" VEHICLES_URL = "https://api.volvocars.com/connected-vehicle/v1/vehicles" diff --git a/src/mqtt.py b/src/mqtt.py index 6f04dd6..7bdb982 100644 --- a/src/mqtt.py +++ b/src/mqtt.py @@ -16,6 +16,7 @@ subscribed_topics = [] assumed_climate_state = {} last_data_update = None climate_timer = {} +door_status = {} def connect(): @@ -59,29 +60,48 @@ def on_message(client, userdata, msg): payload = msg.payload.decode("UTF-8") if "climate_status" in msg.topic: - global assumed_climate_state, climate_timer + global assumed_climate_state, climate_timer, door_status if payload == "ON": - api_thread = Thread(target=volvo.api_call, args=(CLIMATE_START_URL, "POST", vin)) - api_thread.start() - assumed_climate_state[vin] = "ON" + # Start the api call in another thread for HA performance + Thread(target=volvo.api_call, args=(CLIMATE_START_URL, "POST", vin)).start() + + # Start door check thread to turn off climate if driver door is opened + door_thread = Thread(target=volvo.check_door_status, args=(vin, )) + door_thread.start() + door_status[vin] = door_thread # Starting timer to disable climate after 30 mins + climate_timer[vin] = Timer(30 * 60, volvo.disable_climate, (vin, )) climate_timer[vin].start() + # Set and update switch status + + assumed_climate_state[vin] = "ON" update_car_data() elif payload == "OFF": - api_thread = Thread(target=volvo.api_call, args=(CLIMATE_STOP_URL, "POST", vin)) - api_thread.start() - assumed_climate_state[vin] = "OFF" - # Stop timer if active + # Start the api call in another thread for HA performance + Thread(target=volvo.api_call, args=(CLIMATE_STOP_URL, "POST", vin)).start() + + # Stop door check thread if running + if door_status[vin].is_alive(): + door_status[vin].do_run = False + + # Stop climate timer if active if climate_timer[vin].is_alive(): climate_timer[vin].cancel() + + # Set and update switch status + assumed_climate_state[vin] = "OFF" update_car_data() elif "lock_status" in msg.topic: if payload == "LOCK": volvo.api_call(CAR_LOCK_URL, "POST", vin) + + # Force set unlocked state in HA because of slow api response update_car_data(True, {"entity_id": "lock_status", "vin": vin, "state": "LOCKED"}) elif payload == "UNLOCK": volvo.api_call(CAR_UNLOCK_URL, "POST", vin) + + # Force set unlocked state in HA because of slow api response update_car_data(True, {"entity_id": "lock_status", "vin": vin, "state": "UNLOCKED"}) elif "update_data" in msg.topic: if payload == "PRESS": diff --git a/src/volvo.py b/src/volvo.py index ca6187a..53c089c 100644 --- a/src/volvo.py +++ b/src/volvo.py @@ -1,13 +1,15 @@ import requests import mqtt import util +import time +from threading import Thread, currentThread from datetime import datetime, timedelta from config import settings from babel.dates import format_datetime 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 + STATISTICS_URL, CLIMATE_STOP_URL session = requests.Session() session.headers = { @@ -168,10 +170,24 @@ def initialize_climate(vins): def disable_climate(vin): print("Turning climate off by timer!") + mqtt.door_status[vin].do_run = False mqtt.assumed_climate_state[vin] = "OFF" mqtt.update_car_data() +def check_door_status(vin): + t = currentThread() + while getattr(t, "do_run", True): + lock_door_left = api_call(LOCK_STATE_URL, "GET", vin, "door_front_left", True) + lock_door_right = api_call(LOCK_STATE_URL, "GET", vin, "door_front_right", True) + if lock_door_left == "ON" or lock_door_right == "ON": + Thread(target=api_call, args=(CLIMATE_STOP_URL, "POST", vin)).start() + mqtt.assumed_climate_state[vin] = "OFF" + mqtt.update_car_data() + break + time.sleep(5) + + def api_call(url, method, vin, sensor_id=None, force_update=False): global token_expires_at if datetime.now(util.TZ) >= token_expires_at: