|
1 | 1 | """Plugwise Stick and Smile constants.""" |
2 | 2 | from __future__ import annotations |
3 | 3 |
|
| 4 | +from collections import namedtuple |
4 | 5 | import datetime as dt |
5 | 6 | import logging |
6 | 7 | from typing import Final, TypedDict |
|
363 | 364 |
|
364 | 365 | ### Smile constants ### |
365 | 366 |
|
366 | | -ACTUATOR_CLASSES: Final[list[str]] = [ |
| 367 | +ACTUATOR_CLASSES: Final[tuple[str, ...]] = ( |
367 | 368 | "heater_central", |
368 | 369 | "thermostat", |
369 | 370 | "thermostatic_radiator_valve", |
370 | 371 | "zone_thermometer", |
371 | 372 | "zone_thermostat", |
372 | | -] |
373 | | -ACTIVE_ACTUATORS: Final[list[str]] = [ |
| 373 | +) |
| 374 | +ACTIVE_ACTUATORS: Final[tuple[str, ...]] = ( |
374 | 375 | "domestic_hot_water_setpoint", |
375 | 376 | "maximum_boiler_temperature", |
376 | 377 | "thermostat", |
377 | | -] |
378 | | -ATTR_ENABLED: Final = "enabled_default" |
379 | | -ATTR_ID: Final = "id" |
380 | | -ATTR_ICON: Final = "icon" |
381 | | -ATTR_TYPE: Final = "type" |
| 378 | +) |
382 | 379 | DAYS: Final[dict[str, int]] = { |
383 | 380 | "mo": 0, |
384 | 381 | "tu": 1, |
|
393 | 390 | DEFAULT_PORT: Final = 80 |
394 | 391 | NONE: Final = "None" |
395 | 392 | FAKE_LOC: Final = "0000aaaa0000aaaa0000aaaa0000aa00" |
396 | | -LIMITS: Final[list[str]] = ["setpoint", "lower_bound", "upper_bound", "resolution"] |
| 393 | +LIMITS: Final[tuple[str, ...]] = ( |
| 394 | + "setpoint", |
| 395 | + "lower_bound", |
| 396 | + "upper_bound", |
| 397 | + "resolution", |
| 398 | +) |
397 | 399 | MAX_SETPOINT: Final[float] = 40.0 |
398 | 400 | MIN_SETPOINT: Final[float] = 0.0 |
399 | | -SEVERITIES: Final[list[str]] = ["other", "info", "warning", "error"] |
400 | | -SPECIAL_FORMAT: Final[list[str]] = [ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS] |
401 | | -SWITCH_GROUP_TYPES: Final[list[str]] = ["switching", "report"] |
402 | | -ZONE_THERMOSTATS: Final[list[str]] = [ |
| 401 | +SPECIAL_FORMAT: Final[tuple[str, ...]] = (ENERGY_KILO_WATT_HOUR, VOLUME_CUBIC_METERS) |
| 402 | +SWITCH_GROUP_TYPES: Final[tuple[str, ...]] = ("switching", "report") |
| 403 | +ZONE_THERMOSTATS: Final[tuple[str, ...]] = ( |
403 | 404 | "thermostat", |
404 | 405 | "thermostatic_radiator_valve", |
405 | 406 | "zone_thermometer", |
406 | 407 | "zone_thermostat", |
407 | | -] |
408 | | -THERMOSTAT_CLASSES: Final[list[str]] = [ |
| 408 | +) |
| 409 | +THERMOSTAT_CLASSES: Final[tuple[str, ...]] = ( |
409 | 410 | "thermostat", |
410 | 411 | "thermo_sensor", |
411 | 412 | "zone_thermometer", |
412 | 413 | "zone_thermostat", |
413 | 414 | "thermostatic_radiator_valve", |
414 | | -] |
415 | | -SPECIAL_PLUG_TYPES: Final[list[str]] = [ |
| 415 | +) |
| 416 | +SPECIAL_PLUG_TYPES: Final[tuple[str, ...]] = ( |
416 | 417 | "central_heating_pump", |
417 | 418 | "valve_actuator", |
418 | 419 | "heater_electric", |
419 | | -] |
| 420 | +) |
420 | 421 |
|
421 | 422 | # XML data paths |
422 | 423 | APPLIANCES: Final = "/core/appliances" |
|
428 | 429 | SYSTEM: Final = "/system" |
429 | 430 | STATUS: Final = "/system/status.xml" |
430 | 431 |
|
| 432 | +UOM = namedtuple("UOM", "unit_of_measurement") |
| 433 | +DATA = namedtuple("DATA", "name unit_of_measurement") |
431 | 434 | # P1 related measurements: |
432 | | -HOME_MEASUREMENTS: Final[dict[str, dict[str, str]]] = { |
433 | | - "electricity_consumed": { |
434 | | - ATTR_UNIT_OF_MEASUREMENT: POWER_WATT, |
435 | | - }, |
436 | | - "electricity_produced": { |
437 | | - ATTR_UNIT_OF_MEASUREMENT: POWER_WATT, |
438 | | - }, |
439 | | - "gas_consumed": { |
440 | | - ATTR_UNIT_OF_MEASUREMENT: VOLUME_CUBIC_METERS, |
441 | | - }, |
| 435 | +P1_MEASUREMENTS: Final[dict[str, UOM]] = { |
| 436 | + "electricity_consumed": UOM(POWER_WATT), |
| 437 | + "electricity_produced": UOM(POWER_WATT), |
| 438 | + "gas_consumed": UOM(VOLUME_CUBIC_METERS), |
442 | 439 | } |
443 | | - |
444 | 440 | # Thermostat and Plug/Stretch related measurements |
445 | 441 | # Excluded: |
446 | 442 | # zone_thermosstat: 'temperature_offset' |
447 | 443 | # radiator_valve: 'uncorrected_temperature', 'temperature_offset' |
448 | | -DEVICE_MEASUREMENTS: Final[dict[str, dict[str, str]]] = { |
| 444 | + |
| 445 | +DEVICE_MEASUREMENTS: Final[dict[str, DATA | UOM]] = { |
449 | 446 | # HA Core thermostat current_temperature |
450 | | - "temperature": {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, |
| 447 | + "temperature": UOM(TEMP_CELSIUS), |
451 | 448 | # HA Core thermostat setpoint |
452 | | - "thermostat": {ATTR_NAME: "setpoint", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, |
| 449 | + "thermostat": DATA("setpoint", TEMP_CELSIUS), |
453 | 450 | # Specific for an Anna |
454 | | - "illuminance": {ATTR_UNIT_OF_MEASUREMENT: UNIT_LUMEN}, |
| 451 | + "illuminance": UOM(UNIT_LUMEN), |
455 | 452 | # Specific for an Anna with heatpump extension installed |
456 | | - "cooling_activation_outdoor_temperature": {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, |
457 | | - "cooling_deactivation_threshold": {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, |
| 453 | + "cooling_activation_outdoor_temperature": UOM(TEMP_CELSIUS), |
| 454 | + "cooling_deactivation_threshold": UOM(TEMP_CELSIUS), |
458 | 455 | # Specific for a Lisa a Tom/Floor |
459 | | - "battery": {ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE}, |
460 | | - "temperature_difference": {ATTR_UNIT_OF_MEASUREMENT: DEGREE}, |
461 | | - "valve_position": {ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE}, |
| 456 | + "battery": UOM(PERCENTAGE), |
| 457 | + "temperature_difference": UOM(DEGREE), |
| 458 | + "valve_position": UOM(PERCENTAGE), |
462 | 459 | # Specific for a Jip |
463 | | - "humidity": {ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE}, |
| 460 | + "humidity": UOM(PERCENTAGE), |
464 | 461 | # Specific for a Plug |
465 | | - "electricity_consumed": {ATTR_UNIT_OF_MEASUREMENT: POWER_WATT}, |
466 | | - "electricity_produced": {ATTR_UNIT_OF_MEASUREMENT: POWER_WATT}, |
467 | | - "relay": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
468 | | - "regulation_mode": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
| 462 | + "electricity_consumed": UOM(POWER_WATT), |
| 463 | + "electricity_produced": UOM(POWER_WATT), |
| 464 | + "relay": UOM(NONE), |
| 465 | + "regulation_mode": UOM(NONE), |
469 | 466 | } |
470 | 467 |
|
471 | 468 | # Heater Central related measurements |
472 | | -HEATER_CENTRAL_MEASUREMENTS: Final[dict[str, dict[str, str]]] = { |
473 | | - "boiler_temperature": { |
474 | | - ATTR_NAME: "water_temperature", |
475 | | - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, |
476 | | - }, |
477 | | - "domestic_hot_water_comfort_mode": { |
478 | | - ATTR_NAME: "dhw_cm_switch", |
479 | | - ATTR_UNIT_OF_MEASUREMENT: NONE, |
480 | | - }, |
481 | | - "domestic_hot_water_state": { |
482 | | - ATTR_NAME: "dhw_state", |
483 | | - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, |
484 | | - }, |
485 | | - "elga_status_code": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
486 | | - "intended_boiler_temperature": { |
487 | | - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS |
488 | | - }, # Non-zero when heating, zero when dhw-heating |
489 | | - "central_heating_state": { |
490 | | - ATTR_NAME: "c_heating_state", |
491 | | - ATTR_UNIT_OF_MEASUREMENT: NONE, |
492 | | - }, # For Elga (heatpump) use this instead of intended_central_heating_state |
493 | | - "intended_central_heating_state": { |
494 | | - ATTR_NAME: "heating_state", |
495 | | - ATTR_UNIT_OF_MEASUREMENT: NONE, |
496 | | - }, # This key shows in general the heating-behavior better than c-h_state. except when connected to a heatpump |
497 | | - "maximum_boiler_temperature": {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, |
498 | | - "modulation_level": {ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE}, |
499 | | - "return_water_temperature": { |
500 | | - ATTR_NAME: "return_temperature", |
501 | | - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, |
502 | | - }, |
| 469 | +HEATER_CENTRAL_MEASUREMENTS: Final[dict[str, DATA | UOM]] = { |
| 470 | + "boiler_temperature": DATA("water_temperature", TEMP_CELSIUS), |
| 471 | + "domestic_hot_water_comfort_mode": DATA("dhw_cm_switch", NONE), |
| 472 | + "domestic_hot_water_state": DATA("dhw_state", TEMP_CELSIUS), |
| 473 | + "elga_status_code": UOM(NONE), |
| 474 | + "intended_boiler_temperature": UOM( |
| 475 | + TEMP_CELSIUS |
| 476 | + ), # Non-zero when heating, zero when dhw-heating |
| 477 | + "central_heating_state": DATA( |
| 478 | + "c_heating_state", NONE |
| 479 | + ), # For Elga (heatpump) use this instead of intended_central_heating_state |
| 480 | + "intended_central_heating_state": DATA( |
| 481 | + "heating_state", NONE |
| 482 | + ), # This key shows in general the heating-behavior better than c-h_state. except when connected to a heatpump |
| 483 | + "maximum_boiler_temperature": UOM(TEMP_CELSIUS), |
| 484 | + "modulation_level": UOM(PERCENTAGE), |
| 485 | + "return_water_temperature": DATA("return_temperature", TEMP_CELSIUS), |
503 | 486 | # Used with the Elga heatpump - marcelveldt |
504 | | - "compressor_state": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
505 | | - "cooling_state": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
| 487 | + "compressor_state": UOM(NONE), |
| 488 | + "cooling_state": UOM(NONE), |
506 | 489 | # Next 2 keys are used to show the state of the gas-heater used next to the Elga heatpump - marcelveldt |
507 | | - "slave_boiler_state": {ATTR_UNIT_OF_MEASUREMENT: NONE}, |
508 | | - "flame_state": { |
509 | | - ATTR_UNIT_OF_MEASUREMENT: NONE |
510 | | - }, # Also present when there is a single gas-heater |
511 | | - "central_heater_water_pressure": { |
512 | | - ATTR_NAME: "water_pressure", |
513 | | - ATTR_UNIT_OF_MEASUREMENT: PRESSURE_BAR, |
514 | | - }, |
| 490 | + "slave_boiler_state": UOM(NONE), |
| 491 | + "flame_state": UOM(NONE), # Also present when there is a single gas-heater |
| 492 | + "central_heater_water_pressure": DATA("water_pressure", PRESSURE_BAR), |
515 | 493 | # Legacy Anna: similar to flame-state on Anna/Adam |
516 | | - "boiler_state": {ATTR_NAME: "flame_state", ATTR_UNIT_OF_MEASUREMENT: NONE}, |
| 494 | + "boiler_state": DATA("flame_state", NONE), |
517 | 495 | # Legacy Anna: shows when heating is active, we don't show dhw_state, cannot be determined reliably |
518 | | - "intended_boiler_state": { |
519 | | - ATTR_NAME: "heating_state", |
520 | | - ATTR_UNIT_OF_MEASUREMENT: NONE, |
521 | | - }, |
| 496 | + "intended_boiler_state": DATA("heating_state", NONE), |
522 | 497 | # Outdoor temperature from APPLIANCES - present for a heatpump |
523 | | - "outdoor_temperature": { |
524 | | - ATTR_NAME: "outdoor_air_temperature", |
525 | | - ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, |
526 | | - }, |
| 498 | + "outdoor_temperature": DATA("outdoor_air_temperature", TEMP_CELSIUS), |
527 | 499 | } |
528 | 500 |
|
529 | 501 | # Known types of Smiles and Stretches |
530 | | -SMILES: Final[dict[str, dict[str, str]]] = { |
531 | | - "smile_v2": {"type": "power", "name": "P1"}, |
532 | | - "smile_v3": {"type": "power", "name": "P1"}, |
533 | | - "smile_v4": {"type": "power", "name": "P1"}, |
534 | | - "smile_open_therm_v2": {"type": "thermostat", "name": "Adam"}, |
535 | | - "smile_open_therm_v3": {"type": "thermostat", "name": "Adam"}, |
536 | | - "smile_thermo_v1": {"type": "thermostat", "name": "Smile"}, |
537 | | - "smile_thermo_v3": {"type": "thermostat", "name": "Smile"}, |
538 | | - "smile_thermo_v4": {"type": "thermostat", "name": "Smile"}, |
539 | | - "stretch_v2": {"type": "stretch", "name": "Stretch"}, |
540 | | - "stretch_v3": {"type": "stretch", "name": "Stretch"}, |
| 502 | +SMILE = namedtuple("SMILE", "smile_type smile_name") |
| 503 | +SMILES: Final[dict[str, SMILE]] = { |
| 504 | + "smile_v2": SMILE("power", "P1"), |
| 505 | + "smile_v3": SMILE("power", "P1"), |
| 506 | + "smile_v4": SMILE("power", "P1"), |
| 507 | + "smile_open_therm_v2": SMILE("thermostat", "Adam"), |
| 508 | + "smile_open_therm_v3": SMILE("thermostat", "Adam"), |
| 509 | + "smile_thermo_v1": SMILE("thermostat", "Smile"), |
| 510 | + "smile_thermo_v3": SMILE("thermostat", "Smile"), |
| 511 | + "smile_thermo_v4": SMILE("thermostat", "Smile"), |
| 512 | + "stretch_v2": SMILE("stretch", "Stretch"), |
| 513 | + "stretch_v3": SMILE("stretch", "Stretch"), |
541 | 514 | } |
542 | 515 |
|
543 | 516 | # All available Binary Sensor, Sensor, and Switch Types |
544 | 517 |
|
545 | | -BINARY_SENSORS: Final[list[str]] = [ |
| 518 | +BINARY_SENSORS: Final[tuple[str, ...]] = ( |
546 | 519 | "compressor_state", |
547 | 520 | "cooling_state", |
548 | 521 | "dhw_state", |
549 | 522 | "flame_state", |
550 | 523 | "heating_state", |
551 | 524 | "plugwise_notification", |
552 | 525 | "slave_boiler_state", |
553 | | -] |
| 526 | +) |
554 | 527 |
|
555 | | -SENSORS: Final[list[str]] = [ |
| 528 | +SENSORS: Final[tuple[str, ...]] = ( |
556 | 529 | "battery", |
557 | 530 | "cooling_activation_outdoor_temperature", |
558 | 531 | "cooling_deactivation_threshold", |
|
593 | 566 | "valve_position", |
594 | 567 | "water_pressure", |
595 | 568 | "water_temperature", |
596 | | -] |
| 569 | +) |
597 | 570 |
|
598 | | -SWITCHES: Final[list[str]] = [ |
| 571 | +SWITCHES: Final[tuple[str, ...]] = ( |
599 | 572 | "dhw_cm_switch", |
600 | 573 | "lock", |
601 | 574 | "relay", |
602 | | -] |
| 575 | +) |
603 | 576 |
|
604 | 577 |
|
605 | 578 | class ApplianceData(TypedDict, total=False): |
|
0 commit comments