mirror of
https://github.com/Dielee/volvo2mqtt.git
synced 2026-07-22 02:13:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
391ae952d9 | ||
|
|
f9f5e218f5 | ||
|
|
12744b6397 | ||
|
|
065c10c5bc | ||
|
|
4b83aa149e | ||
|
|
4a8caaf436 | ||
|
|
710ca2fcbc | ||
|
|
c1998f8938 | ||
|
|
693e0b0048 | ||
|
|
f23f56e45e | ||
|
|
17eaa8dde2 | ||
|
|
8f3bf5f3b1 | ||
|
|
9d4f8fab0c | ||
|
|
414ac503b1 | ||
|
|
18926b67e4 | ||
|
|
f650ea9247 | ||
|
|
a7a2e1182c | ||
|
|
3d3227de0d | ||
|
|
44509529ff | ||
|
|
0dd5852d81 | ||
|
|
c6ddd71021 | ||
|
|
1f0612ca4a | ||
|
|
6306c9a4b3 | ||
|
|
8bd0388690 | ||
|
|
245dd82c82 | ||
|
|
8e471d8eb0 | ||
|
|
cb1377005c | ||
|
|
89bd76e981 | ||
|
|
19aafa3b21 |
@@ -27,20 +27,20 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm/v6,linux/arm/v8
|
||||
|
||||
@@ -26,6 +26,7 @@ If you like my work:<br>
|
||||
- XC40 BEV (2022)
|
||||
- XC40 PHEV (2021)
|
||||
- V60 T8 PHEV (2023)
|
||||
- V60 T6 PHEV (2025)
|
||||
- C40 BEV (2023)
|
||||
- C40 BEV (2022)
|
||||
- C40 BEV (2024)
|
||||
@@ -40,6 +41,7 @@ If you like my work:<br>
|
||||
- V90 PHEV T8 (2019)*
|
||||
- V90 PHEV T6 (2024)
|
||||
- V90 B5 Mildhybrid (2023)
|
||||
- EX40 BEV (2025)
|
||||
|
||||
*only partly working
|
||||
|
||||
@@ -50,9 +52,10 @@ Please let me know if your car works with this addon so I can expand the list!<b
|
||||
- Lock/unlock car
|
||||
- Start/stop climate
|
||||
- Sensor "Battery Charge Level"
|
||||
- Sensor "Battery Capacity"
|
||||
- Sensor "Electric Range"
|
||||
- Sensor "Charging System Status"
|
||||
- Sensor "Charging Connection Status" (partly broken since 2.10 car update)
|
||||
- Sensor "Charging Connection Status"
|
||||
- Sensor "Estimated Charging Finish Time"
|
||||
- Sensor "Door Lock Status (All doors, tank lid, and engine hood)"
|
||||
- Sensor "Window Lock Status (All windows and sunroof - Thanks to @navet)"
|
||||
@@ -86,8 +89,36 @@ The following steps are required for authentication in exactly this order:
|
||||
```etc ...```
|
||||
4. Now, open your mailbox and copy your OTP Code
|
||||
5. Open HomeAssistant and search for the entity ID ```text.volvo_otp```
|
||||
6. Paste your OTP into the text entity and press Enter
|
||||
7. If everything has worked, your addon is now authenticated. In the future, OTP authentication only needs to be done when updating, not when restarting the container.
|
||||
6. Paste your OTP into the text entity and **<ins>press Enter</ins>**<br>
|
||||
6a. (optional) If your OTP cannot be safed, try to paste your OTP code via MQTT to the following topic: `volvoAAOS2mqtt/otp_code` <p>
|
||||
<details>
|
||||
<summary>OTP Post Script</summary>
|
||||
<div>
|
||||
<p>
|
||||
1. Safe the following script in your script section <br>
|
||||
2. Go to https://yourHAUrl/developer-tools/service<br>
|
||||
3. Search for "Post Volvo OTP"<br>
|
||||
4. Tick "OTP" and fill in your OTP<br>
|
||||
5. Run this service<br>
|
||||
</div>
|
||||
|
||||
alias: Post Volvo OTP
|
||||
sequence:
|
||||
- service: mqtt.publish
|
||||
metadata: {}
|
||||
data:
|
||||
topic: volvoAAOS2mqtt/otp_code
|
||||
payload: "{{ otp }}"
|
||||
mode: single
|
||||
fields:
|
||||
otp:
|
||||
selector:
|
||||
text: null
|
||||
name: OTP
|
||||
description: Volvo OTP
|
||||
|
||||
</details>
|
||||
8. If everything has worked, your addon is now authenticated. In the future, OTP authentication only needs to be done when updating, not when restarting the container.
|
||||
|
||||
## Setup
|
||||
<b>Docker:</b>
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
requests~=2.31.0
|
||||
requests~=2.32.0
|
||||
dynaconf~=3.1.12
|
||||
paho-mqtt~=1.6.1
|
||||
Babel~=2.12.1
|
||||
|
||||
@@ -1,3 +1,65 @@
|
||||
## v1.9.7
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Fix EX30 battery state #230
|
||||
|
||||
## v1.9.6
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Fixed interior and exterior Images #219
|
||||
- Take care of broken token files #220
|
||||
|
||||
## v1.9.5
|
||||
### 🚀 Features:
|
||||
|
||||
- Added "retain" states to survive HA reboot
|
||||
|
||||
## v1.9.4
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Fix backend state API url
|
||||
|
||||
## v1.9.3
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Ignore retained OTP messages #193
|
||||
|
||||
## v1.9.2
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Try to fix OTP Input
|
||||
- Fix `SyntaxWarning: invalid escape sequence '\d'` #196
|
||||
|
||||
## v1.9.1
|
||||
### 🚀 Features:
|
||||
|
||||
- The token file now survives an HA addon update/restart
|
||||
|
||||
### 🐛 Bug Fixes:
|
||||
|
||||
- Extend OTP retry time to 120 seconds
|
||||
|
||||
## v1.9.0
|
||||
### ⚠️ Breaking change
|
||||
### 🚀 Features:
|
||||
|
||||
- Add "Battery Capacity" sensor. Thanks to @gurtjun!
|
||||
- OTP Auth
|
||||
This addon uses the same OTP authentication as the Volvo app, now.
|
||||
The following steps are required for authentication in exactly this order:
|
||||
|
||||
1. Setup volvo2Mqtt, either via Docker, or via HA addon (take a look at the "Setup" section)
|
||||
2. Fill in your settings and start volvo2Mqtt
|
||||
3. Your log will show the following lines
|
||||
Waiting for otp code... Please check your mailbox and post your otp code to the following mqtt topic "volvoAAOS2mqtt/otp_code". Retry 0/15
|
||||
Waiting for otp code... Please check your mailbox and post your otp code to the following mqtt topic "volvoAAOS2mqtt/otp_code". Retry 1/15
|
||||
etc ...
|
||||
4. Now, open your mailbox and copy your OTP Code
|
||||
5. Open HomeAssistant and search for the entity ID text.volvo_otp
|
||||
6. Paste your OTP into the text entity and press Enter
|
||||
7. If everything has worked, your addon is now authenticated. In the future, OTP authentication only needs to be done when updating, not when restarting the container.
|
||||
|
||||
|
||||
## v1.8.27
|
||||
### 🚀 Features:
|
||||
|
||||
|
||||
+4
-1
@@ -1,6 +1,9 @@
|
||||
ARG BUILD_FROM
|
||||
FROM $BUILD_FROM
|
||||
|
||||
# Add community packets
|
||||
RUN echo -e "https://nl.alpinelinux.org/alpine/latest-stable/main\nhttps://nl.alpinelinux.org/alpine/latest-stable/community" > /etc/apk/repositories
|
||||
|
||||
# Install requirements for add-on
|
||||
RUN apk add --no-cache python3 bash py3-pip
|
||||
|
||||
@@ -18,4 +21,4 @@ COPY / .
|
||||
RUN chmod a+x /volvoAAOS2mqtt/run.sh
|
||||
|
||||
# command to run on container start
|
||||
CMD [ "/volvoAAOS2mqtt/run.sh" ]
|
||||
CMD [ "/volvoAAOS2mqtt/run.sh" ]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
name: "Volvo2Mqtt"
|
||||
description: "Volvo AAOS MQTT bridge"
|
||||
version: "1.9.0"
|
||||
version: "1.9.6"
|
||||
slug: "volvo2mqtt"
|
||||
init: false
|
||||
url: "https://github.com/Dielee/volvo2mqtt"
|
||||
|
||||
+15
-14
@@ -1,6 +1,6 @@
|
||||
from config import settings
|
||||
|
||||
VERSION = "v1.9.0"
|
||||
VERSION = "v1.9.7"
|
||||
|
||||
OAUTH_TOKEN_URL = "https://volvoid.eu.volvocars.com/as/token.oauth2"
|
||||
OAUTH_AUTH_URL = "https://volvoid.eu.volvocars.com/as/authorization.oauth2"
|
||||
@@ -22,7 +22,7 @@ STATISTICS_URL = "https://api.volvocars.com/connected-vehicle/v2/vehicles/{0}/st
|
||||
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"
|
||||
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://public-developer-portal-bff.weu-prod.ecpaz.volvocars.biz/api/v1/backend-status"
|
||||
|
||||
LENGTH_KILOMETERS = "km"
|
||||
SPEED_KILOMETERS_PER_HOUR = "km/h"
|
||||
@@ -75,23 +75,24 @@ icon_states = {
|
||||
"door_rear_right": {"ON": "car-door", "OFF": "car-door-lock"},
|
||||
"engine_state": {"ON": "engine-outline", "OFF": "engine-off-outline"},
|
||||
"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"},
|
||||
{"from": float('inf'), "to": 100, "icon": "battery"},
|
||||
{"from": 100, "to": 90, "icon": "battery-90"},
|
||||
{"from": 90, "to": 80, "icon": "battery-80"},
|
||||
{"from": 80, "to": 70, "icon": "battery-70"},
|
||||
{"from": 70, "to": 60, "icon": "battery-60"},
|
||||
{"from": 60, "to": 50, "icon": "battery-50"},
|
||||
{"from": 50, "to": 40, "icon": "battery-40"},
|
||||
{"from": 40, "to": 30, "icon": "battery-30"},
|
||||
{"from": 30, "to": 20, "icon": "battery-20"},
|
||||
{"from": 20, "to": 10, "icon": "battery-10"},
|
||||
{"from": 10, "to": 0, "icon": "battery-alert-variant-outline"},
|
||||
]
|
||||
}
|
||||
|
||||
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": FUEL_BATTERY_STATE_URL, "state_class": "measurement"},
|
||||
{"name": "Battery Capacity", "domain": "sensor", "device_class": "energy_storage", "id": "battery_capacity", "unit": ENERGY_KILO_WATT_HOUR, "icon": "car-battery", "url": VEHICLE_DETAILS_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": 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},
|
||||
@@ -138,5 +139,5 @@ supported_entities = [
|
||||
]
|
||||
|
||||
old_entity_ids = ["months_to_service", "service_warning_trigger", "distance_to_empty"]
|
||||
otp_max_loops = 15
|
||||
otp_max_loops = 24
|
||||
otp_mqtt_topic = "volvoAAOS2mqtt/otp_code"
|
||||
+67
-25
@@ -5,6 +5,7 @@ import json
|
||||
import volvo
|
||||
import util
|
||||
import os
|
||||
import requests
|
||||
from threading import Thread, Timer
|
||||
from datetime import datetime
|
||||
from babel.dates import format_datetime
|
||||
@@ -47,38 +48,51 @@ def connect():
|
||||
|
||||
|
||||
def create_otp_input():
|
||||
state_topic = otp_mqtt_topic + "/state"
|
||||
config = {
|
||||
"name": "Volvo OTP",
|
||||
"object_id": f"volvo_otp",
|
||||
"schema": "state",
|
||||
"command_topic": otp_mqtt_topic,
|
||||
"unique_id": f"volvoAAOS2mqtt_otp",
|
||||
"pattern": "\d{6}",
|
||||
"icon": "mdi:two-factor-authentication"
|
||||
"state_topic": state_topic,
|
||||
"unique_id": "volvoAAOS2mqtt_otp",
|
||||
"pattern": r"\d{6}",
|
||||
"icon": "mdi:two-factor-authentication",
|
||||
"mode": "text"
|
||||
}
|
||||
|
||||
mqtt_client.publish(
|
||||
f"homeassistant/text/volvoAAOS2mqtt/volvo_otp/config",
|
||||
"homeassistant/text/volvoAAOS2mqtt/volvo_otp/config",
|
||||
json.dumps(config),
|
||||
retain=True
|
||||
)
|
||||
|
||||
def delete_otp_input():
|
||||
topic = "homeassistant/text/volvoAAOS2mqtt/volvo_otp/config"
|
||||
mqtt_client.publish(topic, payload="", retain=True)
|
||||
mqtt_client.publish(
|
||||
state_topic,
|
||||
"000000",
|
||||
retain=True
|
||||
)
|
||||
|
||||
def set_otp_state():
|
||||
mqtt_client.publish(
|
||||
otp_mqtt_topic + "/state",
|
||||
otp_code,
|
||||
retain=True
|
||||
)
|
||||
|
||||
|
||||
def send_car_images(vin, data, device):
|
||||
if util.keys_exists(data, "images"):
|
||||
for entity in [{"name": "Exterior Image", "id": "exterior_image"},
|
||||
{"name": "Interior Image", "id": "interior_image"}]:
|
||||
url_topic = f"homeassistant/image/{vin}_{entity['id']}/image_url"
|
||||
image_topic = f"homeassistant/image/{vin}_{entity['id']}/image_topic"
|
||||
config = {
|
||||
"name": entity["name"],
|
||||
"object_id": f"volvo_{vin}_{entity['id']}",
|
||||
"schema": "state",
|
||||
"icon": "mdi:image-area",
|
||||
"url_topic": url_topic,
|
||||
"content_type": "image/png",
|
||||
"image_topic": image_topic,
|
||||
"device": device,
|
||||
"unique_id": f"volvoAAOS2mqtt_{vin}_{entity['id']}",
|
||||
"availability_topic": availability_topic
|
||||
@@ -90,19 +104,41 @@ def send_car_images(vin, data, device):
|
||||
retain=True
|
||||
)
|
||||
|
||||
headers = {"User-Agent": "(Windows NT 10.0; Win64; x64)",
|
||||
"sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "document", "Accept-Encoding": "gzip, deflate, br, zstd",
|
||||
"sec-fetch-mode": "navigate", "sec-fetch-site": "none", "sec-fetch-user": "?1", "upgrade-insecure-requests": "1"}
|
||||
|
||||
# Post exterior image
|
||||
if entity["id"] == "exterior_image":
|
||||
mqtt_client.publish(
|
||||
url_topic,
|
||||
data["images"]["exteriorImageUrl"],
|
||||
retain=True
|
||||
)
|
||||
if not os.path.exists("exterior_image.png"):
|
||||
response = requests.get(data["images"]["exteriorImageUrl"], headers=headers)
|
||||
if response.status_code == 200:
|
||||
with open("exterior_image.png", 'wb') as image:
|
||||
image.write(response.content)
|
||||
|
||||
if os.path.exists("exterior_image.png"):
|
||||
ext_image = open("exterior_image.png", mode="rb").read()
|
||||
mqtt_client.publish(
|
||||
image_topic,
|
||||
ext_image,
|
||||
retain=True
|
||||
)
|
||||
|
||||
if entity["id"] == "interior_image":
|
||||
mqtt_client.publish(
|
||||
url_topic,
|
||||
data["images"]["internalImageUrl"],
|
||||
retain=True
|
||||
)
|
||||
# Post interior Image
|
||||
if not os.path.exists("interior_image.png"):
|
||||
response = requests.get(data["images"]["internalImageUrl"], headers=headers)
|
||||
if response.status_code == 200:
|
||||
with open("interior_image.png", 'wb') as image:
|
||||
image.write(response.content)
|
||||
|
||||
if os.path.exists("interior_image.png"):
|
||||
int_image = open("interior_image.png", mode="rb").read()
|
||||
mqtt_client.publish(
|
||||
image_topic,
|
||||
int_image,
|
||||
retain=True
|
||||
)
|
||||
|
||||
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
@@ -119,8 +155,12 @@ def on_disconnect(client, userdata, rc):
|
||||
def on_message(client, userdata, msg):
|
||||
payload = msg.payload.decode("UTF-8")
|
||||
if msg.topic == otp_mqtt_topic:
|
||||
global otp_code
|
||||
otp_code = payload
|
||||
if msg.retain == 0:
|
||||
global otp_code
|
||||
otp_code = payload
|
||||
set_otp_state()
|
||||
else:
|
||||
logging.warning("Found retained OTP, this can't work! Please clean retained messages!")
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
@@ -300,7 +340,8 @@ def update_car_data(force_update=False, overwrite={}):
|
||||
elif entity["id"] == "warnings":
|
||||
mqtt_client.publish(
|
||||
f"homeassistant/{entity['domain']}/{vin}_{entity['id']}/attributes",
|
||||
json.dumps(state)
|
||||
json.dumps(state),
|
||||
retain=True
|
||||
)
|
||||
if state:
|
||||
state = sum(value == "FAILURE" for value in state.values())
|
||||
@@ -314,7 +355,8 @@ def update_car_data(force_update=False, overwrite={}):
|
||||
if state or state == 0:
|
||||
mqtt_client.publish(
|
||||
topic,
|
||||
json.dumps(state) if isinstance(state, dict) or isinstance(state, list) else state
|
||||
json.dumps(state) if isinstance(state, dict) or isinstance(state, list) else state,
|
||||
retain=True
|
||||
)
|
||||
update_ha_device(entity, vin, state)
|
||||
|
||||
@@ -425,11 +467,11 @@ def create_ha_devices():
|
||||
|
||||
|
||||
def send_heartbeat():
|
||||
mqtt_client.publish(availability_topic, "online")
|
||||
mqtt_client.publish(availability_topic, "online", retain=True)
|
||||
|
||||
|
||||
def send_offline():
|
||||
mqtt_client.publish(availability_topic, "offline")
|
||||
mqtt_client.publish(availability_topic, "offline", retain=True)
|
||||
|
||||
|
||||
def delete_old_entities():
|
||||
|
||||
+14
-6
@@ -42,14 +42,22 @@ def get_volvo_app_version():
|
||||
else:
|
||||
return "5.37.0"
|
||||
|
||||
def save_to_json(data):
|
||||
with open('.token', 'w', encoding='utf-8') as f:
|
||||
def get_token_path():
|
||||
token_path = ".token"
|
||||
if os.environ.get("IS_HA_ADDON"):
|
||||
check_existing_folder("/addons/volvo2mqtt/token/")
|
||||
token_path = "/addons/volvo2mqtt/token/.token"
|
||||
|
||||
return token_path
|
||||
|
||||
def save_to_json(data, token_path):
|
||||
with open(token_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
def get_icon_between(icon_list, state):
|
||||
icon = None
|
||||
for s in icon_list:
|
||||
if s["to"] <= state <= s["from"]:
|
||||
if s["to"] <= state < s["from"]:
|
||||
icon = s["icon"]
|
||||
return icon
|
||||
|
||||
@@ -57,7 +65,7 @@ def get_icon_between(icon_list, state):
|
||||
def setup_logging():
|
||||
log_location = "volvo2mqtt.log"
|
||||
if os.environ.get("IS_HA_ADDON"):
|
||||
check_existing_folder()
|
||||
check_existing_folder("/addons/volvo2mqtt/log/")
|
||||
log_location = "/addons/volvo2mqtt/log/volvo2mqtt.log"
|
||||
|
||||
logging.Formatter.converter = lambda *args: datetime.now(tz=TZ).timetuple()
|
||||
@@ -90,8 +98,8 @@ def setup_logging():
|
||||
logger.setLevel(logging.ERROR)
|
||||
|
||||
|
||||
def check_existing_folder():
|
||||
Path("/addons/volvo2mqtt/log/").mkdir(parents=True, exist_ok=True)
|
||||
def check_existing_folder(path):
|
||||
Path(path).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def keys_exists(element, *keys):
|
||||
|
||||
+16
-8
@@ -35,12 +35,18 @@ backend_status = ""
|
||||
|
||||
def authorize(renew_tokenfile=False):
|
||||
global refresh_token
|
||||
if os.path.isfile(".token") and not renew_tokenfile:
|
||||
|
||||
token_path = util.get_token_path()
|
||||
if os.path.isfile(token_path) and not renew_tokenfile:
|
||||
logging.info("Using login from token file")
|
||||
f = open('.token')
|
||||
data = json.load(f)
|
||||
refresh_token = data["refresh_token"]
|
||||
refresh_auth()
|
||||
f = open(token_path)
|
||||
try:
|
||||
data = json.load(f)
|
||||
refresh_token = data["refresh_token"]
|
||||
refresh_auth()
|
||||
except ValueError:
|
||||
logging.warning("Detected corrupted token file, restarting auth process")
|
||||
authorize(True)
|
||||
else:
|
||||
logging.info("Starting login with OTP")
|
||||
auth_session = requests.session()
|
||||
@@ -91,7 +97,7 @@ def authorize(renew_tokenfile=False):
|
||||
token_expires_at = datetime.now(util.TZ) + timedelta(seconds=(token_data["expires_in"] - 30))
|
||||
refresh_token = token_data["refresh_token"]
|
||||
|
||||
util.save_to_json(token_data)
|
||||
util.save_to_json(token_data, token_path)
|
||||
else:
|
||||
message = auth.json()
|
||||
raise Exception(message["details"][0]["userMessage"])
|
||||
@@ -154,7 +160,6 @@ def send_otp(auth_session, data):
|
||||
if not mqtt.otp_code:
|
||||
raise Exception ("No OTP found, exting...")
|
||||
|
||||
mqtt.delete_otp_input()
|
||||
auth = auth_session.post(next_url, data=json.dumps(body))
|
||||
if auth.status_code == 200:
|
||||
return auth.json()
|
||||
@@ -184,8 +189,9 @@ def refresh_auth():
|
||||
return None
|
||||
|
||||
if auth.status_code == 200:
|
||||
token_path = util.get_token_path()
|
||||
data = auth.json()
|
||||
util.save_to_json(data)
|
||||
util.save_to_json(data, token_path)
|
||||
session.headers.update({"authorization": "Bearer " + data["access_token"]})
|
||||
|
||||
global token_expires_at
|
||||
@@ -548,6 +554,8 @@ def parse_api_data(data, sensor_id=None):
|
||||
|
||||
if sensor_id == "battery_charge_level":
|
||||
return data["batteryChargeLevel"]["value"] if util.keys_exists(data, "batteryChargeLevel") else None
|
||||
elif sensor_id == "battery_capacity":
|
||||
return data["batteryCapacityKWH"] if util.keys_exists(data, "batteryCapacityKWH") else None
|
||||
elif sensor_id == "electric_range":
|
||||
return util.convert_metric_values(data["electricRange"]["value"]) \
|
||||
if util.keys_exists(data, "electricRange") else None
|
||||
|
||||
Reference in New Issue
Block a user