Example #1
0
    def test_parse_transcoder_from_subclass(self):
        """Test parsing only subclasses of a DPT class."""
        assert DPTBase.parse_transcoder("string") == DPTString
        assert DPTNumeric.parse_transcoder("string") is None
        assert DPT2ByteFloat.parse_transcoder("string") is None

        assert DPTBase.parse_transcoder("percent") == DPTScaling
        assert DPTNumeric.parse_transcoder("percent") == DPTScaling
        assert DPT2ByteFloat.parse_transcoder("percent") is None

        assert DPTBase.parse_transcoder("temperature") == DPTTemperature
        assert DPTNumeric.parse_transcoder("temperature") == DPTTemperature
        assert DPT2ByteFloat.parse_transcoder("temperature") == DPTTemperature
Example #2
0
    async def service_send_to_knx_bus(self, call: ServiceCall) -> None:
        """Service for sending an arbitrary KNX message to the KNX bus."""
        attr_address = call.data[KNX_ADDRESS]
        attr_payload = call.data[SERVICE_KNX_ATTR_PAYLOAD]
        attr_type = call.data.get(SERVICE_KNX_ATTR_TYPE)
        attr_response = call.data[SERVICE_KNX_ATTR_RESPONSE]

        payload: DPTBinary | DPTArray
        if attr_type is not None:
            transcoder = DPTBase.parse_transcoder(attr_type)
            if transcoder is None:
                raise ValueError(
                    f"Invalid type for knx.send service: {attr_type}")
            payload = DPTArray(transcoder.to_knx(attr_payload))
        elif isinstance(attr_payload, int):
            payload = DPTBinary(attr_payload)
        else:
            payload = DPTArray(attr_payload)

        for address in attr_address:
            telegram = Telegram(
                destination_address=parse_device_group_address(address),
                payload=GroupValueResponse(payload)
                if attr_response else GroupValueWrite(payload),
            )
            await self.xknx.telegrams.put(telegram)
Example #3
0
 def __init__(
     self,
     xknx: "XKNX",
     group_address: Optional["GroupAddressableType"] = None,
     group_address_state: Optional["GroupAddressableType"] = None,
     sync_state: bool = True,
     value_type: Optional[str] = None,
     device_name: Optional[str] = None,
     feature_name: str = "Control",
     after_update_cb: Optional[AsyncCallbackType] = None,
     passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
 ):
     """Initialize control remote value."""
     # pylint: disable=too-many-arguments
     if value_type is None:
         raise ConversionError("no value type given", device_name=device_name)
     # TODO: typing - parse from DPTControlStepCode when parse_transcoder is a classmethod
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None or not isinstance(_dpt_class(), DPTControlStepCode):
         raise ConversionError(
             "invalid value type", value_type=value_type, device_name=device_name
         )
     self.dpt_class: Type[DPTControlStepCode] = _dpt_class  # type: ignore
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
         passive_group_addresses=passive_group_addresses,
     )
Example #4
0
def ensure_knx_dpt(value: str) -> str:
    """Ensure value is a valid KNX DPT."""
    dpt_class = DPTBase.parse_transcoder(value)
    if dpt_class is None:
        raise vol.Invalid(f"{value!r} is not a valid KNX DPT")

    return value
Example #5
0
 def __init__(
     self,
     xknx,
     group_address=None,
     group_address_state=None,
     sync_state=True,
     value_type=None,
     device_name=None,
     feature_name="Control",
     after_update_cb=None,
     invert=False,
     passive_group_addresses: List[str] = None,
 ):
     """Initialize control remote value."""
     # pylint: disable=too-many-arguments
     self.invert = invert
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None:
         raise ConversionError("invalid value type",
                               value_type=value_type,
                               device_name=device_name)
     self.dpt_class = _dpt_class
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
         passive_group_addresses=passive_group_addresses,
     )
Example #6
0
 def __init__(
     self,
     xknx: "XKNX",
     group_address: Optional["GroupAddressableType"] = None,
     group_address_state: Optional["GroupAddressableType"] = None,
     sync_state: bool = True,
     value_type: Optional[str] = None,
     device_name: Optional[str] = None,
     feature_name: str = "Value",
     after_update_cb: Optional[AsyncCallbackType] = None,
     passive_group_addresses: Optional[List["GroupAddressableType"]] = None,
 ):
     """Initialize RemoteValueSensor class."""
     # pylint: disable=too-many-arguments
     if value_type is None:
         raise ConversionError("no value type given",
                               device_name=device_name)
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None:
         raise ConversionError("invalid value type",
                               value_type=value_type,
                               device_name=device_name)
     self.dpt_class = _dpt_class
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
         passive_group_addresses=passive_group_addresses,
     )
Example #7
0
 def __init__(
     self,
     xknx,
     group_address=None,
     group_address_state=None,
     sync_state=True,
     value_type=None,
     device_name=None,
     feature_name="Value",
     after_update_cb=None,
 ):
     """Initialize RemoteValueSensor class."""
     # pylint: disable=too-many-arguments
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None:
         raise ConversionError("invalid value type",
                               value_type=value_type,
                               device_name=device_name)
     self.dpt_class = _dpt_class
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
     )
Example #8
0
 def __init__(
     self,
     xknx: XKNX,
     group_address: GroupAddressesType | None = None,
     group_address_state: GroupAddressesType | None = None,
     sync_state: bool = True,
     value_type: int | str | None = None,
     device_name: str | None = None,
     feature_name: str = "Value",
     after_update_cb: AsyncCallbackType | None = None,
 ):
     """Initialize RemoteValueSensor class."""
     if value_type is None:
         raise ConversionError("no value type given",
                               device_name=device_name)
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None:
         raise ConversionError("invalid value type",
                               value_type=value_type,
                               device_name=device_name)
     self.dpt_class = _dpt_class
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
     )
Example #9
0
 def __init__(
     self,
     xknx: XKNX,
     group_address: GroupAddressesType | None = None,
     group_address_state: GroupAddressesType | None = None,
     sync_state: bool = True,
     value_type: str | None = None,
     device_name: str | None = None,
     feature_name: str = "Control",
     after_update_cb: AsyncCallbackType | None = None,
 ):
     """Initialize control remote value."""
     if value_type is None:
         raise ConversionError("no value type given",
                               device_name=device_name)
     # TODO: typing - parse from DPTControlStepCode when parse_transcoder is a classmethod
     _dpt_class = DPTBase.parse_transcoder(value_type)
     if _dpt_class is None or not isinstance(_dpt_class(),
                                             DPTControlStepCode):
         raise ConversionError("invalid value type",
                               value_type=value_type,
                               device_name=device_name)
     self.dpt_class: type[DPTControlStepCode] = _dpt_class  # type: ignore
     super().__init__(
         xknx,
         group_address,
         group_address_state,
         sync_state=sync_state,
         device_name=device_name,
         feature_name=feature_name,
         after_update_cb=after_update_cb,
     )
Example #10
0
 def register_event_callback(self) -> TelegramQueue.Callback:
     """Register callback for knx_event within XKNX TelegramQueue."""
     address_filters = []
     for filter_set in self.config[CONF_EVENT]:
         _filters = list(map(AddressFilter, filter_set[KNX_ADDRESS]))
         address_filters.extend(_filters)
         if (dpt := filter_set.get(CONF_TYPE)) and (
                 transcoder := DPTBase.parse_transcoder(dpt)):
Example #11
0
def sensor_value_type(value: T) -> T:
    """Validate sensor type."""
    if DPTBase.parse_transcoder(value):
        return value

    if value.lower() in ["binary", "time", "datetime", "date"]:
        return str(value)

    raise vol.Invalid(f"invalid value type {value}")
Example #12
0
 def calculate_payload(attr_payload):
     """Calculate payload depending on type of attribute."""
     if attr_type is not None:
         transcoder = DPTBase.parse_transcoder(attr_type)
         if transcoder is None:
             raise ValueError(f"Invalid type for knx.send service: {attr_type}")
         return DPTArray(transcoder.to_knx(attr_payload))
     if isinstance(attr_payload, int):
         return DPTBinary(attr_payload)
     return DPTArray(attr_payload)
Example #13
0
 def register_event_callback(self) -> TelegramQueue.Callback:
     """Register callback for knx_event within XKNX TelegramQueue."""
     # backwards compatibility for deprecated CONF_KNX_EVENT_FILTER
     # use `address_filters = []` when this is not needed anymore
     address_filters = list(map(AddressFilter, self.config[CONF_KNX_EVENT_FILTER]))
     for filter_set in self.config[CONF_EVENT]:
         _filters = list(map(AddressFilter, filter_set[KNX_ADDRESS]))
         address_filters.extend(_filters)
         if (dpt := filter_set.get(CONF_TYPE)) and (
             transcoder := DPTBase.parse_transcoder(dpt)
         ):
Example #14
0
 def calculate_payload(attr_payload):
     """Calculate payload depending on type of attribute."""
     if attr_type:
         try:
             transcoder = DPTBase.parse_transcoder(attr_type)
             return DPTArray(transcoder.to_knx(attr_payload))
         except AttributeError as ex:
             _LOGGER.error("Invalid type for knx.send service: %s",
                           attr_type)
             raise ex
     if isinstance(attr_payload, int):
         return DPTBinary(attr_payload)
     return DPTArray(attr_payload)
Example #15
0
 def test_dpt_alternative_notations(self):
     """Test the parser for accepting alternateive notations for the same DPT class."""
     dpt1 = DPTBase.parse_transcoder("2byte_unsigned")
     dpt2 = DPTBase.parse_transcoder(7)
     dpt3 = DPTBase.parse_transcoder("DPT-7")
     self.assertEqual(dpt1, dpt2)
     self.assertEqual(dpt2, dpt3)
     dpt4 = DPTBase.parse_transcoder("temperature")
     dpt5 = DPTBase.parse_transcoder(9.001)
     dpt6 = DPTBase.parse_transcoder("9.001")
     self.assertEqual(dpt4, dpt5)
     self.assertEqual(dpt5, dpt6)
     dpt7 = DPTBase.parse_transcoder("active_energy")
     dpt8 = DPTBase.parse_transcoder(13.010)
     self.assertEqual(dpt7, dpt8, "parsing float failed")
Example #16
0
 def test_dpt_alternative_notations(self):
     """Test the parser for accepting alternateive notations for the same DPT class."""
     dpt1 = DPTBase.parse_transcoder("2byte_unsigned")
     dpt2 = DPTBase.parse_transcoder(7)
     dpt3 = DPTBase.parse_transcoder("DPT-7")
     assert dpt1 == dpt2
     assert dpt2 == dpt3
     dpt4 = DPTBase.parse_transcoder("temperature")
     dpt5 = DPTBase.parse_transcoder("9.001")
     assert dpt4 == dpt5
     dpt7 = DPTBase.parse_transcoder("active_energy")
     dpt8 = DPTBase.parse_transcoder("13.010")
     assert dpt7 == dpt8
Example #17
0
    async def service_event_register_modify(self, call: ServiceCall) -> None:
        """Service for adding or removing a GroupAddress to the knx_event filter."""
        attr_address = call.data[KNX_ADDRESS]
        group_addresses = list(map(parse_device_group_address, attr_address))

        if call.data.get(SERVICE_KNX_ATTR_REMOVE):
            for group_address in group_addresses:
                try:
                    self._knx_event_callback.group_addresses.remove(group_address)
                except ValueError:
                    _LOGGER.warning(
                        "Service event_register could not remove event for '%s'",
                        str(group_address),
                    )
                if group_address in self._group_address_transcoder:
                    del self._group_address_transcoder[group_address]
            return

        if (dpt := call.data.get(CONF_TYPE)) and (
            transcoder := DPTBase.parse_transcoder(dpt)
        ):
Example #18
0
def button_payload_sub_validator(entity_config: OrderedDict) -> OrderedDict:
    """Validate a button entity payload configuration."""
    if _type := entity_config.get(CONF_TYPE):
        _payload = entity_config[ButtonSchema.CONF_VALUE]
        if (transcoder := DPTBase.parse_transcoder(_type)) is None:
            raise vol.Invalid(f"'type: {_type}' is not a valid sensor type.")
Example #19
0
def sensor_type_validator(value: Any) -> str | int:
    """Validate that value is parsable as sensor type."""
    if isinstance(value, (str, int)) and DPTBase.parse_transcoder(value) is not None:
        return value
    raise vol.Invalid(f"value '{value}' is not a valid sensor type.")