Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into auxiliary-heating-timers
Browse files Browse the repository at this point in the history
  • Loading branch information
prvakt committed Jan 15, 2025
2 parents b0ebcac + c784cf0 commit 6e77ebc
Show file tree
Hide file tree
Showing 11 changed files with 950 additions and 140 deletions.
804 changes: 804 additions & 0 deletions fixtures/kodiaq_iv_2024_ps7dyc_selection.yaml

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions myskoda/models/air_conditioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,11 @@ class AirConditioning(DataClassORJSONMixin):
timers: list[AirConditioningTimer]
errors: list[Any]
state: AirConditioningState
steering_wheel_position: Side = field(metadata=field_options(alias="steeringWheelPosition"))
window_heating_state: WindowHeatingState = field(
metadata=field_options(alias="windowHeatingState")
steering_wheel_position: Side | None = field(
default=None, metadata=field_options(alias="steeringWheelPosition")
)
window_heating_state: WindowHeatingState | None = field(
default=None, metadata=field_options(alias="windowHeatingState")
)
car_captured_timestamp: datetime | None = field(
default=None, metadata=field_options(alias="carCapturedTimestamp")
Expand Down
79 changes: 2 additions & 77 deletions myskoda/models/service_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
from typing import Generic, TypeVar

from mashumaro import field_options
from mashumaro.config import BaseConfig
from mashumaro.mixins.orjson import DataClassORJSONMixin
from mashumaro.types import Discriminator

from .charging import ChargeMode, ChargingState

Expand Down Expand Up @@ -46,14 +44,6 @@ class ServiceEvent(Generic[T], DataClassORJSONMixin):
Service Events are unsolicited events emitted by the MQTT bus towards the client.
"""

class Config(BaseConfig):
"""Configuration class for altering the behavior of discriminator."""

discriminator = Discriminator(
field="name",
include_subtypes=True,
)

version: int
producer: str
name: ServiceEventName
Expand Down Expand Up @@ -122,76 +112,11 @@ class ServiceEventChargingData(ServiceEventData):
)


class ServiceEventChangeAccess(ServiceEvent):
"""Event class for change-access service event."""

name = ServiceEventName.CHANGE_ACCESS
data: ServiceEventData


class ServiceEventChangeChargeMode(ServiceEvent):
"""Event class for change-charge-mode service event."""

name = ServiceEventName.CHANGE_CHARGE_MODE
data: ServiceEventData


class ServiceEventChangeLights(ServiceEvent):
"""Event class for change-lights service event."""

name = ServiceEventName.CHANGE_LIGHTS
data: ServiceEventData


class ServiceEventChangeRemainingTime(ServiceEvent):
"""Event class for change-remaining-time service event."""

name = ServiceEventName.CHANGE_REMAINING_TIME
data: ServiceEventData


class ServiceEventChangeSoc(ServiceEvent):
"""Event class for change-soc service event."""

name = ServiceEventName.CHANGE_SOC
data: ServiceEventChargingData


class ServiceEventChargingCompleted(ServiceEvent):
"""Event class for charging-completed service event."""

name = ServiceEventName.CHARGING_COMPLETED
@dataclass
class ServiceEventWithChargingData(ServiceEvent):
data: ServiceEventChargingData


class ServiceEventChargingStatusChanged(ServiceEvent):
"""Event class for charging-status-changed service event."""

name = ServiceEventName.CHARGING_STATUS_CHANGED
data: ServiceEventData


class ServiceEventClimatisationCompleted(ServiceEvent):
"""Event class for climatisation-completed service event."""

name = ServiceEventName.CLIMATISATION_COMPLETED
data: ServiceEventData


class ServiceEventDepartureReady(ServiceEvent):
"""Event class for depature-ready service event."""

name = ServiceEventName.DEPARTURE_READY
data: ServiceEventData


class ServiceEventDepartureStatusChanged(ServiceEvent):
"""Event class for depature-status-changed service event."""

name = ServiceEventName.DEPARTURE_STATUS_CHANGED
data: ServiceEventData


class UnexpectedChargeModeError(Exception):
pass

Expand Down
12 changes: 10 additions & 2 deletions myskoda/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import aiomqtt

from myskoda.auth.authorization import Authorization
from myskoda.models.service_event import ServiceEvent
from myskoda.models.service_event import ServiceEvent, ServiceEventWithChargingData

from .const import (
MQTT_ACCOUNT_EVENT_TOPICS,
Expand Down Expand Up @@ -213,6 +213,14 @@ def _on_message(self, msg: aiomqtt.Message) -> None:

self._parse_topic(topic_match, data)

@staticmethod
def _get_charging_event(data: str) -> ServiceEvent:
try:
event = ServiceEventWithChargingData.from_json(data)
except ValueError:
event = ServiceEvent.from_json(data)
return event

def _parse_topic(self, topic_match: re.Match[str], data: str) -> None:
"""Parse the topic and extract relevant parts."""
[user_id, vin, event_type, topic] = topic_match.groups()
Expand Down Expand Up @@ -263,7 +271,7 @@ def _parse_topic(self, topic_match: re.Match[str], data: str) -> None:
vin=vin,
user_id=user_id,
timestamp=datetime.now(tz=UTC),
event=ServiceEvent.from_json(data),
event=self._get_charging_event(data),
)
)
elif event_type == EventType.SERVICE_EVENT and topic == "departure":
Expand Down
39 changes: 21 additions & 18 deletions myskoda/myskoda.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,24 +420,27 @@ async def _request_capability_data(
self, vehicle: Vehicle, vin: str, capa: CapabilityId
) -> None:
"""Request specific capability data from MySkoda API."""
match capa:
case CapabilityId.AIR_CONDITIONING:
vehicle.air_conditioning = await self.get_air_conditioning(vin)
case CapabilityId.AUXILIARY_HEATING:
vehicle.auxiliary_heating = await self.get_auxiliary_heating(vin)
case CapabilityId.CHARGING:
vehicle.charging = await self.get_charging(vin)
case CapabilityId.PARKING_POSITION:
vehicle.positions = await self.get_positions(vin)
case CapabilityId.STATE:
vehicle.status = await self.get_status(vin)
vehicle.driving_range = await self.get_driving_range(vin)
case CapabilityId.TRIP_STATISTICS:
vehicle.trip_statistics = await self.get_trip_statistics(vin)
case CapabilityId.VEHICLE_HEALTH_INSPECTION:
vehicle.health = await self.get_health(vin)
case CapabilityId.DEPARTURE_TIMERS:
vehicle.departure_info = await self.get_departure_timers(vin)
try:
match capa:
case CapabilityId.AIR_CONDITIONING:
vehicle.air_conditioning = await self.get_air_conditioning(vin)
case CapabilityId.AUXILIARY_HEATING:
vehicle.auxiliary_heating = await self.get_auxiliary_heating(vin)
case CapabilityId.CHARGING:
vehicle.charging = await self.get_charging(vin)
case CapabilityId.PARKING_POSITION:
vehicle.positions = await self.get_positions(vin)
case CapabilityId.STATE:
vehicle.status = await self.get_status(vin)
vehicle.driving_range = await self.get_driving_range(vin)
case CapabilityId.TRIP_STATISTICS:
vehicle.trip_statistics = await self.get_trip_statistics(vin)
case CapabilityId.VEHICLE_HEALTH_INSPECTION:
vehicle.health = await self.get_health(vin)
case CapabilityId.DEPARTURE_TIMERS:
vehicle.departure_info = await self.get_departure_timers(vin)
except Exception as err: # noqa: BLE001
_LOGGER.warning("Requesting %s failed: %s, continue", capa, err)

async def get_all_vehicles(self) -> list[Vehicle]:
"""Load all vehicles based on their capabilities."""
Expand Down
59 changes: 30 additions & 29 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pygments = { version = "^2.18.0", optional = true }
pyright = "^1.1.379"
pytest = "^8"
pytest-asyncio = "^0"
ruff = ">=0.6.4,<0.9.0"
ruff = ">=0.6.4,<0.10.0"
pytest-cov = ">=5,<7"
aioresponses = "^0.7.6"
amqtt = "0.11.0-beta1"
Expand Down
31 changes: 31 additions & 0 deletions tests/fixtures/enyaq/air-conditioning-no-steering.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"state": "INVALID",
"chargerConnectionState": "DISCONNECTED",
"chargerLockState": "UNLOCKED",
"timers": [
{
"id": 1,
"enabled": false,
"time": "09:55",
"type": "ONE_OFF",
"selectedDays": [
"SATURDAY"
]
},
{
"id": 2,
"enabled": false,
"time": "00:00",
"type": "ONE_OFF",
"selectedDays": [
"SATURDAY"
]
}
],
"errors": [
{
"type": "UNAVAILABLE_CLIMA_INFORMATION",
"description": "APIs for obtaining air conditioning status are not available"
}
]
}
Loading

0 comments on commit 6e77ebc

Please sign in to comment.