Compare commits

..
10 Commits
10 changed files with 104 additions and 34 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ NOTE: Energy status currently available only for cars in the Europe / Middle Eas
Just install this addon with the following command. Just install this addon with the following command.
Please note to fill in your settings inside the environment variables. Please note to fill in your settings inside the environment variables.
`docker run -d --pull=always -e CONF_updateInterval=300 -e CONF_babelLocale='de' -e CONF_mqtt='@json {"broker": "", "username": "", "password": "", "port": 1883}' -e CONF_volvoData='@json {"username": "", "password": "", "vin": "", "vccapikey": "", "backupvccapikey": "", "odometerMultiplier": 1, "averageSpeedDivider": 1, "averageFuelConsumptionMultiplier": 1}' -e TZ='Europe/Berlin' --name volvo2mqtt ghcr.io/dielee/volvo2mqtt:latest` `docker run -d --pull=always -e CONF_updateInterval=300 -e CONF_babelLocale='de' -e CONF_mqtt='@json {"broker": "", "username": "", "password": "", "port": 1883}' -e CONF_volvoData='@json {"username": "", "password": "", "vin": "", "vccapikey": ["key1", "key2"], "odometerMultiplier": 1, "averageSpeedDivider": 1, "averageFuelConsumptionMultiplier": 1}' -e TZ='Europe/Berlin' --name volvo2mqtt ghcr.io/dielee/volvo2mqtt:latest`
<b>HA Add-On:</b><br> <b>HA Add-On:</b><br>
+36
View File
@@ -1,3 +1,39 @@
## v1.8.7
### 🚀 Features:
- Add option to disable log completely #96
### 🐛 Bug Fixes:
- Fix regex error for some mailaddresses #97
## v1.8.6
### 🚀 Features:
- Add option to use multiple docker containers (with different logins) #93
## v1.8.5
### 🚀 Features:
- Allow phone number as username #91
## v1.8.4
### 🚀 Features:
- Optimize Addon configuration #90
## v1.8.3
### 🚀 Features:
- Add `device_class: battery` for battery state sensors from BEV and PHEV
## v1.8.2
### 🚀 Features:
- Add `updateInterval` limit to prevent abuse (60 Seconds)
- Add `vccapikey` limit to prevent abuse (3 Keys)
- Optimize vcc api key change behaviour
## v1.8.1 ## v1.8.1
### 🐛 Bug Fixes: ### 🐛 Bug Fixes:
+9 -6
View File
@@ -1,6 +1,6 @@
name: "Volvo2Mqtt" name: "Volvo2Mqtt"
description: "Volvo AAOS MQTT bridge" description: "Volvo AAOS MQTT bridge"
version: "1.8.1" version: "1.8.7"
slug: "volvo2mqtt" slug: "volvo2mqtt"
init: false init: false
url: "https://github.com/Dielee/volvo2mqtt" url: "https://github.com/Dielee/volvo2mqtt"
@@ -15,6 +15,7 @@ options:
babelLocale: null babelLocale: null
TZ: null TZ: null
debug: false debug: false
disable_logging: false
mqtt: mqtt:
broker: "auto_broker" broker: "auto_broker"
port: "auto_port" port: "auto_port"
@@ -24,26 +25,28 @@ options:
username: null username: null
password: null password: null
vin: "" vin: ""
vccapikey: null vccapikey:
- null
odometerMultiplier: 1 odometerMultiplier: 1
averageSpeedDivider: 1 averageSpeedDivider: 1
averageFuelConsumptionMultiplier: 1 averageFuelConsumptionMultiplier: 1
schema: schema:
updateInterval: int(10,) updateInterval: int(60,)
babelLocale: str babelLocale: str
TZ: str TZ: match(^.+/.+$)
debug: bool debug: bool
disable_logging: bool
mqtt: mqtt:
broker: str broker: str
port: str port: str
username: str? username: str?
password: str? password: str?
volvoData: volvoData:
username: str username: match(^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)|(\+\d{5,20})$)
password: str password: str
vin: str? vin: str?
vccapikey: vccapikey:
- str - match(^\b\w{32}\b$)
odometerMultiplier: int(1,) odometerMultiplier: int(1,)
averageSpeedDivider: int(1,) averageSpeedDivider: int(1,)
averageFuelConsumptionMultiplier: int(1,) averageFuelConsumptionMultiplier: int(1,)
+3 -3
View File
@@ -1,6 +1,6 @@
from config import settings from config import settings
VERSION = "v1.8.1" VERSION = "v1.8.7"
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"
@@ -77,8 +77,8 @@ icon_states = {
} }
supported_entities = [ supported_entities = [
{"name": "Battery Charge Level", "domain": "sensor", "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", "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": BATTERY_CHARGE_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": "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": "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}, {"name": "Charging System Status", "domain": "sensor", "id": "charging_system_status", "icon": "ev-station", "url": RECHARGE_STATE_URL},
+4 -3
View File
@@ -2,14 +2,15 @@ import logging
from volvo import authorize from volvo import authorize
from mqtt import update_loop, connect from mqtt import update_loop, connect
from const import VERSION from const import VERSION
from util import set_tz, setup_logging, set_mqtt_settings from util import set_tz, setup_logging, set_mqtt_settings, validate_settings
if __name__ == '__main__': if __name__ == '__main__':
set_tz()
set_mqtt_settings()
setup_logging() setup_logging()
logging.info("Starting volvo2mqtt version " + VERSION) logging.info("Starting volvo2mqtt version " + VERSION)
validate_settings()
set_tz()
set_mqtt_settings()
connect() connect()
authorize() authorize()
update_loop() update_loop()
+4 -1
View File
@@ -4,6 +4,7 @@ import paho.mqtt.client as mqtt
import json import json
import volvo import volvo
import util import util
import os
from threading import Thread, Timer from threading import Thread, Timer
from datetime import datetime from datetime import datetime
from babel.dates import format_datetime from babel.dates import format_datetime
@@ -23,7 +24,9 @@ active_schedules = {}
def connect(): def connect():
client = mqtt.Client("volvoAAOS2mqtt") client = mqtt.Client("volvoAAOS2mqtt") if os.environ.get("IS_HA_ADDON") \
else mqtt.Client("volvoAAOS2mqtt_" + settings.volvoData["username"])
client.will_set(availability_topic, "offline", 0, False) client.will_set(availability_topic, "offline", 0, False)
if settings["mqtt"]["username"] and settings["mqtt"]["password"]: if settings["mqtt"]["username"] and settings["mqtt"]["password"]:
client.username_pw_set(settings["mqtt"]["username"], settings["mqtt"]["password"]) client.username_pw_set(settings["mqtt"]["username"], settings["mqtt"]["password"])
+2
View File
@@ -2,6 +2,8 @@
"updateInterval": 300, "updateInterval": 300,
"babelLocale": "de", "babelLocale": "de",
"TZ": "Europe/Berlin", "TZ": "Europe/Berlin",
"debug": false,
"disable_logging": false,
"mqtt": { "mqtt": {
"broker": "", "broker": "",
"port": 1883, "port": 1883,
+3
View File
@@ -11,6 +11,9 @@ configuration:
debug: debug:
name: API debug mode name: API debug mode
description: Enable Volvo API debug, normaly this can stay off. If enabled, the complete log file can be found under \\<Your HA Host IP>\addons\volvo2mqtt\log\volvo2mqtt.log. description: Enable Volvo API debug, normaly this can stay off. If enabled, the complete log file can be found under \\<Your HA Host IP>\addons\volvo2mqtt\log\volvo2mqtt.log.
disable_logging:
name: Disable logging
description: Disable logging completely to reduce IO and SD card access.
mqtt: mqtt:
name: MQTT Broker settings name: MQTT Broker settings
description: Leave the settings as they are if you are using the MQTT Mosquitto Addon. If not, take a look at the readme from volvo2mqtt. description: Leave the settings as they are if you are using the MQTT Mosquitto Addon. If not, take a look at the readme from volvo2mqtt.
+16
View File
@@ -68,6 +68,10 @@ def setup_logging():
if settings["debug"]: if settings["debug"]:
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
if "disable_logging" in settings:
if settings["disable_logging"]:
logger.setLevel(logging.ERROR)
def check_existing_folder(): def check_existing_folder():
Path("/addons/volvo2mqtt/log/").mkdir(parents=True, exist_ok=True) Path("/addons/volvo2mqtt/log/").mkdir(parents=True, exist_ok=True)
@@ -136,3 +140,15 @@ def set_mqtt_settings():
config.settings["mqtt"]["port"] = broker_port config.settings["mqtt"]["port"] = broker_port
config.settings["mqtt"]["username"] = broker_user config.settings["mqtt"]["username"] = broker_user
config.settings["mqtt"]["password"] = broker_pass config.settings["mqtt"]["password"] = broker_pass
def validate_settings():
if not os.environ.get("DEV_MODE"):
setting_keys = settings.volvoData["vccapikey"]
if isinstance(setting_keys, list):
if len(setting_keys) > 3:
raise Exception("Settings invalid! Maximum allowed vccapikeys are three!")
update_interval = settings["updateInterval"]
if update_interval < 60:
raise Exception("Settings invalid! Minimum allowed update interval is 60 seconds!")
+26 -20
View File
@@ -119,28 +119,32 @@ def get_vehicles():
def get_vcc_api_keys(used_key=None): def get_vcc_api_keys(used_key=None):
setting_keys = settings.volvoData["vccapikey"] working_keys = None
if isinstance(setting_keys, str):
set_key_state(setting_keys)
elif isinstance(setting_keys, list):
for key in setting_keys:
set_key_state(key)
logging.debug(str(vcc_api_keys)) while not working_keys:
working_keys = [key["key"] for key in vcc_api_keys if not key.get("extended") and key.get('key') != used_key] setting_keys = settings.volvoData["vccapikey"]
if len(working_keys) < 1: if isinstance(setting_keys, str):
logging.warning("No working VCCAPIKEY found, waiting 10 minutes. Then trying again!") set_key_state(setting_keys)
mqtt.send_offline() elif isinstance(setting_keys, list):
time.sleep(600) for key in setting_keys:
get_vcc_api_keys(used_key=None) set_key_state(key)
return None
mqtt.send_heartbeat() logging.debug(str(vcc_api_keys))
session.headers.update({"vcc-api-key": working_keys[0]}) working_keys = [key["key"] for key in vcc_api_keys if not key.get("extended") and key.get('key') != used_key]
logging.info("Using VCCAPIKEY: " + working_keys[0]) if len(working_keys) < 1:
for key_dict in vcc_api_keys: used_key = None
if key_dict["key"] == working_keys[0]: logging.warning("No working VCCAPIKEY found, waiting 10 minutes. Then trying again!")
key_dict["in_use"] = True mqtt.send_offline()
time.sleep(600)
else:
mqtt.send_heartbeat()
session.headers.update({"vcc-api-key": working_keys[0]})
logging.info("Using VCCAPIKEY: " + working_keys[0])
for key_dict in vcc_api_keys:
if key_dict["key"] == working_keys[0]:
key_dict["in_use"] = True
logging.debug(str(vcc_api_keys))
def set_key_state(key): def set_key_state(key):
@@ -160,6 +164,8 @@ def set_key_state(key):
def check_vcc_api_key(test_key, extended_until=None): def check_vcc_api_key(test_key, extended_until=None):
if extended_until: if extended_until:
if extended_until >= datetime.now(): if extended_until >= datetime.now():
logging.warning("VCCAPIKEY " + test_key + " is extended and will be reusable at: "
+ format_datetime(extended_until, format="medium", locale=settings["babelLocale"]))
return True, extended_until return True, extended_until
if datetime.now(util.TZ) >= token_expires_at: if datetime.now(util.TZ) >= token_expires_at: