|
2 | 2 | from typing import Any, Optional |
3 | 3 | from typing_extensions import Self |
4 | 4 | from dateutil.parser import parse |
| 5 | +from dateutil import tz |
5 | 6 |
|
6 | 7 |
|
7 | 8 | class VueDevice(object): |
8 | 9 | def __init__(self, gid=0, manId="", modelNum="", firmwareVersion=""): |
| 10 | + self.device_id = "" |
9 | 11 | self.device_gid: int = gid |
10 | 12 | self.manufacturer_id = manId |
11 | 13 | self.model = modelNum |
@@ -42,6 +44,7 @@ def __init__(self, gid=0, manId="", modelNum="", firmwareVersion=""): |
42 | 44 |
|
43 | 45 | def from_json_dictionary(self, js: "dict[str, Any]") -> Self: |
44 | 46 | """Populate device data from a dictionary extracted from the response json.""" |
| 47 | + self.device_id = js.get("device_id", "") |
45 | 48 | if "deviceGid" in js: |
46 | 49 | self.device_gid = js["deviceGid"] |
47 | 50 | if "manufacturerDeviceId" in js: |
@@ -247,92 +250,208 @@ def from_json_dictionary(self, js: "dict[str, Any]") -> Self: |
247 | 250 |
|
248 | 251 | class OutletDevice(object): |
249 | 252 | def __init__(self, gid: int = 0, on: bool = False): |
| 253 | + self.device_id = "" |
250 | 254 | self.device_gid = gid |
251 | 255 | self.outlet_on = on |
252 | 256 | self.load_gid: int = 0 |
253 | | - self.schedules = [] |
254 | 257 |
|
255 | 258 | def from_json_dictionary(self, js: "dict[str, Any]") -> Self: |
256 | | - if "deviceGid" in js: |
257 | | - self.device_gid = js["deviceGid"] |
258 | | - if "outletOn" in js: |
259 | | - self.outlet_on = js["outletOn"] |
260 | | - if "loadGid" in js: |
261 | | - self.load_gid = js["loadGid"] |
262 | | - # don't have support for schedules yet |
| 259 | + self.device_id = js.get("device_id", "") |
| 260 | + self.device_gid = js.get("device_gid", 0) |
| 261 | + self.load_gid = js.get("load_gid", 0) |
| 262 | + self.outlet_on = js.get("outlet_on", False) |
263 | 263 | return self |
264 | 264 |
|
265 | 265 | def as_dictionary(self) -> "dict[str, Any]": |
266 | 266 | return { |
267 | | - "deviceGid": self.device_gid, |
268 | | - "outletOn": self.outlet_on, |
269 | | - "loadGid": self.load_gid, |
| 267 | + "device_id": self.device_id, |
| 268 | + "device_gid": self.device_gid, |
| 269 | + "load_gid": self.load_gid, |
| 270 | + "outlet_on": self.outlet_on, |
270 | 271 | } |
271 | 272 |
|
| 273 | +class EvseStatus(object): |
| 274 | + """{ |
| 275 | + "device_id": "D2129A0700AC67B2FBBD9C", |
| 276 | + "device_gid": 62626, |
| 277 | + "load_gid": 42275, |
| 278 | + "charger_status": "DISCONNECTED_ON" |
| 279 | + }""" |
| 280 | + |
| 281 | + def __init__(self, id: str = "", gid: int = 0, load_gid: int = 0, status: str = ""): |
| 282 | + self.device_id = id |
| 283 | + self.device_gid = gid |
| 284 | + self.load_gid = load_gid |
| 285 | + self.charger_status = status |
| 286 | + |
| 287 | + def from_json_dictionary(self, js: "dict[str, Any]") -> Self: |
| 288 | + self.device_id = js.get("device_id", "") |
| 289 | + self.device_gid = js.get("device_gid", 0) |
| 290 | + self.load_gid = js.get("load_gid", 0) |
| 291 | + self.charger_status = js.get("charger_status", "") |
| 292 | + return self |
272 | 293 |
|
273 | 294 | class ChargerDevice(object): |
274 | | - def __init__(self, gid: int = 0, on: bool = False): |
| 295 | + """{ |
| 296 | + "device_id": "D2129A0700AC67B2FBBD9C", |
| 297 | + "category": "EVSE", |
| 298 | + "name": "EV", |
| 299 | + "device_description": null, |
| 300 | + "connected": true, |
| 301 | + "connected_changed_time": "2025-12-25T03:52:27.629Z", |
| 302 | + "time_zone": "America/New_York", |
| 303 | + "billing_cycle_start_day": 16, |
| 304 | + "firmware": "EVCharger-599", |
| 305 | + "latitude": 43.1910367, |
| 306 | + "longitude": -77.8089975, |
| 307 | + "excess_solar_configured": false, |
| 308 | + "peak_demand_configured": false, |
| 309 | + "energy_management_active": "NONE", |
| 310 | + "energy_managements_configured": [], |
| 311 | + "energy_managements_active": [], |
| 312 | + "evse_product": "C1", |
| 313 | + "evse_model": "Classic", |
| 314 | + "evse_branding": "EMPORIA", |
| 315 | + "evse_power_source": "NEMA", |
| 316 | + "evse_color": "WHITE", |
| 317 | + "evse_gun_type": "J1772", |
| 318 | + "breaker_pin": "1313", |
| 319 | + "charger_on": true, |
| 320 | + "charge_rate_amps": 24, |
| 321 | + "max_charge_rate_amps": 24, |
| 322 | + "power_smart_configuration": null, |
| 323 | + "vehicle_connected": false, |
| 324 | + "vehicle_charging": false, |
| 325 | + "partner_schedule_status": "INELIGIBLE" |
| 326 | + }""" |
| 327 | + |
| 328 | + def __init__(self, id: str = "", gid: int = 0, on: bool = False): |
| 329 | + self.device_id = id |
275 | 330 | self.device_gid = gid |
276 | 331 | self.charger_on = on |
277 | | - self.message = "" |
278 | | - self.status = "" |
279 | | - self.icon = "" |
280 | | - self.icon_label = "" |
281 | | - self.icon_detail_text = "" |
282 | | - self.fault_text = "" |
| 332 | + self.category = "" |
| 333 | + self.name = "" |
| 334 | + self.device_description = "" |
| 335 | + self.connected = False |
| 336 | + self.connected_changed_time: Optional[datetime.datetime] = None |
| 337 | + self.time_zone = datetime.timezone.utc |
| 338 | + self.time_zone_string = datetime.timezone.utc.tzname(None) |
| 339 | + self.billing_cycle_start_day = 0 |
| 340 | + self.firmware = "" |
| 341 | + self.latitude = 0.0 |
| 342 | + self.longitude = 0.0 |
| 343 | + self.excess_solar_configured = False |
| 344 | + self.peak_demand_configured = False |
| 345 | + self.energy_management_active = "NONE" |
| 346 | + self.energy_managements_configured: list[str] = [] |
| 347 | + self.energy_managements_active: list[str] = [] |
| 348 | + self.evse_product = "" |
| 349 | + self.evse_model = "" |
| 350 | + self.evse_branding = "" |
| 351 | + self.evse_power_source = "" |
| 352 | + self.evse_color = "" |
| 353 | + self.evse_gun_type = "" |
| 354 | + self.breaker_pin = "" |
283 | 355 | self.charging_rate = 0 |
284 | 356 | self.max_charging_rate = 0 |
285 | | - self.off_peak_schedules_enabled = False |
286 | | - self.custom_schedules = [] |
287 | | - self.load_gid: int = 0 |
288 | | - self.debug_code = "" |
289 | | - self.pro_control_code = "" |
290 | | - self.breaker_pin = "" |
| 357 | + self.power_smart_configuration: Optional[dict[str, Any]] = None |
| 358 | + self.vehicle_connected = False |
| 359 | + self.vehicle_charging = False |
| 360 | + self.partner_schedule_status = "" |
291 | 361 |
|
292 | 362 | def from_json_dictionary(self, js: "dict[str, Any]") -> Self: |
293 | | - if "deviceGid" in js: |
294 | | - self.device_gid = js["deviceGid"] |
295 | | - if "loadGid" in js: |
296 | | - self.load_gid = js["loadGid"] |
297 | | - if "chargerOn" in js: |
298 | | - self.charger_on = js["chargerOn"] |
299 | | - if "message" in js: |
300 | | - self.message = js["message"] |
301 | | - if "status" in js: |
302 | | - self.status = js["status"] |
303 | | - if "icon" in js: |
304 | | - self.icon = js["icon"] |
305 | | - if "iconLabel" in js: |
306 | | - self.icon_label = js["iconLabel"] |
307 | | - if "iconDetailText" in js: |
308 | | - self.icon_detail_text = js["iconDetailText"] |
309 | | - if "faultText" in js: |
310 | | - self.fault_text = js["faultText"] |
311 | | - if "chargingRate" in js: |
312 | | - self.charging_rate = js["chargingRate"] |
313 | | - if "maxChargingRate" in js: |
314 | | - self.max_charging_rate = js["maxChargingRate"] |
315 | | - if "offPeakSchedulesEnabled" in js: |
316 | | - self.off_peak_schedules_enabled = js["offPeakSchedulesEnabled"] |
317 | | - if "debugCode" in js: |
318 | | - self.debug_code = js["debugCode"] |
319 | | - if "proControlCode" in js: |
320 | | - self.pro_control_code = js["proControlCode"] |
321 | | - if "breakerPIN" in js: |
322 | | - self.breaker_pin = js["breakerPIN"] |
323 | | - # don't have support for schedules yet |
| 363 | + self.device_id = js.get("device_id", self.device_id) |
| 364 | + self.device_gid = js.get("device_gid", self.device_gid) |
| 365 | + self.category = js.get("category", self.category) |
| 366 | + self.name = js.get("name", self.name) |
| 367 | + self.device_description = js.get("device_description", self.device_description) |
| 368 | + self.connected = js.get("connected", self.connected) |
| 369 | + if "connected_changed_time" in js and js["connected_changed_time"]: |
| 370 | + try: |
| 371 | + self.connected_changed_time = parse(js["connected_changed_time"]) |
| 372 | + except: |
| 373 | + self.connected_changed_time = None |
| 374 | + timezone_string = js.get("time_zone", None) |
| 375 | + if timezone_string: # convert timezone string to a tzinfo object |
| 376 | + self.time_zone_string = timezone_string |
| 377 | + self.time_zone = tz.gettz(timezone_string) |
| 378 | + |
| 379 | + self.billing_cycle_start_day = js.get( |
| 380 | + "billing_cycle_start_day", self.billing_cycle_start_day |
| 381 | + ) |
| 382 | + self.firmware = js.get("firmware", self.firmware) |
| 383 | + self.latitude = js.get("latitude", self.latitude) |
| 384 | + self.longitude = js.get("longitude", self.longitude) |
| 385 | + self.excess_solar_configured = js.get( |
| 386 | + "excess_solar_configured", self.excess_solar_configured |
| 387 | + ) |
| 388 | + self.peak_demand_configured = js.get( |
| 389 | + "peak_demand_configured", self.peak_demand_configured |
| 390 | + ) |
| 391 | + self.energy_management_active = js.get( |
| 392 | + "energy_management_active", self.energy_management_active |
| 393 | + ) |
| 394 | + self.energy_managements_configured = js.get( |
| 395 | + "energy_managements_configured", self.energy_managements_configured |
| 396 | + ) |
| 397 | + self.energy_managements_active = js.get( |
| 398 | + "energy_managements_active", self.energy_managements_active |
| 399 | + ) |
| 400 | + self.evse_product = js.get("evse_product", self.evse_product) |
| 401 | + self.evse_model = js.get("evse_model", self.evse_model) |
| 402 | + self.evse_branding = js.get("evse_branding", self.evse_branding) |
| 403 | + self.evse_power_source = js.get("evse_power_source", self.evse_power_source) |
| 404 | + self.evse_color = js.get("evse_color", self.evse_color) |
| 405 | + self.evse_gun_type = js.get("evse_gun_type", self.evse_gun_type) |
| 406 | + self.breaker_pin = js.get("breaker_pin", self.breaker_pin) |
| 407 | + self.charger_on = js.get("charger_on", self.charger_on) |
| 408 | + self.charging_rate = js.get("charge_rate_amps", self.charging_rate) |
| 409 | + self.max_charging_rate = js.get("max_charge_rate_amps", self.max_charging_rate) |
| 410 | + self.power_smart_configuration = js.get( |
| 411 | + "power_smart_configuration", self.power_smart_configuration |
| 412 | + ) |
| 413 | + self.vehicle_connected = js.get("vehicle_connected", self.vehicle_connected) |
| 414 | + self.vehicle_charging = js.get("vehicle_charging", self.vehicle_charging) |
| 415 | + self.partner_schedule_status = js.get( |
| 416 | + "partner_schedule_status", self.partner_schedule_status |
| 417 | + ) |
324 | 418 | return self |
325 | 419 |
|
326 | 420 | def as_dictionary(self) -> "dict[str, Any]": |
327 | 421 | d = { |
328 | | - "deviceGid": self.device_gid, |
329 | | - "loadGid": self.load_gid, |
330 | | - "chargerOn": self.charger_on, |
331 | | - "chargingRate": self.charging_rate, |
332 | | - "maxChargingRate": self.max_charging_rate, |
| 422 | + "device_id": self.device_id, |
| 423 | + "device_gid": self.device_gid, |
| 424 | + "charger_on": self.charger_on, |
| 425 | + "category": self.category, |
| 426 | + "name": self.name, |
| 427 | + "device_description": self.device_description, |
| 428 | + "connected": self.connected, |
| 429 | + "connected_changed_time": self.connected_changed_time.isoformat() if self.connected_changed_time else None, |
| 430 | + "time_zone": self.time_zone_string, |
| 431 | + "billing_cycle_start_day": self.billing_cycle_start_day, |
| 432 | + "firmware": self.firmware, |
| 433 | + "latitude": self.latitude, |
| 434 | + "longitude": self.longitude, |
| 435 | + "excess_solar_configured": self.excess_solar_configured, |
| 436 | + "peak_demand_configured": self.peak_demand_configured, |
| 437 | + "energy_management_active": self.energy_management_active, |
| 438 | + "energy_managements_configured": self.energy_managements_configured, |
| 439 | + "energy_managements_active": self.energy_managements_active, |
| 440 | + "evse_product": self.evse_product, |
| 441 | + "evse_model": self.evse_model, |
| 442 | + "evse_branding": self.evse_branding, |
| 443 | + "evse_power_source": self.evse_power_source, |
| 444 | + "evse_color": self.evse_color, |
| 445 | + "evse_gun_type": self.evse_gun_type, |
| 446 | + "charging_rate_amps": self.charging_rate, |
| 447 | + "max_charge_rate_amps": self.max_charging_rate, |
| 448 | + "power_smart_configuration": self.power_smart_configuration, |
| 449 | + "vehicle_connected": self.vehicle_connected, |
| 450 | + "vehicle_charging": self.vehicle_charging, |
| 451 | + "partner_schedule_status": self.partner_schedule_status, |
333 | 452 | } |
334 | 453 | if self.breaker_pin: |
335 | | - d["breakerPIN"] = self.breaker_pin |
| 454 | + d["breaker_pin"] = self.breaker_pin |
336 | 455 | return d |
337 | 456 |
|
338 | 457 |
|
|
0 commit comments