Skip to content

Commit

Permalink
Enable Window Heater + Preparation for more climatisation options
Browse files Browse the repository at this point in the history
Small fix for auxiliary_climatisation sensor as well.
  • Loading branch information
stickpin committed Dec 19, 2023
1 parent 248c59f commit 00e3750
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 8 deletions.
54 changes: 52 additions & 2 deletions volkswagencarnet/vw_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import jwt
import logging
from aiohttp import ClientSession, ClientTimeout, client_exceptions
from aiohttp.hdrs import METH_GET, METH_POST
from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT
from bs4 import BeautifulSoup
from json import dumps as to_json
from urllib.parse import urljoin, parse_qs, urlparse
Expand Down Expand Up @@ -487,6 +487,22 @@ async def post(self, url, vin="", tries=0, return_raw=False, **data):
else:
raise

async def put(self, url, vin="", tries=0, return_raw=False, **data):
"""Perform a put query."""
try:
if data:
return await self._request(METH_PUT, self._make_url(url, vin), return_raw=return_raw, **data)
else:
return await self._request(METH_PUT, self._make_url(url, vin), return_raw=return_raw)
except client_exceptions.ClientResponseError as error:
if error.status == 429 and tries < MAX_RETRIES_ON_RATE_LIMIT:
delay = randint(1, 3 + tries * 2)
_LOGGER.debug(f"Server side throttled. Waiting {delay}, try {tries + 1}")
await asyncio.sleep(delay)
return await self.post(url, vin, tries + 1, return_raw=return_raw, **data)
else:
raise

# Construct URL from request, home region and variables
def _make_url(self, ref, vin=""):
# TODO after verifying that we don't need home region handling anymore, this method should be completely removed
Expand Down Expand Up @@ -835,6 +851,10 @@ async def get_request_status(self, vin, sectionId, requestId):
url = (
f"fs-car/bs/$sectionId/v1/{BRAND}/{self._session_country}/vehicles/$vin/climater/actions/$requestId"
)
elif sectionId == "window_heating":
url = (
f"{BASE_API}/vehicle/v1/vehicles/{vin}/selectivestatus?jobs=climatisation"
)
elif sectionId == "batterycharge":
url = (
f"fs-car/bs/$sectionId/v1/{BRAND}/{self._session_country}/vehicles/$vin/charger/actions/$requestId"
Expand All @@ -851,8 +871,12 @@ async def get_request_status(self, vin, sectionId, requestId):
url = re.sub("\\$requestId", requestId, url)

response = await self.get(url, vin)
# window_heating
window_heating_status = response.get("climatisation", {}).get("windowHeatingStatus", {}).get("requests", {})[0].get("status", False)
if window_heating_status:
result = window_heating_status
# Pre-heater, ???
if response.get("requestStatusResponse", {}).get("status", False):
elif response.get("requestStatusResponse", {}).get("status", False):
result = response.get("requestStatusResponse", {}).get("status", False)
# For electric charging, climatisation and departure timers
elif response.get("action", {}).get("actionState", False):
Expand Down Expand Up @@ -1041,6 +1065,32 @@ async def setClimater(self, vin, data, spin):
self._session_headers.pop("X-securityToken", None)
raise

async def setWindowHeater(self, vin, action):
"""Execute window heating actions."""

action = "start" if action else "stop"

try:
response_raw = None
if action in ["start", "stop"]:
response_raw = await self.post(f"{BASE_API}/vehicle/v1/vehicles/{vin}/windowheating/{action}", json={}, return_raw=True)

response = await response_raw.json(loads=json_loads)
if not response:
raise Exception("Invalid or no response")
elif response == 429:
return dict({"id": None, "state": "Throttled", "rate_limit_remaining": 0})
else:
request_id = response.get("data", {}).get("requestID", 0)
remaining = response_raw.headers.get("Vcf-Remaining-Calls")
_LOGGER.debug(
f'Request for window heating returned with request id: {request_id},'
f" remaining requests: {remaining}"
)
return dict({"id": str(request_id), "rate_limit_remaining": remaining})
except Exception as e:
raise Exception("Unknown error during setWindowHeater") from e

async def setPreHeater(self, vin, data, spin):
"""Petrol/diesel parking heater actions."""
content_type = None
Expand Down
13 changes: 7 additions & 6 deletions volkswagencarnet/vw_vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def __init__(self, conn, url):
"tripStatistics": {"active": False},
"measurements": {"active": False},
"honkAndFlash": {"active": False},
"parkingPosition": {"active": False}
"parkingPosition": {"active": False},
"climatisation": {"active": False}
# "rheating_v1": {"active": False},
# "rclima_v1": {"active": False},
# "statusreport_v1": {"active": False},
Expand Down Expand Up @@ -326,7 +327,7 @@ async def wait_for_request(self, section, request, retry_count=36):
try:
status = await self._connection.get_request_status(self.vin, section, request)
_LOGGER.debug(f"Request ID {request}: {status}")
if status == "In progress":
if status == "in_progress":
self._requests["state"] = "In progress"
await asyncio.sleep(5)
return await self.wait_for_request(section, request)
Expand Down Expand Up @@ -436,12 +437,11 @@ async def set_climatisation_temp(self, temperature=20):
async def set_window_heating(self, action="stop"):
"""Turn on/off window heater."""
if self.is_window_heater_supported:
if action in ["start", "stop"]:
data = {"action": {"type": action + "WindowHeating"}}
else:
if not action in ["start", "stop"]:
_LOGGER.error(f'Window heater action "{action}" is not supported.')
raise Exception(f'Window heater action "{action}" is not supported.')
return await self.set_climater(data)
response = await self._connection.setWindowHeater(self.vin, (action == "start"))
return await self._handle_response(response=response, topic="window_heating", error_msg=f"Failed to {action} window heating")
else:
_LOGGER.error("No climatisation support.")
raise Exception("No climatisation support.")
Expand Down Expand Up @@ -1330,6 +1330,7 @@ def auxiliary_climatisation(self) -> bool:
climatisation_state = find_path(self.attrs, "climatisation.climatisationStatus.value.climatisationState")
if climatisation_state in ["heating", "heatingAuxiliary", "on"]:
return True
return False

@property
def auxiliary_climatisation_last_updated(self) -> datetime:
Expand Down

0 comments on commit 00e3750

Please sign in to comment.