|
| 1 | +"""Plugwise models.""" |
| 2 | + |
| 3 | +from typing import Any |
| 4 | + |
| 5 | +from pydantic import BaseModel, ConfigDict, Field |
| 6 | + |
| 7 | + |
| 8 | +class PWBase(BaseModel): |
| 9 | + """Base / common Plugwise class.""" |
| 10 | + |
| 11 | + # Allow additional struct (ignored) |
| 12 | + model_config = ConfigDict(extra="ignore") |
| 13 | + |
| 14 | + |
| 15 | +class WithID(PWBase): |
| 16 | + """Class for Plugwise ID base XML elements. |
| 17 | +
|
| 18 | + Takes id from the xml definition. |
| 19 | + """ |
| 20 | + |
| 21 | + id: str = Field(alias="@id") |
| 22 | + model_config = ConfigDict(extra="allow") |
| 23 | + |
| 24 | + |
| 25 | +# Period and measurements |
| 26 | +class Measurement(PWBase): |
| 27 | + """Plugwise Measurement.""" |
| 28 | + |
| 29 | + log_date: str = Field(alias="@log_date") |
| 30 | + value: str = Field(alias="#text") |
| 31 | + |
| 32 | + |
| 33 | +class Period(PWBase): |
| 34 | + """Plugwise period of time.""" |
| 35 | + |
| 36 | + start_date: str = Field(alias="@start_date") |
| 37 | + end_date: str = Field(alias="@end_date") |
| 38 | + interval: str | None = Field(default=None, alias="@interval") |
| 39 | + measurement: Measurement | None = None |
| 40 | + |
| 41 | + |
| 42 | +# Notification |
| 43 | +class Notification(WithID): |
| 44 | + """Plugwise notification. |
| 45 | +
|
| 46 | + Our examples only show single optional notification being present |
| 47 | + """ |
| 48 | + |
| 49 | + type: str |
| 50 | + origin: str | None = None |
| 51 | + title: str | None = None |
| 52 | + message: str | None = None |
| 53 | + |
| 54 | + created_date: str |
| 55 | + modified_date: str | list[str] | None = None |
| 56 | + deleted_date: str | None = None |
| 57 | + |
| 58 | + valid_from: str | list[str] | None = None |
| 59 | + valid_to: str | list[str] | None = None |
| 60 | + read_date: str | list[str] | None = None |
| 61 | + |
| 62 | + |
| 63 | +# Logging |
| 64 | +class BaseLog(WithID): |
| 65 | + """Plugwise mapping for point_log and interval_log constructs.""" |
| 66 | + |
| 67 | + type: str |
| 68 | + unit: str | None = None |
| 69 | + updated_date: str | None = None |
| 70 | + last_consecutive_log_date: str | None = None |
| 71 | + interval: str | None = None |
| 72 | + period: Period | None = None |
| 73 | + |
| 74 | + |
| 75 | +class PointLog(BaseLog): |
| 76 | + """Plugwise class ofr specific point_logs. |
| 77 | +
|
| 78 | + i.e. <relay id="..."/> |
| 79 | + """ |
| 80 | + |
| 81 | + relay: WithID | None = None |
| 82 | + thermo_meter: WithID | None = None |
| 83 | + thermostat: WithID | None = None |
| 84 | + battery_meter: WithID | None = None |
| 85 | + temperature_offset: WithID | None = None |
| 86 | + weather_descriptor: WithID | None = None |
| 87 | + irradiance_meter: WithID | None = None |
| 88 | + wind_vector: WithID | None = None |
| 89 | + hygro_meter: WithID | None = None |
| 90 | + |
| 91 | + |
| 92 | +class IntervalLog(BaseLog): |
| 93 | + """Plugwise class ofr specific interval_logs.""" |
| 94 | + |
| 95 | + electricity_interval_meter: WithID | None = ( |
| 96 | + None # references only, still to type if we need this |
| 97 | + ) |
| 98 | + |
| 99 | + |
| 100 | +# Functionality |
| 101 | +class BaseFunctionality(WithID): |
| 102 | + """Plugwise functionality.""" |
| 103 | + |
| 104 | + updated_date: str | None = None |
| 105 | + |
| 106 | + |
| 107 | +class RelayFunctionality(BaseFunctionality): |
| 108 | + """Relay functionality.""" |
| 109 | + |
| 110 | + lock: bool | None = None |
| 111 | + state: str | None = None |
| 112 | + relay: WithID | None = None |
| 113 | + |
| 114 | + |
| 115 | +class ThermostatFunctionality(BaseFunctionality): |
| 116 | + """Thermostat functionality.""" |
| 117 | + |
| 118 | + type: str |
| 119 | + lower_bound: float |
| 120 | + upper_bound: float |
| 121 | + resolution: float |
| 122 | + setpoint: float |
| 123 | + thermostat: WithID | None = None |
| 124 | + |
| 125 | + |
| 126 | +class OffsetFunctionality(BaseFunctionality): |
| 127 | + """Offset functionality.""" |
| 128 | + |
| 129 | + type: str |
| 130 | + offset: float |
| 131 | + temperature_offset: WithID | None = None |
| 132 | + |
| 133 | + |
| 134 | +# Services |
| 135 | +class ServiceBase(WithID): |
| 136 | + """Plugwise Services.""" |
| 137 | + |
| 138 | + log_type: str | None = Field(default=None, alias="@log_type") |
| 139 | + endpoint: str | None = Field(default=None, alias="@endpoint") |
| 140 | + functionalities: dict[str, WithID | list[WithID]] | None = ( |
| 141 | + None # references only, still to type if we need this |
| 142 | + ) |
| 143 | + |
| 144 | + |
| 145 | +# Protocols |
| 146 | +class Neighbor(PWBase): |
| 147 | + """Neighbor definition.""" |
| 148 | + |
| 149 | + mac_address: str = Field(alias="@mac_address") |
| 150 | + lqi: int | None = None |
| 151 | + depth: int | None = None |
| 152 | + relationship: str | None = None |
| 153 | + |
| 154 | + |
| 155 | +class ZigBeeNode(WithID): |
| 156 | + """ZigBee node definition.""" |
| 157 | + |
| 158 | + mac_address: str |
| 159 | + type: str |
| 160 | + reachable: bool |
| 161 | + power_source: str | None = None |
| 162 | + battery_type: str | None = None |
| 163 | + zig_bee_coordinator: WithID | None = None |
| 164 | + neighbors: list[Neighbor] |
| 165 | + last_neighbor_table_received: str | None = None |
| 166 | + neighbor_table_support: bool | None = None |
| 167 | + |
| 168 | + |
| 169 | +# Appliance |
| 170 | +class Appliance(WithID): |
| 171 | + """Plugwise Appliance.""" |
| 172 | + |
| 173 | + name: str |
| 174 | + description: str | None = None |
| 175 | + type: str |
| 176 | + created_date: str |
| 177 | + modified_date: str | list[str] | None = None |
| 178 | + deleted_date: str | None = None |
| 179 | + |
| 180 | + location: dict[str, Any] | None = None |
| 181 | + groups: dict[str, WithID | list[WithID]] | None = None |
| 182 | + logs: dict[str, BaseLog | list[BaseLog]] | None = None |
| 183 | + actuator_functionalities: ( |
| 184 | + dict[str, BaseFunctionality | list[BaseFunctionality]] | None |
| 185 | + ) = None |
| 186 | + |
| 187 | + |
| 188 | +# Module |
| 189 | +class Module(WithID): |
| 190 | + """Plugwise Module.""" |
| 191 | + |
| 192 | + vendor_name: str | None = None |
| 193 | + vendor_model: str | None = None |
| 194 | + hardware_version: str | None = None |
| 195 | + firmware_version: str | None = None |
| 196 | + created_date: str |
| 197 | + modified_date: str | list[str] | None = None |
| 198 | + deleted_date: str | None = None |
| 199 | + |
| 200 | + # This is too much :) shorted to Any, but we should still look at this |
| 201 | + # services: dict[str, ServiceBase | list[ServiceBase]] | list[dict[str, Any]] | None = None |
| 202 | + services: dict[str, Any] | list[Any] | None = None |
| 203 | + |
| 204 | + protocols: dict[str, Any] | None = None # ZigBeeNode, WLAN, LAN |
| 205 | + |
| 206 | + |
| 207 | +# Location |
| 208 | +class Location(WithID): |
| 209 | + """Plugwise Location.""" |
| 210 | + |
| 211 | + name: str |
| 212 | + description: str | None = None |
| 213 | + type: str |
| 214 | + created_date: str |
| 215 | + modified_date: str | list[str] | None = None |
| 216 | + deleted_date: str | None = None |
| 217 | + preset: str | None = None |
| 218 | + appliances: list[WithID] |
| 219 | + logs: dict[str, BaseLog | list[BaseLog]] | list[BaseLog] | None |
| 220 | + appliances: dict[str, WithID | list[WithID]] | None = None |
| 221 | + actuator_functionalities: dict[str, BaseFunctionality] | None = None |
| 222 | + |
| 223 | + |
| 224 | +# Root objects |
| 225 | +class DomainObjects(PWBase): |
| 226 | + """Plugwise Domain Objects.""" |
| 227 | + |
| 228 | + appliance: list[Appliance] = [] |
| 229 | + module: list[Module] = [] |
| 230 | + location: list[Location] = [] |
| 231 | + notification: Notification | list[Notification] | None = None |
| 232 | + rule: list[dict] = [] |
| 233 | + template: list[dict] = [] |
| 234 | + |
| 235 | + |
| 236 | +class Root(PWBase): |
| 237 | + """Main XML definition.""" |
| 238 | + |
| 239 | + domain_objects: DomainObjects |
0 commit comments