Source code for nwp500.mqtt_events
"""Typed event definitions for NavienMqttClient.
This module provides a centralized registry of all events emitted by the
NavienMqttClient, with full type information and documentation. This enables:
- IDE autocomplete for event names
- Type-safe event handlers
- Clear contracts for event data
- Programmatic event discovery
Example::
from nwp500.mqtt_events import MqttClientEvents
from nwp500.unit_system import get_unit_system
# Type-safe event listening with autocomplete
def on_temperature_changed(event):
unit = "°C" if get_unit_system() == "metric" else "°F"
print(
f"Temp: {event.old_temperature}{unit} → "
f"{event.new_temperature}{unit}"
)
mqtt_client.on(MqttClientEvents.TEMPERATURE_CHANGED, on_temperature_changed)
# List all available events
for event_name in MqttClientEvents.get_all_events():
print(event_name)
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, cast
if TYPE_CHECKING:
from .enums import CurrentOperationMode, ErrorCode
from .models import DeviceFeature, DeviceStatus
[docs]
@dataclass(frozen=True)
class ConnectionInterruptedEvent:
"""Emitted when MQTT connection is interrupted.
Attributes:
error: The error that caused the interruption
"""
error: Exception
[docs]
@dataclass(frozen=True)
class ConnectionResumedEvent:
"""Emitted when MQTT connection is resumed after interruption.
Attributes:
return_code: MQTT return code (0 = success)
session_present: Whether session state was preserved
"""
return_code: int
session_present: bool
[docs]
@dataclass(frozen=True)
class StatusReceivedEvent:
"""Emitted when a device status message is received.
Attributes:
device_mac: MAC address of the origin device
status: The current device status snapshot
"""
device_mac: str
status: DeviceStatus
[docs]
@dataclass(frozen=True)
class TemperatureChangedEvent:
"""Emitted when the DHW temperature changes.
Attributes:
device_mac: MAC address of the origin device
old_temperature: Previous DHW temperature in user's preferred unit
(Celsius or Fahrenheit based on unit system context)
new_temperature: New DHW temperature in user's preferred unit
(Celsius or Fahrenheit based on unit system context)
"""
device_mac: str
old_temperature: float
new_temperature: float
[docs]
@dataclass(frozen=True)
class ModeChangedEvent:
"""Emitted when the device operation mode changes.
Attributes:
device_mac: MAC address of the origin device
old_mode: Previous operation mode
new_mode: New operation mode
"""
device_mac: str
old_mode: CurrentOperationMode
new_mode: CurrentOperationMode
[docs]
@dataclass(frozen=True)
class PowerChangedEvent:
"""Emitted when instantaneous power consumption changes.
Attributes:
device_mac: MAC address of the origin device
old_power: Previous power consumption in watts
new_power: New power consumption in watts
"""
device_mac: str
old_power: float
new_power: float
[docs]
@dataclass(frozen=True)
class HeatingStartedEvent:
"""Emitted when device transitions from idle to heating.
Attributes:
device_mac: MAC address of the origin device
status: Device status when heating started
"""
device_mac: str
status: DeviceStatus
[docs]
@dataclass(frozen=True)
class HeatingStoppedEvent:
"""Emitted when device transitions from heating to idle.
Attributes:
device_mac: MAC address of the origin device
status: Device status when heating stopped
"""
device_mac: str
status: DeviceStatus
[docs]
@dataclass(frozen=True)
class ErrorDetectedEvent:
"""Emitted when a device error is first detected.
Attributes:
device_mac: MAC address of the origin device
error_code: The error code that occurred
status: Device status when error was detected
"""
device_mac: str
error_code: ErrorCode
status: DeviceStatus
[docs]
@dataclass(frozen=True)
class ErrorClearedEvent:
"""Emitted when a device error is resolved.
Attributes:
device_mac: MAC address of the origin device
error_code: The error code that was cleared
"""
device_mac: str
error_code: ErrorCode
[docs]
@dataclass(frozen=True)
class FeatureReceivedEvent:
"""Emitted when device feature information is received.
Attributes:
device_mac: MAC address of the origin device
feature: The device feature information
"""
device_mac: str
feature: DeviceFeature
[docs]
class MqttClientEvents:
"""Registry of all NavienMqttClient events.
This class provides string constants for all events emitted by
NavienMqttClient, with associated event data types documented in
their dataclass definitions.
Usage::
mqtt_client.on(
MqttClientEvents.TEMPERATURE_CHANGED,
lambda event: update_display(event.new_temperature)
)
# Wait for a specific event
args, _ = await mqtt_client.wait_for(
MqttClientEvents.CONNECTION_RESUMED
)
connection_event = args[0]
# List all available events
events = ', '.join(MqttClientEvents.get_all_events())
print(f"Available events: {events}")
See Also:
:doc:`../guides/event_system` - Comprehensive event handling guide
"""
# Connection lifecycle events
CONNECTION_INTERRUPTED = "connection_interrupted"
"""Emitted: MQTT connection interrupted with error.
Args:
event (ConnectionInterruptedEvent): Event object with the error field.
See: :class:`ConnectionInterruptedEvent`
"""
CONNECTION_RESUMED = "connection_resumed"
"""Emitted: MQTT connection resumed after interruption.
Args:
event (ConnectionResumedEvent): Event object with return_code and
session_present fields.
See: :class:`ConnectionResumedEvent`
"""
# Device status events
STATUS_RECEIVED = "status_received"
"""Emitted: Device status message received.
Args:
event (StatusReceivedEvent): Event object with the status field.
See: :class:`StatusReceivedEvent`
"""
TEMPERATURE_CHANGED = "temperature_changed"
"""Emitted: DHW temperature changed.
Args:
event (TemperatureChangedEvent): Event object with old_temperature
and new_temperature fields.
See: :class:`TemperatureChangedEvent`
"""
MODE_CHANGED = "mode_changed"
"""Emitted: Device operation mode changed.
Args:
event (ModeChangedEvent): Event object with old_mode and new_mode
fields.
See: :class:`ModeChangedEvent`
"""
POWER_CHANGED = "power_changed"
"""Emitted: Instantaneous power consumption changed.
Args:
event (PowerChangedEvent): Event object with old_power and new_power
fields.
See: :class:`PowerChangedEvent`
"""
# Heating events
HEATING_STARTED = "heating_started"
"""Emitted: Device started heating.
Args:
event (HeatingStartedEvent): Event object with the status field.
See: :class:`HeatingStartedEvent`
"""
HEATING_STOPPED = "heating_stopped"
"""Emitted: Device stopped heating.
Args:
event (HeatingStoppedEvent): Event object with the status field.
See: :class:`HeatingStoppedEvent`
"""
# Error events
ERROR_DETECTED = "error_detected"
"""Emitted: Device error detected.
Args:
event (ErrorDetectedEvent): Event object with error_code and status
fields.
See: :class:`ErrorDetectedEvent`
"""
ERROR_CLEARED = "error_cleared"
"""Emitted: Device error cleared.
Args:
event (ErrorClearedEvent): Event object with the error_code field.
See: :class:`ErrorClearedEvent`
"""
# Feature events
FEATURE_RECEIVED = "feature_received"
"""Emitted: Device feature information received.
Args:
event (FeatureReceivedEvent): Event object with the feature field.
See: :class:`FeatureReceivedEvent`
"""
[docs]
@classmethod
def get_all_events(cls) -> list[str]:
"""Get list of all available event names.
Returns:
List of event constant names (not including metadata strings)
Example::
for event_name in MqttClientEvents.get_all_events():
print(f"- {event_name}")
# Output:
# - CONNECTION_INTERRUPTED
# - CONNECTION_RESUMED
# - STATUS_RECEIVED
# - TEMPERATURE_CHANGED
# - ...
"""
return [
attr
for attr in dir(cls)
if not attr.startswith("_")
and attr.isupper()
and isinstance(getattr(cls, attr), str)
]
[docs]
@classmethod
def get_event_value(cls, event_name: str) -> str:
"""Get the string value of an event constant.
Args:
event_name: Event constant name (e.g., "TEMPERATURE_CHANGED")
Returns:
Event string value (e.g., "temperature_changed")
Raises:
AttributeError: If event_name does not exist
Example::
value = MqttClientEvents.get_event_value("TEMPERATURE_CHANGED")
print(value) # Output: "temperature_changed"
"""
return cast(str, getattr(cls, event_name))