forked from peter/volvo2mqtt
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7db02b5dc6 | ||
|
|
7c87c71ac8 | ||
|
|
3482a5f893 | ||
|
|
3f1f793c1b | ||
|
|
1039eab649 | ||
|
|
47bd726ebb | ||
|
|
0397d05522 | ||
|
|
f0628e6a26 | ||
|
|
0f89258718 |
@@ -19,6 +19,7 @@ If you like my work:<br>
|
|||||||
[](https://ko-fi.com/U7U8MFXCF)
|
[](https://ko-fi.com/U7U8MFXCF)
|
||||||
|
|
||||||
## Confirmed working with
|
## Confirmed working with
|
||||||
|
- XC40 BEV (2024)
|
||||||
- XC40 BEV (2023)
|
- XC40 BEV (2023)
|
||||||
- XC40 BEV (2022)
|
- XC40 BEV (2022)
|
||||||
- XC40 PHEV (2021)
|
- XC40 PHEV (2021)
|
||||||
@@ -26,6 +27,7 @@ If you like my work:<br>
|
|||||||
- C40 BEV (2023)
|
- C40 BEV (2023)
|
||||||
- C40 BEV (2022)
|
- C40 BEV (2022)
|
||||||
- XC90 T8 PHEV (2023)
|
- XC90 T8 PHEV (2023)
|
||||||
|
- XC60 PHEV (2024)
|
||||||
- XC60 PHEV (2023)
|
- XC60 PHEV (2023)
|
||||||
- XC60 PHEV (2022)
|
- XC60 PHEV (2022)
|
||||||
- XC90 PHEV T8 (2023)
|
- XC90 PHEV T8 (2023)
|
||||||
@@ -53,6 +55,12 @@ Please let me know if your car works with this addon so I can expand the list!<b
|
|||||||
- Sensor "Fuel Status"
|
- Sensor "Fuel Status"
|
||||||
- Sensor "Average Fuel Consumption"
|
- Sensor "Average Fuel Consumption"
|
||||||
- Sensor "Average Speed"
|
- Sensor "Average Speed"
|
||||||
|
- Sensor "Distance to Empty"
|
||||||
|
- Sensor "Hours to Service"
|
||||||
|
- Sensor "Distance to Service"
|
||||||
|
- Sensor "Months to Service"
|
||||||
|
- Sensor "Service warning status"
|
||||||
|
- Sensor "Service warning trigger"
|
||||||
- Car Device Tracker
|
- Car Device Tracker
|
||||||
- Multiple cars
|
- Multiple cars
|
||||||
|
|
||||||
@@ -64,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>
|
||||||
|
|
||||||
@@ -90,74 +98,6 @@ Here is what every option means:
|
|||||||
| `CONF_debug` | `string` | | optional | Debug option (true/false). Normally you don't need this. |
|
| `CONF_debug` | `string` | | optional | Debug option (true/false). Normally you don't need this. |
|
||||||
| `TZ` | `string` | | **required** | Container timezone eg "Europe/Berlin" from [here](https://docs.diladele.com/docker/timezones.html)|
|
| `TZ` | `string` | | **required** | Container timezone eg "Europe/Berlin" from [here](https://docs.diladele.com/docker/timezones.html)|
|
||||||
|
|
||||||
## Lovelace sample card
|
|
||||||
<details>
|
|
||||||
<summary>Show me more!</summary><blockquote>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Lovelace card sample</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
type: vertical-stack
|
|
||||||
title: Autostatus
|
|
||||||
cards:
|
|
||||||
- type: custom:vertical-stack-in-card
|
|
||||||
cards:
|
|
||||||
- type: custom:mushroom-lock-card
|
|
||||||
entity: lock.volvo_<your vin>_lock_status
|
|
||||||
name: Verrigelungsstatus
|
|
||||||
- type: horizontal-stack
|
|
||||||
cards:
|
|
||||||
- type: custom:mushroom-entity-card
|
|
||||||
entity: sensor.volvo_<your vin>_electric_range
|
|
||||||
name: Reichweite
|
|
||||||
layout: vertical
|
|
||||||
- type: custom:mushroom-entity-card
|
|
||||||
entity: sensor.volvo_<your vin>_battery_charge_level
|
|
||||||
name: Batteriestatus
|
|
||||||
layout: vertical
|
|
||||||
- type: custom:mushroom-entity-card
|
|
||||||
entity: sensor.volvo_<your vin>_estimated_charging_time
|
|
||||||
layout: vertical
|
|
||||||
name: Ladezeit
|
|
||||||
- type: horizontal-stack
|
|
||||||
cards:
|
|
||||||
- type: custom:mushroom-entity-card
|
|
||||||
entity: switch.volvo_<your vin>_climate_status
|
|
||||||
tap_action:
|
|
||||||
action: toggle
|
|
||||||
layout: vertical
|
|
||||||
name: Klimatisieren/Heizen
|
|
||||||
- type: custom:mushroom-template-card
|
|
||||||
primary: Daten aktualisieren
|
|
||||||
secondary: '{{ states(''sensor.volvo_<your vin>_last_data_update'')}}'
|
|
||||||
icon: mdi:update
|
|
||||||
layout: vertical
|
|
||||||
entity: button.volvo_<your vin>_update_data
|
|
||||||
- type: conditional
|
|
||||||
conditions:
|
|
||||||
- entity: sensor.volvo_<your vin>_estimated_charging_time
|
|
||||||
state_not: '0'
|
|
||||||
card:
|
|
||||||
type: custom:mushroom-entity-card
|
|
||||||
entity: sensor.volvo_<your vin>_estimated_charging_finish_time
|
|
||||||
name: Ladung vorraussichtlich abgeschlossen
|
|
||||||
show_name: true
|
|
||||||
- type: map
|
|
||||||
entities:
|
|
||||||
- entity: device_tracker.volvo_<your vin>_location
|
|
||||||
default_zoom: 16
|
|
||||||
dark_mode: false
|
|
||||||
hours_to_show: 0
|
|
||||||
auto_fit: true
|
|
||||||
aspect_ratio: '16:9'
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
</blockquote></details>
|
|
||||||
|
|
||||||
|
|
||||||
[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg
|
[aarch64-shield]: https://img.shields.io/badge/aarch64-yes-green.svg
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
## 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
|
||||||
|
### 🐛 Bug Fixes:
|
||||||
|
|
||||||
|
- Fix app crash if `debug` is not set #86
|
||||||
|
|
||||||
## v1.8.0
|
## v1.8.0
|
||||||
### 🚀 Features:
|
### 🚀 Features:
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
name: "Volvo2Mqtt"
|
name: "Volvo2Mqtt"
|
||||||
description: "Volvo AAOS MQTT bridge"
|
description: "Volvo AAOS MQTT bridge"
|
||||||
version: "1.8.0"
|
version: "1.8.2"
|
||||||
slug: "volvo2mqtt"
|
slug: "volvo2mqtt"
|
||||||
init: false
|
init: false
|
||||||
url: "https://github.com/Dielee/volvo2mqtt"
|
url: "https://github.com/Dielee/volvo2mqtt"
|
||||||
@@ -29,7 +29,7 @@ options:
|
|||||||
averageSpeedDivider: 1
|
averageSpeedDivider: 1
|
||||||
averageFuelConsumptionMultiplier: 1
|
averageFuelConsumptionMultiplier: 1
|
||||||
schema:
|
schema:
|
||||||
updateInterval: int(10,)
|
updateInterval: int(60,)
|
||||||
babelLocale: str
|
babelLocale: str
|
||||||
TZ: str
|
TZ: str
|
||||||
debug: bool
|
debug: bool
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
from config import settings
|
from config import settings
|
||||||
|
|
||||||
VERSION = "v1.8.0"
|
VERSION = "v1.8.2"
|
||||||
|
|
||||||
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"
|
||||||
|
|||||||
+4
-3
@@ -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()
|
||||||
|
|||||||
+16
-3
@@ -50,9 +50,10 @@ def setup_logging():
|
|||||||
'%b %d %H:%M:%S')
|
'%b %d %H:%M:%S')
|
||||||
file_log_handler.setFormatter(formatter)
|
file_log_handler.setFormatter(formatter)
|
||||||
|
|
||||||
if settings["debug"]:
|
if "debug" in settings:
|
||||||
sensitive_data_filter = SensitiveDataFilter(SENSITIVE_PATTERNS)
|
if settings["debug"]:
|
||||||
file_log_handler.addFilter(sensitive_data_filter)
|
sensitive_data_filter = SensitiveDataFilter(SENSITIVE_PATTERNS)
|
||||||
|
file_log_handler.addFilter(sensitive_data_filter)
|
||||||
|
|
||||||
console_log_handler = logging.StreamHandler(sys.stdout)
|
console_log_handler = logging.StreamHandler(sys.stdout)
|
||||||
console_log_handler.setFormatter(formatter)
|
console_log_handler.setFormatter(formatter)
|
||||||
@@ -135,3 +136,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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user