mirror of
https://github.com/Dielee/volvo2mqtt.git
synced 2026-08-12 18:59:53 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d01174e213 | ||
|
|
c87a3cb2d7 | ||
|
|
f6a26e5a41 | ||
|
|
42d07f1a4c | ||
|
|
71f03e505b | ||
|
|
2b6a2a4f4c | ||
|
|
38cca04473 |
@@ -3,6 +3,11 @@
|
|||||||
This component establishes a connection between the newer AAOS Volvo cars and Home Assistant via MQTT.<br>
|
This component establishes a connection between the newer AAOS Volvo cars and Home Assistant via MQTT.<br>
|
||||||
Maybe this component works also with other Volvo cars. Please try out the native Volvo [integration](https://www.home-assistant.io/integrations/volvooncall/) before using this component! If the native component doesn't work for your car, try this mqtt bridge.
|
Maybe this component works also with other Volvo cars. Please try out the native Volvo [integration](https://www.home-assistant.io/integrations/volvooncall/) before using this component! If the native component doesn't work for your car, try this mqtt bridge.
|
||||||
|
|
||||||
|
## Confirmed working with
|
||||||
|
- Volvo XC40 BEV (2023)
|
||||||
|
|
||||||
|
Please let me know if your car works with this addon so I can expand the list!
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
Just install this addon with the following command.
|
Just install this addon with the following command.
|
||||||
@@ -17,7 +22,7 @@ Here is what every option means:
|
|||||||
| `updateInterval` | `int` | **required** | Update intervall in seconds. |
|
| `updateInterval` | `int` | **required** | Update intervall in seconds. |
|
||||||
| `babelLocale` | `string` | **required** | Locale for date Format |
|
| `babelLocale` | `string` | **required** | Locale for date Format |
|
||||||
| `mqtt` | `json` | **required** | Broker = Mqtt Broker IP / Username and Passwort are optional! |
|
| `mqtt` | `json` | **required** | Broker = Mqtt Broker IP / Username and Passwort are optional! |
|
||||||
| `volvoData` | `json` | **required** | Username and password are required. Car vin can be a single vin or a list of multiple vins like `["vin1", "vin2"]`. If no vin is provided, <b>ALL</b> of your vehicles will be used. Vccapi key is your api key from [here](https://developer.volvocars.com/account/). |
|
| `volvoData` | `json` | **required** | Username and password are REQUIRED. Car vin can be a single vin or a list of multiple vins like `["vin1", "vin2"]`. If no vin is provided, <b>ALL</b> of your vehicles will be used. Vccapi key is REQUIRED. Get your Vccapi key from [here](https://developer.volvocars.com/account/). |
|
||||||
| `TZ` | `string` | | Container timezone eg "Europe/Berlin" |
|
| `TZ` | `string` | | Container timezone eg "Europe/Berlin" |
|
||||||
|
|
||||||
If you like my work:
|
If you like my work:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
VERSION = "v1.0.4"
|
VERSION = "v1.0.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"
|
||||||
|
|||||||
@@ -42,27 +42,28 @@ def on_disconnect(client, userdata, rc):
|
|||||||
|
|
||||||
def on_message(client, userdata, msg):
|
def on_message(client, userdata, msg):
|
||||||
if msg.topic in subscribed_topics:
|
if msg.topic in subscribed_topics:
|
||||||
|
vin = msg.topic.split('/')[2].split('_')[0]
|
||||||
payload = msg.payload.decode("UTF-8")
|
payload = msg.payload.decode("UTF-8")
|
||||||
if "climate_status" in msg.topic:
|
if "climate_status" in msg.topic:
|
||||||
global assumed_climate_state
|
global assumed_climate_state
|
||||||
if payload == "ON":
|
if payload == "ON":
|
||||||
api_thread = threading.Thread(target=volvo.api_call, args=(CLIMATE_START_URL, "POST", ))
|
api_thread = threading.Thread(target=volvo.api_call, args=(CLIMATE_START_URL, "POST", vin))
|
||||||
api_thread.start()
|
api_thread.start()
|
||||||
assumed_climate_state = "ON"
|
assumed_climate_state = "ON"
|
||||||
# Starting timer to disable climate after 30 mins
|
# Starting timer to disable climate after 30 mins
|
||||||
threading.Timer(30 * 60, volvo.disable_climate).start()
|
threading.Timer(30 * 60, volvo.disable_climate).start()
|
||||||
update_car_data()
|
update_car_data()
|
||||||
elif payload == "OFF":
|
elif payload == "OFF":
|
||||||
api_thread = threading.Thread(target=volvo.api_call, args=(CLIMATE_STOP_URL, "POST", ))
|
api_thread = threading.Thread(target=volvo.api_call, args=(CLIMATE_STOP_URL, "POST", vin))
|
||||||
api_thread.start()
|
api_thread.start()
|
||||||
assumed_climate_state = "OFF"
|
assumed_climate_state = "OFF"
|
||||||
update_car_data()
|
update_car_data()
|
||||||
elif "lock_status" in msg.topic:
|
elif "lock_status" in msg.topic:
|
||||||
if payload == "LOCK":
|
if payload == "LOCK":
|
||||||
volvo.api_call(CAR_LOCK_URL, "POST")
|
volvo.api_call(CAR_LOCK_URL, "POST", vin)
|
||||||
update_car_data()
|
update_car_data()
|
||||||
elif payload == "UNLOCK":
|
elif payload == "UNLOCK":
|
||||||
volvo.api_call(CAR_UNLOCK_URL, "POST")
|
volvo.api_call(CAR_UNLOCK_URL, "POST", vin)
|
||||||
update_car_data()
|
update_car_data()
|
||||||
elif "update_data" in msg.topic:
|
elif "update_data" in msg.topic:
|
||||||
if payload == "PRESS":
|
if payload == "PRESS":
|
||||||
@@ -74,6 +75,7 @@ def update_loop():
|
|||||||
while True:
|
while True:
|
||||||
print("Sending mqtt update...")
|
print("Sending mqtt update...")
|
||||||
update_car_data()
|
update_car_data()
|
||||||
|
print("Mqtt update done. Next run in " + str(settings["updateInterval"]) + " seconds.")
|
||||||
time.sleep(settings["updateInterval"])
|
time.sleep(settings["updateInterval"])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ token_expires_at: datetime
|
|||||||
refresh_token = None
|
refresh_token = None
|
||||||
vins = []
|
vins = []
|
||||||
recharge_response = {}
|
recharge_response = {}
|
||||||
recharge_last_update = None
|
recharge_last_update = {}
|
||||||
|
|
||||||
|
|
||||||
def authorize():
|
def authorize():
|
||||||
@@ -111,22 +111,22 @@ def api_call(url, method, vin, sensor_id=None):
|
|||||||
global recharge_response, recharge_last_update
|
global recharge_response, recharge_last_update
|
||||||
if url == RECHARGE_STATUS_URL:
|
if url == RECHARGE_STATUS_URL:
|
||||||
# Minimize API calls for recharge API
|
# Minimize API calls for recharge API
|
||||||
if not bool(recharge_response):
|
if not vin in recharge_response:
|
||||||
# No API Data cached, get fresh data from API
|
# No API Data for vin cached, get fresh data from API
|
||||||
print("Starting " + method + " call against " + url)
|
print("Starting " + method + " call against " + url)
|
||||||
response = session.get(url.format(vin), timeout=15)
|
response = session.get(url.format(vin), timeout=15)
|
||||||
recharge_response = response
|
recharge_response[vin] = response
|
||||||
recharge_last_update = datetime.now()
|
recharge_last_update[vin] = datetime.now()
|
||||||
else:
|
else:
|
||||||
if (datetime.now() - recharge_last_update).total_seconds() >= settings["updateInterval"]:
|
if (datetime.now() - recharge_last_update[vin]).total_seconds() >= settings["updateInterval"]:
|
||||||
# Old Data in Cache, updateing
|
# Old Data in Cache, updating
|
||||||
print("Starting " + method + " call against " + url)
|
print("Starting " + method + " call against " + url)
|
||||||
response = session.get(url.format(vin), timeout=15)
|
response = session.get(url.format(vin), timeout=15)
|
||||||
recharge_response = response
|
recharge_response[vin] = response
|
||||||
recharge_last_update = datetime.now()
|
recharge_last_update[vin] = datetime.now()
|
||||||
else:
|
else:
|
||||||
# Data is up do date, returning cached data
|
# Data is up do date, returning cached data
|
||||||
response = recharge_response
|
response = recharge_response[vin]
|
||||||
elif method == "GET":
|
elif method == "GET":
|
||||||
print("Starting " + method + " call against " + url)
|
print("Starting " + method + " call against " + url)
|
||||||
response = session.get(url.format(vin), timeout=15)
|
response = session.get(url.format(vin), timeout=15)
|
||||||
@@ -147,7 +147,10 @@ def api_call(url, method, vin, sensor_id=None):
|
|||||||
else:
|
else:
|
||||||
print("API Call failed. Status Code: " + str(response.status_code) + ". Error: " + response.text)
|
print("API Call failed. Status Code: " + str(response.status_code) + ". Error: " + response.text)
|
||||||
return ""
|
return ""
|
||||||
|
return parse_api_data(url, data, sensor_id)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_api_data(url, data, sensor_id=None):
|
||||||
if url == VEHICLE_DETAILS_URL:
|
if url == VEHICLE_DETAILS_URL:
|
||||||
return data["data"]
|
return data["data"]
|
||||||
elif sensor_id == "battery_charge_level":
|
elif sensor_id == "battery_charge_level":
|
||||||
|
|||||||
Reference in New Issue
Block a user