zwave-js-server-python/zwave_js_server/model/controller/inclusion_and_provisioning.py

204 lines
7.5 KiB
Python

"""Provide a model for inclusion and provisioning."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, TypedDict
from ...const import Protocols, ProvisioningEntryStatus, QRCodeVersion, SecurityClass
class InclusionGrantDataType(TypedDict):
"""Representation of an inclusion grant data dict type."""
# https://github.com/zwave-js/node-zwave-js/blob/master/packages/zwave-js/src/lib/controller/Inclusion.ts#L48-L56
securityClasses: list[int]
clientSideAuth: bool
@dataclass
class InclusionGrant:
"""Representation of an inclusion grant."""
security_classes: list[SecurityClass]
client_side_auth: bool
def to_dict(self) -> InclusionGrantDataType:
"""Return InclusionGrantDataType dict from self."""
return {
"securityClasses": [sec_cls.value for sec_cls in self.security_classes],
"clientSideAuth": self.client_side_auth,
}
@classmethod
def from_dict(cls, data: InclusionGrantDataType) -> InclusionGrant:
"""Return InclusionGrant from InclusionGrantDataType dict."""
return cls(
security_classes=[
SecurityClass(sec_cls) for sec_cls in data["securityClasses"]
],
client_side_auth=data["clientSideAuth"],
)
@dataclass
class ProvisioningEntry:
"""Class to represent the base fields of a provisioning entry."""
dsk: str
security_classes: list[SecurityClass]
requested_security_classes: list[SecurityClass] | None = None
status: ProvisioningEntryStatus = ProvisioningEntryStatus.ACTIVE
protocol: Protocols | None = None
additional_properties: dict[str, Any] | None = None
def to_dict(self) -> dict[str, Any]:
"""Return PlannedProvisioning data dict from self."""
data = {
"dsk": self.dsk,
"securityClasses": [sec_cls.value for sec_cls in self.security_classes],
"status": self.status.value,
**(self.additional_properties or {}),
}
if self.requested_security_classes:
data["requestedSecurityClasses"] = [
sec_cls.value for sec_cls in self.requested_security_classes
]
if self.protocol is not None:
data["protocol"] = self.protocol.value
return data
@classmethod
def from_dict(cls, data: dict[str, Any]) -> ProvisioningEntry:
"""Return ProvisioningEntry from data dict."""
cls_instance = cls(
dsk=data["dsk"],
security_classes=[
SecurityClass(sec_cls) for sec_cls in data["securityClasses"]
],
)
if additional_properties := {
k: v
for k, v in data.items()
if k not in ("dsk", "securityClasses", "requestedSecurityClasses", "status")
}:
cls_instance.additional_properties = additional_properties
if "requestedSecurityClasses" in data:
cls_instance.requested_security_classes = [
SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"]
]
if "status" in data:
cls_instance.status = ProvisioningEntryStatus(data["status"])
if "protocol" in data:
cls_instance.protocol = Protocols(data["protocol"])
return cls_instance
@dataclass
class QRProvisioningInformationMixin:
"""Mixin class to represent the base fields of a QR provisioning information."""
version: QRCodeVersion
generic_device_class: int
specific_device_class: int
installer_icon_type: int
manufacturer_id: int
product_type: int
product_id: int
application_version: str
max_inclusion_request_interval: int | None
uuid: str | None
supported_protocols: list[Protocols] | None
@dataclass
class QRProvisioningInformation(ProvisioningEntry, QRProvisioningInformationMixin):
"""Representation of provisioning information retrieved from a QR code."""
def to_dict(self) -> dict[str, Any]:
"""Return QRProvisioningInformation data dict from self."""
data = {
"version": self.version.value,
"securityClasses": [sec_cls.value for sec_cls in self.security_classes],
"dsk": self.dsk,
"status": self.status.value,
"genericDeviceClass": self.generic_device_class,
"specificDeviceClass": self.specific_device_class,
"installerIconType": self.installer_icon_type,
"manufacturerId": self.manufacturer_id,
"productType": self.product_type,
"productId": self.product_id,
"applicationVersion": self.application_version,
**(self.additional_properties or {}),
}
if self.requested_security_classes:
data["requestedSecurityClasses"] = [
sec_cls.value for sec_cls in self.requested_security_classes
]
if self.max_inclusion_request_interval is not None:
data["maxInclusionRequestInterval"] = self.max_inclusion_request_interval
if self.uuid is not None:
data["uuid"] = self.uuid
if self.supported_protocols is not None:
data["supportedProtocols"] = [
protocol.value for protocol in self.supported_protocols
]
return data
@classmethod
def from_dict(cls, data: dict[str, Any]) -> QRProvisioningInformation:
"""Return QRProvisioningInformation from data dict."""
supported_protocols: list[Protocols] | None = None
if "supportedProtocols" in data:
supported_protocols = [
Protocols(supported_protocol)
for supported_protocol in data["supportedProtocols"]
]
cls_instance = cls(
version=QRCodeVersion(data["version"]),
security_classes=[
SecurityClass(sec_cls) for sec_cls in data["securityClasses"]
],
dsk=data["dsk"],
generic_device_class=data["genericDeviceClass"],
specific_device_class=data["specificDeviceClass"],
installer_icon_type=data["installerIconType"],
manufacturer_id=data["manufacturerId"],
product_type=data["productType"],
product_id=data["productId"],
application_version=data["applicationVersion"],
max_inclusion_request_interval=data.get("maxInclusionRequestInterval"),
uuid=data.get("uuid"),
supported_protocols=supported_protocols,
)
if additional_properties := {
k: v
for k, v in data.items()
if k
not in (
"version",
"securityClasses",
"requestedSecurityClasses",
"dsk",
"genericDeviceClass",
"specificDeviceClass",
"installerIconType",
"manufacturerId",
"productType",
"productId",
"applicationVersion",
"maxInclusionRequestInterval",
"uuid",
"supportedProtocols",
"status",
)
}:
cls_instance.additional_properties = additional_properties
if "requestedSecurityClasses" in data:
cls_instance.requested_security_classes = [
SecurityClass(sec_cls) for sec_cls in data["requestedSecurityClasses"]
]
if "status" in data:
cls_instance.status = ProvisioningEntryStatus(data["status"])
return cls_instance