zwave-js-server-python 0.28.0__py3-none-any.whl → 0.29.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zwave_js_server/const.py +283 -8
- zwave_js_server/exceptions.py +35 -1
- zwave_js_server/model/controller.py +100 -7
- zwave_js_server/model/log_config.py +3 -3
- zwave_js_server/model/node.py +21 -1
- zwave_js_server/util/command_class.py +49 -0
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/METADATA +1 -1
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/RECORD +12 -11
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/WHEEL +1 -1
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/LICENSE +0 -0
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/entry_points.txt +0 -0
- {zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/top_level.txt +0 -0
zwave_js_server/const.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Constants for the Z-Wave JS python library."""
|
|
2
2
|
from enum import Enum, IntEnum
|
|
3
|
-
from typing import Dict, List
|
|
3
|
+
from typing import Dict, List, Set, Type, Union
|
|
4
4
|
|
|
5
5
|
# minimal server schema version we can handle
|
|
6
|
-
MIN_SERVER_SCHEMA_VERSION =
|
|
6
|
+
MIN_SERVER_SCHEMA_VERSION = 8
|
|
7
7
|
# max server schema version we can handle (and our code is compatible with)
|
|
8
|
-
MAX_SERVER_SCHEMA_VERSION =
|
|
8
|
+
MAX_SERVER_SCHEMA_VERSION = 8
|
|
9
9
|
|
|
10
10
|
VALUE_UNKNOWN = "unknown"
|
|
11
11
|
|
|
@@ -90,7 +90,6 @@ class LogLevel(str, Enum):
|
|
|
90
90
|
class CommandClass(IntEnum):
|
|
91
91
|
"""Enum with all known CommandClasses."""
|
|
92
92
|
|
|
93
|
-
ALARM = 113
|
|
94
93
|
SENSOR_ALARM = 156
|
|
95
94
|
SILENCE_ALARM = 157
|
|
96
95
|
SWITCH_ALL = 39
|
|
@@ -265,6 +264,7 @@ THERMOSTAT_MODE_PROPERTY = "mode"
|
|
|
265
264
|
THERMOSTAT_SETPOINT_PROPERTY = "setpoint"
|
|
266
265
|
THERMOSTAT_OPERATING_STATE_PROPERTY = "state"
|
|
267
266
|
THERMOSTAT_CURRENT_TEMP_PROPERTY = "Air temperature"
|
|
267
|
+
THERMOSTAT_HUMIDITY_PROPERTY = "Humidity"
|
|
268
268
|
|
|
269
269
|
|
|
270
270
|
class ThermostatMode(IntEnum):
|
|
@@ -390,6 +390,14 @@ class BarrierState(IntEnum):
|
|
|
390
390
|
OPEN = 255
|
|
391
391
|
|
|
392
392
|
|
|
393
|
+
COVER_OPEN_PROPERTY = "Open"
|
|
394
|
+
COVER_UP_PROPERTY = "Up"
|
|
395
|
+
COVER_ON_PROPERTY = "On"
|
|
396
|
+
COVER_CLOSE_PROPERTY = "Close"
|
|
397
|
+
COVER_DOWN_PROPERTY = "Down"
|
|
398
|
+
COVER_OFF_PROPERTY = "Off"
|
|
399
|
+
|
|
400
|
+
|
|
393
401
|
class ColorComponent(IntEnum):
|
|
394
402
|
"""Enum with all (known/used) Color Switch CC colors."""
|
|
395
403
|
|
|
@@ -405,6 +413,23 @@ class ColorComponent(IntEnum):
|
|
|
405
413
|
INDEX = 8
|
|
406
414
|
|
|
407
415
|
|
|
416
|
+
# Keys for the Color Switch CC combined colors value
|
|
417
|
+
# https://github.com/zwave-js/node-zwave-js/pull/1782
|
|
418
|
+
COLOR_SWITCH_COMBINED_RED = "red"
|
|
419
|
+
COLOR_SWITCH_COMBINED_GREEN = "green"
|
|
420
|
+
COLOR_SWITCH_COMBINED_BLUE = "blue"
|
|
421
|
+
COLOR_SWITCH_COMBINED_AMBER = "amber"
|
|
422
|
+
COLOR_SWITCH_COMBINED_CYAN = "cyan"
|
|
423
|
+
COLOR_SWITCH_COMBINED_PURPLE = "purple"
|
|
424
|
+
COLOR_SWITCH_COMBINED_WARM_WHITE = "warmWhite"
|
|
425
|
+
COLOR_SWITCH_COMBINED_COLD_WHITE = "coldWhite"
|
|
426
|
+
|
|
427
|
+
CURRENT_COLOR_PROPERTY = "currentColor"
|
|
428
|
+
TARGET_COLOR_PROPERTY = "targetColor"
|
|
429
|
+
TARGET_STATE_PROPERTY = "targetState"
|
|
430
|
+
TARGET_VALUE_PROPERTY = "targetValue"
|
|
431
|
+
|
|
432
|
+
|
|
408
433
|
class ToneID(IntEnum):
|
|
409
434
|
"""Enum with all known Sound Switch CC tone IDs."""
|
|
410
435
|
|
|
@@ -414,13 +439,263 @@ class ToneID(IntEnum):
|
|
|
414
439
|
|
|
415
440
|
|
|
416
441
|
class NodeStatus(IntEnum):
|
|
417
|
-
"""Enum with all Node status values.
|
|
418
|
-
|
|
419
|
-
https://zwave-js.github.io/node-zwave-js/#/api/node?id=status
|
|
420
|
-
"""
|
|
442
|
+
"""Enum with all Node status values."""
|
|
421
443
|
|
|
444
|
+
# https://zwave-js.github.io/node-zwave-js/#/api/node?id=status
|
|
422
445
|
UNKNOWN = 0
|
|
423
446
|
ASLEEP = 1
|
|
424
447
|
AWAKE = 2
|
|
425
448
|
DEAD = 3
|
|
426
449
|
ALIVE = 4
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
CC_SPECIFIC_SCALE = "scale"
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
# Multilevel Sensor constants
|
|
456
|
+
CC_SPECIFIC_SENSOR_TYPE = "sensorType"
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
class MultilevelSensorType(IntEnum):
|
|
460
|
+
"""Enum with all known multilevel sensor types."""
|
|
461
|
+
|
|
462
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/config/config/sensorTypes.json
|
|
463
|
+
AIR_TEMPERATURE = 1
|
|
464
|
+
GENERAL_PURPOSE = 2
|
|
465
|
+
ILLUMINANCE = 3
|
|
466
|
+
POWER = 4
|
|
467
|
+
HUMIDITY = 5
|
|
468
|
+
VELOCITY = 6
|
|
469
|
+
DIRECTION = 7
|
|
470
|
+
ATMOSPHERIC_PRESSURE = 8
|
|
471
|
+
BAROMETRIC_PRESSURE = 9
|
|
472
|
+
SOLAR_RADIATION = 10
|
|
473
|
+
DEW_POINT = 11
|
|
474
|
+
RAIN_RATE = 12
|
|
475
|
+
TIDE_LEVEL = 13
|
|
476
|
+
WEIGHT = 14
|
|
477
|
+
VOLTAGE = 15
|
|
478
|
+
CURRENT = 16
|
|
479
|
+
CARBON_DIOXIDE_LEVEL = 17
|
|
480
|
+
AIR_FLOW = 18
|
|
481
|
+
TANK_CAPACITY = 19
|
|
482
|
+
DISTANCE = 20
|
|
483
|
+
ANGLE_POSITION = 21
|
|
484
|
+
ROTATION = 22
|
|
485
|
+
WATER_TEMPERATURE = 23
|
|
486
|
+
SOIL_TEMPERATURE = 24
|
|
487
|
+
SEISMIC_INTENSITY = 25
|
|
488
|
+
SEISMIC_MAGNITUDE = 26
|
|
489
|
+
ULTRAVIOLET = 27
|
|
490
|
+
ELECTRICAL_RESISTIVITY = 28
|
|
491
|
+
ELECTRICAL_CONDUCTIVITY = 29
|
|
492
|
+
LOUDNESS = 30
|
|
493
|
+
MOISTURE = 31
|
|
494
|
+
FREQUENCY = 32
|
|
495
|
+
TIME = 33
|
|
496
|
+
TARGET_TEMPERATURE = 34
|
|
497
|
+
PARTICULATE_MATTER_25 = 35
|
|
498
|
+
FORMALDEHYDE_LEVEL = 36
|
|
499
|
+
RADON_CONCENTRATION = 37
|
|
500
|
+
METHANE_DENSITY = 38
|
|
501
|
+
VOLATILE_ORGANIC_COMPOUND_LEVEL = 39
|
|
502
|
+
CARBON_MONOXIDE_LEVEL = 40
|
|
503
|
+
SOIL_HUMIDITY = 41
|
|
504
|
+
SOIL_REACTIVITY = 42
|
|
505
|
+
SOIL_SALINITY = 43
|
|
506
|
+
HEART_RATE = 44
|
|
507
|
+
BLOOD_PRESSURE = 45
|
|
508
|
+
MUSCLE_MASS = 46
|
|
509
|
+
FAT_MASS = 47
|
|
510
|
+
BONE_MASS = 48
|
|
511
|
+
TOTAL_BODY_WATER = 49
|
|
512
|
+
BASIS_METABOLIC_RATE = 50
|
|
513
|
+
BODY_MASS_INDEX = 51
|
|
514
|
+
ACCELERATION_X_AXIS = 52
|
|
515
|
+
ACCELERATION_Y_AXIS = 53
|
|
516
|
+
ACCELERATION_Z_AXIS = 54
|
|
517
|
+
SMOKE_DENSITY = 55
|
|
518
|
+
WATER_FLOW = 56
|
|
519
|
+
WATER_PRESSURE = 57
|
|
520
|
+
RF_SIGNAL_STRENGTH = 58
|
|
521
|
+
PARTICULATE_MATTER_10 = 59
|
|
522
|
+
RESPIRATORY_RATE = 60
|
|
523
|
+
RELATIVE_MODULATION_LEVEL = 61
|
|
524
|
+
BOILER_WATER_TEMPERATURE = 62
|
|
525
|
+
DOMESTIC_HOT_WATER_TEMPERATURE = 63
|
|
526
|
+
OUTSIDE_TEMPERATURE = 64
|
|
527
|
+
EXHAUST_TEMPERATURE = 65
|
|
528
|
+
WATER_CHLORINE_LEVEL = 66
|
|
529
|
+
WATER_ACIDITY = 67
|
|
530
|
+
WATER_OXIDATION_REDUCTION_POTENTIAL = 68
|
|
531
|
+
HEART_RATE_LF_HF_RATIO = 69
|
|
532
|
+
MOTION_DIRECTION = 70
|
|
533
|
+
APPLIED_FORCE_ON_THE_SENSOR = 71
|
|
534
|
+
RETURN_AIR_TEMPERATURE = 72
|
|
535
|
+
SUPPLY_AIR_TEMPERATURE = 73
|
|
536
|
+
CONDENSER_COIL_TEMPERATURE = 74
|
|
537
|
+
EVAPORATOR_COIL_TEMPERATURE = 75
|
|
538
|
+
LIQUID_LINE_TEMPERATURE = 76
|
|
539
|
+
DISCHARGE_LINE_TEMPERATURE = 77
|
|
540
|
+
SUCTION_PRESSURE = 78
|
|
541
|
+
DISCHARGE_PRESSURE = 79
|
|
542
|
+
DEFROST_TEMPERATURE = 80
|
|
543
|
+
OZONE = 81
|
|
544
|
+
SULFUR_DIOXIDE = 82
|
|
545
|
+
NITROGEN_DIOXIDE = 83
|
|
546
|
+
AMMONIA = 84
|
|
547
|
+
LEAD = 85
|
|
548
|
+
PARTICULATE_MATTER_1 = 86
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
CO_SENSORS = {MultilevelSensorType.CARBON_MONOXIDE_LEVEL}
|
|
552
|
+
CO2_SENSORS = {MultilevelSensorType.CARBON_DIOXIDE_LEVEL}
|
|
553
|
+
CURRENT_SENSORS = {MultilevelSensorType.CURRENT}
|
|
554
|
+
ENERGY_SENSORS = {MultilevelSensorType.BASIS_METABOLIC_RATE}
|
|
555
|
+
HUMIDITY_SENSORS = {MultilevelSensorType.HUMIDITY}
|
|
556
|
+
ILLUMINANCE_SENSORS = {MultilevelSensorType.ILLUMINANCE}
|
|
557
|
+
POWER_SENSORS = {MultilevelSensorType.POWER}
|
|
558
|
+
PRESSURE_SENSORS = {
|
|
559
|
+
MultilevelSensorType.BLOOD_PRESSURE,
|
|
560
|
+
MultilevelSensorType.WATER_PRESSURE,
|
|
561
|
+
MultilevelSensorType.SUCTION_PRESSURE,
|
|
562
|
+
MultilevelSensorType.DISCHARGE_PRESSURE,
|
|
563
|
+
MultilevelSensorType.BAROMETRIC_PRESSURE,
|
|
564
|
+
MultilevelSensorType.ATMOSPHERIC_PRESSURE,
|
|
565
|
+
}
|
|
566
|
+
SIGNAL_STRENGTH_SENSORS = {MultilevelSensorType.RF_SIGNAL_STRENGTH}
|
|
567
|
+
TEMPERATURE_SENSORS = {
|
|
568
|
+
MultilevelSensorType.AIR_TEMPERATURE,
|
|
569
|
+
MultilevelSensorType.DEW_POINT,
|
|
570
|
+
MultilevelSensorType.WATER_TEMPERATURE,
|
|
571
|
+
MultilevelSensorType.SOIL_TEMPERATURE,
|
|
572
|
+
MultilevelSensorType.TARGET_TEMPERATURE,
|
|
573
|
+
MultilevelSensorType.BOILER_WATER_TEMPERATURE,
|
|
574
|
+
MultilevelSensorType.DOMESTIC_HOT_WATER_TEMPERATURE,
|
|
575
|
+
MultilevelSensorType.OUTSIDE_TEMPERATURE,
|
|
576
|
+
MultilevelSensorType.EXHAUST_TEMPERATURE,
|
|
577
|
+
MultilevelSensorType.RETURN_AIR_TEMPERATURE,
|
|
578
|
+
MultilevelSensorType.SUPPLY_AIR_TEMPERATURE,
|
|
579
|
+
MultilevelSensorType.CONDENSER_COIL_TEMPERATURE,
|
|
580
|
+
MultilevelSensorType.EVAPORATOR_COIL_TEMPERATURE,
|
|
581
|
+
MultilevelSensorType.LIQUID_LINE_TEMPERATURE,
|
|
582
|
+
MultilevelSensorType.DISCHARGE_LINE_TEMPERATURE,
|
|
583
|
+
MultilevelSensorType.DEFROST_TEMPERATURE,
|
|
584
|
+
}
|
|
585
|
+
TIMESTAMP_SENSORS = {MultilevelSensorType.TIME}
|
|
586
|
+
VOLTAGE_SENSORS = {
|
|
587
|
+
MultilevelSensorType.VOLTAGE,
|
|
588
|
+
MultilevelSensorType.WATER_OXIDATION_REDUCTION_POTENTIAL,
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
# Meter CC constants
|
|
593
|
+
|
|
594
|
+
CC_SPECIFIC_METER_TYPE = "meterType"
|
|
595
|
+
CC_SPECIFIC_RATE_TYPE = "rateType"
|
|
596
|
+
|
|
597
|
+
RESET_METER_CC_API = "reset"
|
|
598
|
+
|
|
599
|
+
# optional attributes when calling the Meter CC reset API.
|
|
600
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/commandclass/MeterCC.ts#L873-L881
|
|
601
|
+
RESET_METER_OPTION_TARGET_VALUE = TARGET_VALUE_PROPERTY
|
|
602
|
+
RESET_METER_OPTION_TYPE = "type"
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/config/config/meters.json
|
|
606
|
+
class MeterType(IntEnum):
|
|
607
|
+
"""Enum with all known meter types."""
|
|
608
|
+
|
|
609
|
+
ELECTRIC = 1
|
|
610
|
+
GAS = 2
|
|
611
|
+
WATER = 3
|
|
612
|
+
HEATING = 4
|
|
613
|
+
COOLING = 5
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
class ElectricScale(IntEnum):
|
|
617
|
+
"""Enum with all known electric meter scale values."""
|
|
618
|
+
|
|
619
|
+
KILOWATT_HOUR = 0
|
|
620
|
+
KILOVOLT_AMPERE_HOUR = 1
|
|
621
|
+
WATT = 2
|
|
622
|
+
PULSE = 3
|
|
623
|
+
VOLT = 4
|
|
624
|
+
AMPERE = 5
|
|
625
|
+
POWER_FACTOR = 6
|
|
626
|
+
KILOVOLT_AMPERE_REACTIVE = 7
|
|
627
|
+
KILOVOLT_AMPERE_REACTIVE_HOUR = 8
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
class GasScale(IntEnum):
|
|
631
|
+
"""Enum with all known gas meter scale values."""
|
|
632
|
+
|
|
633
|
+
CUBIC_METER = 0
|
|
634
|
+
CUBIC_FEET = 1
|
|
635
|
+
PULSE_COUNT = 3
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
class WaterScale(IntEnum):
|
|
639
|
+
"""Enum with all known water meter scale values."""
|
|
640
|
+
|
|
641
|
+
CUBIC_METER = 0
|
|
642
|
+
CUBIC_FEET = 1
|
|
643
|
+
US_GALLON = 2
|
|
644
|
+
PULSE_COUNT = 3
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
class HeatingScale(IntEnum):
|
|
648
|
+
"""Enum with all known heating meter scale values."""
|
|
649
|
+
|
|
650
|
+
KILOWATT_HOUR = 0
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
CoolingScale = HeatingScale
|
|
654
|
+
|
|
655
|
+
MeterScaleType = Union[CoolingScale, ElectricScale, GasScale, HeatingScale, WaterScale]
|
|
656
|
+
|
|
657
|
+
METER_TYPE_TO_SCALE_ENUM_MAP: Dict[MeterType, Type[MeterScaleType]] = {
|
|
658
|
+
MeterType.ELECTRIC: ElectricScale,
|
|
659
|
+
MeterType.GAS: GasScale,
|
|
660
|
+
MeterType.WATER: WaterScale,
|
|
661
|
+
MeterType.HEATING: HeatingScale,
|
|
662
|
+
MeterType.COOLING: CoolingScale,
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
ENERGY_METER_TYPES: Set[MeterScaleType] = {
|
|
666
|
+
ElectricScale.KILOWATT_HOUR,
|
|
667
|
+
ElectricScale.KILOVOLT_AMPERE_HOUR,
|
|
668
|
+
ElectricScale.KILOVOLT_AMPERE_REACTIVE_HOUR,
|
|
669
|
+
HeatingScale.KILOWATT_HOUR,
|
|
670
|
+
CoolingScale.KILOWATT_HOUR,
|
|
671
|
+
}
|
|
672
|
+
POWER_METER_TYPES: Set[MeterScaleType] = {
|
|
673
|
+
ElectricScale.WATT,
|
|
674
|
+
ElectricScale.PULSE,
|
|
675
|
+
ElectricScale.KILOVOLT_AMPERE_REACTIVE,
|
|
676
|
+
}
|
|
677
|
+
POWER_FACTOR_METER_TYPES: Set[MeterScaleType] = {ElectricScale.POWER_FACTOR}
|
|
678
|
+
VOLTAGE_METER_TYPES: Set[MeterScaleType] = {ElectricScale.VOLT}
|
|
679
|
+
CURRENT_METER_TYPES: Set[MeterScaleType] = {ElectricScale.AMPERE}
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
class InclusionStrategy(IntEnum):
|
|
683
|
+
"""Enum for all known inclusion strategies."""
|
|
684
|
+
|
|
685
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L9-L46
|
|
686
|
+
DEFAULT = 0
|
|
687
|
+
SMART_START = 1
|
|
688
|
+
INSECURE = 2
|
|
689
|
+
SECURITY_S0 = 3
|
|
690
|
+
SECURITY_S2 = 4
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
class SecurityClass(IntEnum):
|
|
694
|
+
"""Enum for all known security classes."""
|
|
695
|
+
|
|
696
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/core/src/security/SecurityClass.ts#L3-L17
|
|
697
|
+
NONE = -1
|
|
698
|
+
S2_UNAUTHENTICATED = 0
|
|
699
|
+
S2_AUTHENTICATED = 1
|
|
700
|
+
S2_ACCESS_CONTROL = 2
|
|
701
|
+
S0_LEGACY = 7
|
zwave_js_server/exceptions.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"""Exceptions for zwave-js-server."""
|
|
2
|
+
from typing import Optional, TYPE_CHECKING
|
|
2
3
|
|
|
4
|
+
from .const import CommandClass
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .model.value import Value
|
|
5
8
|
|
|
6
9
|
|
|
7
10
|
class BaseZwaveJSServerError(Exception):
|
|
@@ -120,3 +123,34 @@ class BulkSetConfigParameterFailed(BaseZwaveJSServerError):
|
|
|
120
123
|
|
|
121
124
|
Derived from another exception
|
|
122
125
|
"""
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class InvalidCommandClass(BaseZwaveJSServerError):
|
|
129
|
+
"""Exception raised when Zwave Value has an invalid command class."""
|
|
130
|
+
|
|
131
|
+
def __init__(self, value: "Value", command_class: CommandClass) -> None:
|
|
132
|
+
"""Initialize an invalid Command Class error."""
|
|
133
|
+
self.value = value
|
|
134
|
+
self.command_class = command_class
|
|
135
|
+
super().__init__(
|
|
136
|
+
f"Value {value} does not match expected command class: {command_class}"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class UnknownValueData(BaseZwaveJSServerError):
|
|
141
|
+
"""
|
|
142
|
+
Exception raised when Zwave Value has data that the library can't parse.
|
|
143
|
+
|
|
144
|
+
This can be caused by an upstream issue with the driver, or missing support in the
|
|
145
|
+
library.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
def __init__(self, value: "Value", path: str) -> None:
|
|
149
|
+
"""Initialize an unknown data error."""
|
|
150
|
+
self.value = value
|
|
151
|
+
self.path = path
|
|
152
|
+
super().__init__(
|
|
153
|
+
f"Value {value} has unknown data in the following location: {path}. "
|
|
154
|
+
"Please report this issue, it can be caused by either an upstream issue "
|
|
155
|
+
"with the driver or missing support for this data in the library"
|
|
156
|
+
)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Provide a model for the Z-Wave JS controller."""
|
|
2
|
-
from
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Literal, TYPE_CHECKING, Dict, List, Optional, TypedDict, Union, cast
|
|
3
4
|
|
|
5
|
+
from ..const import InclusionStrategy, SecurityClass
|
|
4
6
|
from ..event import Event, EventBase
|
|
5
7
|
from .association import Association, AssociationGroup
|
|
6
8
|
from .node import Node
|
|
@@ -9,9 +11,41 @@ if TYPE_CHECKING:
|
|
|
9
11
|
from ..client import Client
|
|
10
12
|
|
|
11
13
|
|
|
14
|
+
class InclusionGrantDataType(TypedDict):
|
|
15
|
+
"""Representation of an inclusion grant data dict type."""
|
|
16
|
+
|
|
17
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L48-L56
|
|
18
|
+
securityClasses: List[SecurityClass]
|
|
19
|
+
clientSideAuth: bool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class InclusionGrant:
|
|
24
|
+
"""Representation of an inclusion grant."""
|
|
25
|
+
|
|
26
|
+
security_classes: List[SecurityClass]
|
|
27
|
+
client_side_auth: bool
|
|
28
|
+
|
|
29
|
+
def to_dict(self) -> InclusionGrantDataType:
|
|
30
|
+
"""Return InclusionGrantDataType dict from self."""
|
|
31
|
+
return {
|
|
32
|
+
"securityClasses": self.security_classes,
|
|
33
|
+
"clientSideAuth": self.client_side_auth,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_dict(cls, data: InclusionGrantDataType) -> "InclusionGrant":
|
|
38
|
+
"""Return InclusionGrant from InclusionGrantDataType dict."""
|
|
39
|
+
return cls(
|
|
40
|
+
[SecurityClass(sec_cls) for sec_cls in data["securityClasses"]],
|
|
41
|
+
data["clientSideAuth"],
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
12
45
|
class ControllerStatisticsDataType(TypedDict):
|
|
13
46
|
"""Represent a controller statistics data dict type."""
|
|
14
47
|
|
|
48
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/ControllerStatistics.ts#L20-L39
|
|
15
49
|
messagesTX: int
|
|
16
50
|
messagesRX: int
|
|
17
51
|
messagesDroppedTX: int
|
|
@@ -244,14 +278,37 @@ class Controller(EventBase):
|
|
|
244
278
|
return self._heal_network_progress
|
|
245
279
|
|
|
246
280
|
async def async_begin_inclusion(
|
|
247
|
-
self,
|
|
281
|
+
self,
|
|
282
|
+
inclusion_strategy: Union[
|
|
283
|
+
Literal[InclusionStrategy.SECURITY_S0],
|
|
284
|
+
Literal[InclusionStrategy.SECURITY_S2],
|
|
285
|
+
Literal[InclusionStrategy.INSECURE],
|
|
286
|
+
],
|
|
248
287
|
) -> bool:
|
|
249
288
|
"""Send beginInclusion command to Controller."""
|
|
250
289
|
data = await self.client.async_send_command(
|
|
251
290
|
{
|
|
252
291
|
"command": "controller.begin_inclusion",
|
|
253
|
-
"
|
|
254
|
-
}
|
|
292
|
+
"options": {"inclusionStrategy": inclusion_strategy},
|
|
293
|
+
},
|
|
294
|
+
require_schema=8,
|
|
295
|
+
)
|
|
296
|
+
return cast(bool, data["success"])
|
|
297
|
+
|
|
298
|
+
async def async_begin_inclusion_default(
|
|
299
|
+
self,
|
|
300
|
+
force_security: Optional[bool] = None,
|
|
301
|
+
) -> bool:
|
|
302
|
+
"""Send beginInclusion command to Controller using Default inclusion method."""
|
|
303
|
+
data = await self.client.async_send_command(
|
|
304
|
+
{
|
|
305
|
+
"command": "controller.begin_inclusion",
|
|
306
|
+
"options": {
|
|
307
|
+
"inclusionStrategy": InclusionStrategy.DEFAULT,
|
|
308
|
+
"forceSecurity": force_security,
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
require_schema=8,
|
|
255
312
|
)
|
|
256
313
|
return cast(bool, data["success"])
|
|
257
314
|
|
|
@@ -283,15 +340,22 @@ class Controller(EventBase):
|
|
|
283
340
|
)
|
|
284
341
|
|
|
285
342
|
async def async_replace_failed_node(
|
|
286
|
-
self,
|
|
343
|
+
self,
|
|
344
|
+
node_id: int,
|
|
345
|
+
inclusion_strategy: Union[
|
|
346
|
+
Literal[InclusionStrategy.SECURITY_S0],
|
|
347
|
+
Literal[InclusionStrategy.SECURITY_S2],
|
|
348
|
+
Literal[InclusionStrategy.INSECURE],
|
|
349
|
+
],
|
|
287
350
|
) -> bool:
|
|
288
351
|
"""Send replaceFailedNode command to Controller."""
|
|
289
352
|
data = await self.client.async_send_command(
|
|
290
353
|
{
|
|
291
354
|
"command": "controller.replace_failed_node",
|
|
292
355
|
"nodeId": node_id,
|
|
293
|
-
"
|
|
294
|
-
}
|
|
356
|
+
"options": {"inclusionStrategy": inclusion_strategy},
|
|
357
|
+
},
|
|
358
|
+
require_schema=8,
|
|
295
359
|
)
|
|
296
360
|
return cast(bool, data["success"])
|
|
297
361
|
|
|
@@ -438,6 +502,26 @@ class Controller(EventBase):
|
|
|
438
502
|
)
|
|
439
503
|
return cast(List[int], data["neighbors"])
|
|
440
504
|
|
|
505
|
+
async def async_grant_security_classes(
|
|
506
|
+
self, inclusion_grant: InclusionGrant
|
|
507
|
+
) -> None:
|
|
508
|
+
"""Send grantSecurityClasses command to Controller."""
|
|
509
|
+
await self.client.async_send_command(
|
|
510
|
+
{
|
|
511
|
+
"command": "controller.grant_security_classes",
|
|
512
|
+
"inclusionGrant": inclusion_grant.to_dict(),
|
|
513
|
+
}
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
async def async_validate_dsk_and_enter_pin(self, pin: str) -> None:
|
|
517
|
+
"""Send validateDSKAndEnterPIN command to Controller."""
|
|
518
|
+
await self.client.async_send_command(
|
|
519
|
+
{
|
|
520
|
+
"command": "controller.validate_dsk_and_enter_pin",
|
|
521
|
+
"pin": pin,
|
|
522
|
+
}
|
|
523
|
+
)
|
|
524
|
+
|
|
441
525
|
def receive_event(self, event: Event) -> None:
|
|
442
526
|
"""Receive an event."""
|
|
443
527
|
if event.data["source"] == "node":
|
|
@@ -502,3 +586,12 @@ class Controller(EventBase):
|
|
|
502
586
|
"""Process a statistics updated event."""
|
|
503
587
|
self._statistics.data.update(event.data["statistics"])
|
|
504
588
|
event.data["statistics_updated"] = self.statistics
|
|
589
|
+
|
|
590
|
+
def handle_grant_security_classes(self, event: Event) -> None:
|
|
591
|
+
"""Process a grant security classes event."""
|
|
592
|
+
event.data["requested_grant"] = InclusionGrant.from_dict(
|
|
593
|
+
event.data["requested"]
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
def handle_validate_dsk_and_enter_pin(self, event: Event) -> None:
|
|
597
|
+
"""Process a validate dsk and enter pin event."""
|
|
@@ -38,10 +38,10 @@ class LogConfig:
|
|
|
38
38
|
}
|
|
39
39
|
return cast(LogConfigDataType, {k: v for k, v in data.items() if v is not None})
|
|
40
40
|
|
|
41
|
-
@
|
|
42
|
-
def from_dict(data: LogConfigDataType) -> "LogConfig":
|
|
41
|
+
@classmethod
|
|
42
|
+
def from_dict(cls, data: LogConfigDataType) -> "LogConfig":
|
|
43
43
|
"""Return LogConfig from LogConfigDataType dict."""
|
|
44
|
-
return
|
|
44
|
+
return cls(
|
|
45
45
|
data.get("enabled"),
|
|
46
46
|
LogLevel(data["level"]) if "level" in data else None,
|
|
47
47
|
data.get("logToFile"),
|
zwave_js_server/model/node.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Provide a model for the Z-Wave JS node."""
|
|
2
2
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, TypedDict, Union, cast
|
|
3
3
|
|
|
4
|
-
from ..const import INTERVIEW_FAILED, CommandClass, NodeStatus
|
|
4
|
+
from ..const import INTERVIEW_FAILED, CommandClass, NodeStatus, SecurityClass
|
|
5
5
|
from ..event import Event
|
|
6
6
|
from ..exceptions import (
|
|
7
7
|
FailedCommand,
|
|
@@ -42,6 +42,7 @@ if TYPE_CHECKING:
|
|
|
42
42
|
class NodeStatisticsDataType(TypedDict):
|
|
43
43
|
"""Represent a node statistics data dict type."""
|
|
44
44
|
|
|
45
|
+
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/node/NodeStatistics.ts#L21-L33
|
|
45
46
|
commandsTX: int
|
|
46
47
|
commandsRX: int
|
|
47
48
|
commandsDroppedTX: int
|
|
@@ -511,6 +512,25 @@ class Node(Endpoint):
|
|
|
511
512
|
)
|
|
512
513
|
return cast(bool, data.get("responded", False))
|
|
513
514
|
|
|
515
|
+
async def async_has_security_class(self, security_class: SecurityClass) -> bool:
|
|
516
|
+
"""Return whether node has the given security class."""
|
|
517
|
+
data = await self.async_send_command(
|
|
518
|
+
"has_security_class",
|
|
519
|
+
securityClass=security_class,
|
|
520
|
+
require_schema=8,
|
|
521
|
+
wait_for_result=True,
|
|
522
|
+
)
|
|
523
|
+
assert data
|
|
524
|
+
return cast(bool, data["hasSecurityClass"])
|
|
525
|
+
|
|
526
|
+
async def async_get_highest_security_class(self) -> SecurityClass:
|
|
527
|
+
"""Get the highest security class that a node supports."""
|
|
528
|
+
data = await self.async_send_command(
|
|
529
|
+
"get_highest_security_class", require_schema=8, wait_for_result=True
|
|
530
|
+
)
|
|
531
|
+
assert data
|
|
532
|
+
return SecurityClass(data["highestSecurityClass"])
|
|
533
|
+
|
|
514
534
|
def handle_wake_up(self, event: Event) -> None:
|
|
515
535
|
"""Process a node wake up event."""
|
|
516
536
|
# pylint: disable=unused-argument
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Command Class specific utility functions for values."""
|
|
2
|
+
from ..const import (
|
|
3
|
+
CC_SPECIFIC_METER_TYPE,
|
|
4
|
+
CC_SPECIFIC_SCALE,
|
|
5
|
+
CC_SPECIFIC_SENSOR_TYPE,
|
|
6
|
+
METER_TYPE_TO_SCALE_ENUM_MAP,
|
|
7
|
+
CommandClass,
|
|
8
|
+
MeterScaleType,
|
|
9
|
+
MeterType,
|
|
10
|
+
MultilevelSensorType,
|
|
11
|
+
)
|
|
12
|
+
from ..exceptions import InvalidCommandClass, UnknownValueData
|
|
13
|
+
from ..model.value import Value
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_meter_type(value: Value) -> MeterType:
|
|
17
|
+
"""Get the MeterType for a given value."""
|
|
18
|
+
if value.command_class != CommandClass.METER:
|
|
19
|
+
raise InvalidCommandClass(value, CommandClass.METER)
|
|
20
|
+
try:
|
|
21
|
+
return MeterType(value.metadata.cc_specific[CC_SPECIFIC_METER_TYPE])
|
|
22
|
+
except ValueError:
|
|
23
|
+
raise UnknownValueData( # pylint: disable=raise-missing-from
|
|
24
|
+
value, f"metadata.cc_specific.{CC_SPECIFIC_METER_TYPE}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_meter_scale_type(value: Value) -> MeterScaleType:
|
|
29
|
+
"""Get the ScaleType for a given value."""
|
|
30
|
+
meter_type = get_meter_type(value)
|
|
31
|
+
scale_enum = METER_TYPE_TO_SCALE_ENUM_MAP[meter_type]
|
|
32
|
+
try:
|
|
33
|
+
return scale_enum(value.metadata.cc_specific[CC_SPECIFIC_SCALE])
|
|
34
|
+
except ValueError:
|
|
35
|
+
raise UnknownValueData( # pylint: disable=raise-missing-from
|
|
36
|
+
value, f"metadata.cc_specific.{CC_SPECIFIC_SCALE}"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_multilevel_sensor_type(value: Value) -> MultilevelSensorType:
|
|
41
|
+
"""Get the MultilevelSensorType for a given value."""
|
|
42
|
+
if value.command_class != CommandClass.SENSOR_MULTILEVEL:
|
|
43
|
+
raise InvalidCommandClass(value, CommandClass.SENSOR_MULTILEVEL)
|
|
44
|
+
try:
|
|
45
|
+
return MultilevelSensorType(value.metadata.cc_specific[CC_SPECIFIC_SENSOR_TYPE])
|
|
46
|
+
except ValueError:
|
|
47
|
+
raise UnknownValueData( # pylint: disable=raise-missing-from
|
|
48
|
+
value, f"metadata.cc_specific.{CC_SPECIFIC_SENSOR_TYPE}"
|
|
49
|
+
)
|
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
zwave_js_server/__init__.py,sha256=Ey3O4Tha56uU-M92oLJmQHupCJ7B9oZmxlQTo8pGUM8,45
|
|
2
2
|
zwave_js_server/__main__.py,sha256=1gWC927sa3FwcA47ndmrRWW0HlfYVdiUarjEsccRF2k,3624
|
|
3
3
|
zwave_js_server/client.py,sha256=kVaxlUfrj2izdwjbzgBZFVi0vZDZflkCtUDDBhugPYk,11946
|
|
4
|
-
zwave_js_server/const.py,sha256=
|
|
4
|
+
zwave_js_server/const.py,sha256=V-kS0EkzPaqTDM0-Yr2yuNzguPma5uYAjw9AqpU7nQ8,19220
|
|
5
5
|
zwave_js_server/dump.py,sha256=inv0Q-i0DbzEcbwXeLDiu29U2I248pPMyNUTQDp5wYY,1184
|
|
6
6
|
zwave_js_server/event.py,sha256=0Aw3NzkzKMnhS7AxBh6BwAVYXRu4zDKeUDib9mHjj8w,1772
|
|
7
|
-
zwave_js_server/exceptions.py,sha256=
|
|
7
|
+
zwave_js_server/exceptions.py,sha256=mbuiWMwmVjmQrimhZROCguQFYQuFP93pubDJKs1FcVc,4741
|
|
8
8
|
zwave_js_server/firmware.py,sha256=F5selNpOWWICuLs3L8zBjddnGKrEmip7LriijjL9pDA,878
|
|
9
9
|
zwave_js_server/version.py,sha256=RDFP2kSU3cCVIQbgMWggdeDnvhtVsZzzZg9pOjH7CC8,364
|
|
10
10
|
zwave_js_server/model/__init__.py,sha256=XfyKH8lxZ3CB7CbRkOr5sR-eV0GrklZiBtNPmlnCJ_8,123
|
|
11
11
|
zwave_js_server/model/association.py,sha256=FsgKAha7mw6dpk7u7zdQoNEajTyiL0S5eOYcY4M2Rx4,529
|
|
12
12
|
zwave_js_server/model/command_class.py,sha256=CPKZOJNr6T3Y-ShfFB0CDZOLmITtXm5p1cOHbnRHMaI,1118
|
|
13
|
-
zwave_js_server/model/controller.py,sha256=
|
|
13
|
+
zwave_js_server/model/controller.py,sha256=1eQfRwErjBrOtUYyTtTBSoqeWw6mSxO3XTWV8pi2wzw,20577
|
|
14
14
|
zwave_js_server/model/device_class.py,sha256=XxiTRVxY-Dc5cVHfJQFc2IkUHEXRiLpL5-V49PkwMxg,1708
|
|
15
15
|
zwave_js_server/model/device_config.py,sha256=gn3xMGs8efn3B1BQ31VsXOG2u-CdMFJeIKDqIyMPBj8,5882
|
|
16
16
|
zwave_js_server/model/driver.py,sha256=IEmcukQw7r_Wrls_ZeyZ77RnnTKW9eopeDExOUoFm88,5166
|
|
17
17
|
zwave_js_server/model/endpoint.py,sha256=EJ_178hg2O4A3oc2xUegLnv6mshv0zo1h6ZwZ1Ws0qo,4110
|
|
18
18
|
zwave_js_server/model/firmware.py,sha256=ATSCz3fbCipthqfmTbw7C1bfeK4DhrWOiaGdxHNqPds,2315
|
|
19
|
-
zwave_js_server/model/log_config.py,sha256=
|
|
19
|
+
zwave_js_server/model/log_config.py,sha256=Qti1p8Y1T1-mXJJydqLAa9JPbglzIzAd34koftG6U0w,1569
|
|
20
20
|
zwave_js_server/model/log_message.py,sha256=9HQnvVZkwg7V_ENn4YLylEoX6OkmU9EOWMmK9BCQ92k,2607
|
|
21
|
-
zwave_js_server/model/node.py,sha256=
|
|
21
|
+
zwave_js_server/model/node.py,sha256=QlTlRfoJDjuwnq-uODjblXyma584M-0sRfI5pks9Jsk,22991
|
|
22
22
|
zwave_js_server/model/notification.py,sha256=hflkoNjr6ZrS7D1rpdTmeVfi6h9L87EqGCVupgmBAZY,3689
|
|
23
23
|
zwave_js_server/model/value.py,sha256=rpJNKYEzxfoZvUS4kRruRseGJCDOzVk04tpZHs34NCI,8450
|
|
24
24
|
zwave_js_server/model/version.py,sha256=FTdCCyHW69NW4CXeeuNMx339SF0tV2ZipPt24eVcl2o,1000
|
|
25
25
|
zwave_js_server/util/__init__.py,sha256=ArF1K885aW0GdVd7Lo8fl8Atf70gvsxO5Ra_WoJTG28,42
|
|
26
|
+
zwave_js_server/util/command_class.py,sha256=RQ9iJ1JbhYom1qc-FH25Hrk_Ef-WUyv6hoNBqXaOr6E,1822
|
|
26
27
|
zwave_js_server/util/helpers.py,sha256=RfIqYFVARlGzvG5oIs1SIvbUkHT5JVjRX3Cs-5SzhdA,1475
|
|
27
28
|
zwave_js_server/util/lock.py,sha256=m_bRvshaRHV0v_YBaCIrgVDUPLab6xFoXZxXuxknD5E,3806
|
|
28
29
|
zwave_js_server/util/multicast.py,sha256=iZZ1BcbtH4WqMm6DoHqH_ft0AwdUNSIjU8Yu-QYeKFk,4303
|
|
29
30
|
zwave_js_server/util/node.py,sha256=tYS9UaPs4UCD6Q0_yiRySOlFH-vjf5bdgozYhSAybTo,12314
|
|
30
|
-
zwave_js_server_python-0.
|
|
31
|
-
zwave_js_server_python-0.
|
|
32
|
-
zwave_js_server_python-0.
|
|
33
|
-
zwave_js_server_python-0.
|
|
34
|
-
zwave_js_server_python-0.
|
|
35
|
-
zwave_js_server_python-0.
|
|
31
|
+
zwave_js_server_python-0.29.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
32
|
+
zwave_js_server_python-0.29.0.dist-info/METADATA,sha256=RL7OTpRpFPtQkvWHGZjCjUaNeIbOVXOUVgfkY3qBhQA,1627
|
|
33
|
+
zwave_js_server_python-0.29.0.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
|
|
34
|
+
zwave_js_server_python-0.29.0.dist-info/entry_points.txt,sha256=_8Swg1yhKiBElo6k1fxIEd6E8uPz8PDxQpwQoZ29FZE,74
|
|
35
|
+
zwave_js_server_python-0.29.0.dist-info/top_level.txt,sha256=-hwsl-i4Av5Op_yfOHC_OP56KPmzp_iVEkeohRIN5Ng,16
|
|
36
|
+
zwave_js_server_python-0.29.0.dist-info/RECORD,,
|
|
File without changes
|
{zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{zwave_js_server_python-0.28.0.dist-info → zwave_js_server_python-0.29.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|