1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
"""Provide a model for the Z-Wave JS controller's statistics."""
from __future__ import annotations
from contextlib import suppress
from dataclasses import dataclass, field
from typing import TYPE_CHECKING, TypedDict
from ..statistics import RouteStatistics, RouteStatisticsDataType
if TYPE_CHECKING:
from ...client import Client
class ControllerLifelineRoutesDataType(TypedDict):
"""Represent a controller lifeline routes data dict type."""
lwr: RouteStatisticsDataType
nlwr: RouteStatisticsDataType
@dataclass
class ControllerLifelineRoutes:
"""Represent controller lifeline routes."""
client: Client = field(repr=False)
data: ControllerLifelineRoutesDataType = field(repr=False)
lwr: RouteStatistics | None = field(init=False, default=None)
nlwr: RouteStatistics | None = field(init=False, default=None)
def __post_init__(self) -> None:
"""Post initialize."""
if lwr := self.data.get("lwr"):
with suppress(ValueError):
self.lwr = RouteStatistics(self.client, lwr)
if nlwr := self.data.get("nlwr"):
with suppress(ValueError):
self.nlwr = RouteStatistics(self.client, nlwr)
class ChannelRSSIDataType(TypedDict):
"""Represent a channel RSSI data dict type."""
average: int
current: int
class BackgroundRSSIDataType(TypedDict, total=False):
"""Represent a background RSSI data dict type."""
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/ControllerStatistics.ts#L40
timestamp: int # required
channel0: ChannelRSSIDataType # required
channel1: ChannelRSSIDataType # required
channel2: ChannelRSSIDataType
channel3: ChannelRSSIDataType
class ControllerStatisticsDataType(TypedDict, total=False):
"""Represent a controller statistics data dict type."""
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/ControllerStatistics.ts#L20-L39
messagesTX: int # required
messagesRX: int # required
messagesDroppedTX: int # required
messagesDroppedRX: int # required
NAK: int # required
CAN: int # required
timeoutACK: int # required
timeoutResponse: int # required
timeoutCallback: int # required
backgroundRSSI: BackgroundRSSIDataType
@dataclass
class ChannelRSSI:
"""Represent a channel RSSI."""
data: ChannelRSSIDataType = field(repr=False)
average: int = field(init=False)
current: int = field(init=False)
def __post_init__(self) -> None:
"""Post initialize."""
self.average = self.data["average"]
self.current = self.data["current"]
@dataclass
class BackgroundRSSI:
"""Represent a background RSSI update."""
data: BackgroundRSSIDataType = field(repr=False)
timestamp: int = field(init=False)
channel_0: ChannelRSSI = field(init=False)
channel_1: ChannelRSSI = field(init=False)
channel_2: ChannelRSSI | None = field(init=False)
channel_3: ChannelRSSI | None = field(init=False)
def __post_init__(self) -> None:
"""Post initialize."""
self.timestamp = self.data["timestamp"]
self.channel_0 = ChannelRSSI(self.data["channel0"])
self.channel_1 = ChannelRSSI(self.data["channel1"])
# Channels 2 and 3 may not be present, but 3 requires 2 to be present
self.channel_2 = None
self.channel_3 = None
if channel_2 := self.data.get("channel2"):
self.channel_2 = ChannelRSSI(channel_2)
if channel_3 := self.data.get("channel3"):
self.channel_3 = ChannelRSSI(channel_3)
@dataclass
class ControllerStatistics:
"""Represent a controller statistics update."""
data: ControllerStatisticsDataType = field(repr=False)
messages_tx: int = field(init=False)
messages_rx: int = field(init=False)
messages_dropped_rx: int = field(init=False)
messages_dropped_tx: int = field(init=False)
nak: int = field(init=False)
can: int = field(init=False)
timeout_ack: int = field(init=False)
timeout_response: int = field(init=False)
timeout_callback: int = field(init=False)
background_rssi: BackgroundRSSI | None = field(init=False, default=None)
def __post_init__(self) -> None:
"""Post initialize."""
self.messages_tx = self.data["messagesTX"]
self.messages_rx = self.data["messagesRX"]
self.messages_dropped_rx = self.data["messagesDroppedRX"]
self.messages_dropped_tx = self.data["messagesDroppedTX"]
self.nak = self.data["NAK"]
self.can = self.data["CAN"]
self.timeout_ack = self.data["timeoutACK"]
self.timeout_response = self.data["timeoutResponse"]
self.timeout_callback = self.data["timeoutCallback"]
if background_rssi := self.data.get("backgroundRSSI"):
self.background_rssi = BackgroundRSSI(background_rssi)
|