Example #1
0
    def __init__(
        self,
        xknx: XKNX,
        name: str,
        group_address_state: GroupAddressesType | None = None,
        sync_state: bool | int | float | str = True,
        always_callback: bool = False,
        value_type: int | str | None = None,
        device_updated_cb: DeviceCallbackType[Sensor] | None = None,
    ):
        """Initialize Sensor class."""
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value: RemoteValueControl | RemoteValueSensor
        if isinstance(value_type, str) and value_type in [
                "stepwise_dimming",
                "stepwise_blinds",
                "startstop_dimming",
                "startstop_blinds",
        ]:
            self.sensor_value = RemoteValueControl(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        self.always_callback = always_callback
Example #2
0
    def __init__(
        self,
        xknx: "XKNX",
        name: str,
        group_address_temperature: Optional["GroupAddressableType"] = None,
        group_address_brightness_south: Optional[
            "GroupAddressableType"] = None,
        group_address_brightness_north: Optional[
            "GroupAddressableType"] = None,
        group_address_brightness_west: Optional["GroupAddressableType"] = None,
        group_address_brightness_east: Optional["GroupAddressableType"] = None,
        group_address_wind_speed: Optional["GroupAddressableType"] = None,
        group_address_wind_bearing: Optional["GroupAddressableType"] = None,
        group_address_rain_alarm: Optional["GroupAddressableType"] = None,
        group_address_frost_alarm: Optional["GroupAddressableType"] = None,
        group_address_wind_alarm: Optional["GroupAddressableType"] = None,
        group_address_day_night: Optional["GroupAddressableType"] = None,
        group_address_air_pressure: Optional["GroupAddressableType"] = None,
        group_address_humidity: Optional["GroupAddressableType"] = None,
        create_sensors: bool = False,
        sync_state: bool = True,
        device_updated_cb: Optional[DeviceCallbackType] = None,
    ) -> None:
        """Initialize Weather class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self._temperature = RemoteValueSensor(
            xknx,
            group_address_state=group_address_temperature,
            sync_state=sync_state,
            value_type="temperature",
            device_name=self.name,
            feature_name="Temperature",
            after_update_cb=self.after_update,
        )

        self._brightness_south = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_south,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness south",
            after_update_cb=self.after_update,
        )

        self._brightness_north = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_north,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness north",
            after_update_cb=self.after_update,
        )

        self._brightness_west = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_west,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness west",
            after_update_cb=self.after_update,
        )

        self._brightness_east = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_east,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness east",
            after_update_cb=self.after_update,
        )

        self._wind_speed = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_speed,
            sync_state=sync_state,
            value_type="wind_speed_ms",
            device_name=self.name,
            feature_name="Wind speed",
            after_update_cb=self.after_update,
        )

        self._wind_bearing = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_bearing,
            sync_state=sync_state,
            value_type="angle",
            device_name=self.name,
            feature_name="Wind bearing",
            after_update_cb=self.after_update,
        )

        self._rain_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_rain_alarm,
            device_name=self.name,
            feature_name="Rain alarm",
            after_update_cb=self.after_update,
        )

        self._frost_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_frost_alarm,
            device_name=self.name,
            feature_name="Frost alarm",
            after_update_cb=self.after_update,
        )

        self._wind_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_wind_alarm,
            device_name=self.name,
            feature_name="Wind alarm",
            after_update_cb=self.after_update,
        )

        self._day_night = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_day_night,
            device_name=self.name,
            feature_name="Day/Night",
            after_update_cb=self.after_update,
        )

        self._air_pressure = RemoteValueSensor(
            xknx,
            group_address_state=group_address_air_pressure,
            sync_state=sync_state,
            value_type="pressure_2byte",
            device_name=self.name,
            feature_name="Air pressure",
            after_update_cb=self.after_update,
        )

        self._humidity = RemoteValueSensor(
            xknx,
            group_address_state=group_address_humidity,
            sync_state=sync_state,
            value_type="humidity",
            device_name=self.name,
            feature_name="Humidity",
            after_update_cb=self.after_update,
        )

        if create_sensors:
            self.create_sensors()
Example #3
0
class Weather(Device):
    """Class for managing a weather device."""

    # pylint: disable=too-many-locals
    def __init__(
        self,
        xknx: "XKNX",
        name: str,
        group_address_temperature: Optional["GroupAddressableType"] = None,
        group_address_brightness_south: Optional[
            "GroupAddressableType"] = None,
        group_address_brightness_north: Optional[
            "GroupAddressableType"] = None,
        group_address_brightness_west: Optional["GroupAddressableType"] = None,
        group_address_brightness_east: Optional["GroupAddressableType"] = None,
        group_address_wind_speed: Optional["GroupAddressableType"] = None,
        group_address_wind_bearing: Optional["GroupAddressableType"] = None,
        group_address_rain_alarm: Optional["GroupAddressableType"] = None,
        group_address_frost_alarm: Optional["GroupAddressableType"] = None,
        group_address_wind_alarm: Optional["GroupAddressableType"] = None,
        group_address_day_night: Optional["GroupAddressableType"] = None,
        group_address_air_pressure: Optional["GroupAddressableType"] = None,
        group_address_humidity: Optional["GroupAddressableType"] = None,
        create_sensors: bool = False,
        sync_state: bool = True,
        device_updated_cb: Optional[DeviceCallbackType] = None,
    ) -> None:
        """Initialize Weather class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self._temperature = RemoteValueSensor(
            xknx,
            group_address_state=group_address_temperature,
            sync_state=sync_state,
            value_type="temperature",
            device_name=self.name,
            feature_name="Temperature",
            after_update_cb=self.after_update,
        )

        self._brightness_south = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_south,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness south",
            after_update_cb=self.after_update,
        )

        self._brightness_north = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_north,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness north",
            after_update_cb=self.after_update,
        )

        self._brightness_west = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_west,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness west",
            after_update_cb=self.after_update,
        )

        self._brightness_east = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_east,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness east",
            after_update_cb=self.after_update,
        )

        self._wind_speed = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_speed,
            sync_state=sync_state,
            value_type="wind_speed_ms",
            device_name=self.name,
            feature_name="Wind speed",
            after_update_cb=self.after_update,
        )

        self._wind_bearing = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_bearing,
            sync_state=sync_state,
            value_type="angle",
            device_name=self.name,
            feature_name="Wind bearing",
            after_update_cb=self.after_update,
        )

        self._rain_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_rain_alarm,
            device_name=self.name,
            feature_name="Rain alarm",
            after_update_cb=self.after_update,
        )

        self._frost_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_frost_alarm,
            device_name=self.name,
            feature_name="Frost alarm",
            after_update_cb=self.after_update,
        )

        self._wind_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_wind_alarm,
            device_name=self.name,
            feature_name="Wind alarm",
            after_update_cb=self.after_update,
        )

        self._day_night = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_day_night,
            device_name=self.name,
            feature_name="Day/Night",
            after_update_cb=self.after_update,
        )

        self._air_pressure = RemoteValueSensor(
            xknx,
            group_address_state=group_address_air_pressure,
            sync_state=sync_state,
            value_type="pressure_2byte",
            device_name=self.name,
            feature_name="Air pressure",
            after_update_cb=self.after_update,
        )

        self._humidity = RemoteValueSensor(
            xknx,
            group_address_state=group_address_humidity,
            sync_state=sync_state,
            value_type="humidity",
            device_name=self.name,
            feature_name="Humidity",
            after_update_cb=self.after_update,
        )

        if create_sensors:
            self.create_sensors()

    def _iter_remote_values(self) -> Iterator[RemoteValue[Any]]:
        """Iterate the devices remote values."""
        yield self._temperature
        yield self._brightness_south
        yield self._brightness_north
        yield self._brightness_east
        yield self._brightness_west
        yield self._wind_speed
        yield self._wind_bearing
        yield self._rain_alarm
        yield self._wind_alarm
        yield self._frost_alarm
        yield self._day_night
        yield self._air_pressure
        yield self._humidity

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        for remote_value in self._iter_remote_values():
            await remote_value.process(telegram)

    @property
    def temperature(self) -> Optional[float]:
        """Return current temperature."""
        return self._temperature.value  # type: ignore

    @property
    def brightness_south(self) -> float:
        """Return brightness south."""
        return (  # type: ignore
            0.0 if self._brightness_south.value is None else
            self._brightness_south.value)

    @property
    def brightness_north(self) -> float:
        """Return brightness north."""
        return (  # type: ignore
            0.0 if self._brightness_north.value is None else
            self._brightness_north.value)

    @property
    def brightness_east(self) -> float:
        """Return brightness east."""
        return (  # type: ignore
            0.0 if self._brightness_east.value is None else
            self._brightness_east.value)

    @property
    def brightness_west(self) -> float:
        """Return brightness west."""
        return (  # type: ignore
            0.0 if self._brightness_west.value is None else
            self._brightness_west.value)

    @property
    def wind_speed(self) -> Optional[float]:
        """Return wind speed in m/s."""
        return self._wind_speed.value  # type: ignore

    @property
    def wind_bearing(self) -> Optional[int]:
        """Return wind bearing in °."""
        return self._wind_bearing.value  # type: ignore

    @property
    def rain_alarm(self) -> Optional[bool]:
        """Return True if rain alarm False if not."""
        return self._rain_alarm.value  # type: ignore

    @property
    def wind_alarm(self) -> Optional[bool]:
        """Return True if wind alarm False if not."""
        return self._wind_alarm.value  # type: ignore

    @property
    def frost_alarm(self) -> Optional[bool]:
        """Return True if frost alarm False if not."""
        return self._frost_alarm.value  # type: ignore

    @property
    def day_night(self) -> Optional[bool]:
        """Return day or night."""
        return self._day_night.value  # type: ignore

    @property
    def air_pressure(self) -> Optional[float]:
        """Return pressure in Pa."""
        return self._air_pressure.value  # type: ignore

    @property
    def humidity(self) -> Optional[float]:
        """Return humidity in %."""
        return self._humidity.value  # type: ignore

    @property
    def max_brightness(self) -> float:
        """Return highest illuminance from all sensors."""
        return max(
            self.brightness_west,
            self.brightness_south,
            self.brightness_north,
            self.brightness_east,
        )

    def create_sensors(self) -> None:
        """Expose sensors to xknx."""
        for suffix, group_address in (
            ("_rain_alarm", self._rain_alarm.group_address_state),
            ("_wind_alarm", self._wind_alarm.group_address_state),
            ("_frost_alarm", self._frost_alarm.group_address_state),
            ("_day_night", self._day_night.group_address_state),
        ):
            if group_address is not None:
                BinarySensor(
                    self.xknx,
                    name=self.name + suffix,
                    group_address_state=group_address,
                )

        for suffix, group_address, value_type in (
            (
                "_temperature",
                self._temperature.group_address_state,
                "temperature",
            ),
            (
                "_brightness_south",
                self._brightness_south.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_north",
                self._brightness_north.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_west",
                self._brightness_west.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_east",
                self._brightness_east.group_address_state,
                "illuminance",
            ),
            (
                "_wind_speed",
                self._wind_speed.group_address_state,
                "wind_speed_ms",
            ),
            (
                "_wind_bearing",
                self._wind_bearing.group_address_state,
                "angle",
            ),
            (
                "_air_pressure",
                self._air_pressure.group_address_state,
                "pressure",
            ),
            (
                "_humidity",
                self._humidity.group_address_state,
                "humidity",
            ),
        ):
            if group_address is not None:
                Sensor(
                    self.xknx,
                    name=self.name + suffix,
                    group_address_state=group_address,
                    value_type=value_type,
                )

    # pylint: disable=too-many-return-statements
    def ha_current_state(
        self, current_date: date = date.today()) -> WeatherCondition:
        """Return the current state for home assistant."""
        def _get_season(now: date) -> Season:
            """Return winter or summer."""
            if isinstance(now, datetime):
                now = now.date()
            now = now.replace(year=YEAR)
            return next(season for season, (start, end) in SEASONS
                        if start <= now <= end)

        if self.wind_alarm and self.rain_alarm:
            return WeatherCondition.lightning_rainy

        if self.frost_alarm and self.rain_alarm:
            return WeatherCondition.snowy_rainy

        if self.rain_alarm:
            return WeatherCondition.rainy

        if self.wind_alarm:
            return WeatherCondition.windy

        current_season: Season = _get_season(current_date)
        _season: Season
        function: Callable[[float], bool]
        result: WeatherCondition
        for _season, function, result in ILLUMINANCE_MAPPING:
            if _season == current_season and function(self.max_brightness):
                return result

        if self.day_night is False:
            return WeatherCondition.clear_night

        return WeatherCondition.exceptional

    @classmethod
    def from_config(cls, xknx: "XKNX", name: str, config: Any) -> "Weather":
        """Initialize object from configuration structure."""
        group_address_temperature = config.get("group_address_temperature")
        group_address_brightness_south = config.get(
            "group_address_brightness_south")
        group_address_brightness_north = config.get(
            "group_address_brightness_north")
        group_address_brightness_west = config.get(
            "group_address_brightness_west")
        group_address_brightness_east = config.get(
            "group_address_brightness_east")
        group_address_wind_speed = config.get("group_address_wind_speed")
        group_address_wind_bearing = config.get("group_address_wind_bearing")
        group_address_rain_alarm = config.get("group_address_rain_alarm")
        group_address_frost_alarm = config.get("group_address_frost_alarm")
        group_address_wind_alarm = config.get("group_address_wind_alarm")
        group_address_day_night = config.get("group_address_day_night")
        group_address_air_pressure = config.get("group_address_air_pressure")
        group_address_humidity = config.get("group_address_humidity")
        create_sensors = config.get("create_sensors", False)
        sync_state = config.get("sync_state", True)

        return cls(
            xknx,
            name,
            group_address_temperature=group_address_temperature,
            group_address_brightness_south=group_address_brightness_south,
            group_address_brightness_north=group_address_brightness_north,
            group_address_brightness_west=group_address_brightness_west,
            group_address_brightness_east=group_address_brightness_east,
            group_address_wind_speed=group_address_wind_speed,
            group_address_wind_bearing=group_address_wind_bearing,
            group_address_rain_alarm=group_address_rain_alarm,
            group_address_frost_alarm=group_address_frost_alarm,
            group_address_wind_alarm=group_address_wind_alarm,
            group_address_day_night=group_address_day_night,
            group_address_air_pressure=group_address_air_pressure,
            group_address_humidity=group_address_humidity,
            create_sensors=create_sensors,
            sync_state=sync_state,
        )

    def __str__(self) -> str:
        """Return object as readable string."""
        return (
            '<Weather name="{}" '
            'temperature="{}" brightness_south="{}" brightness_north="{}" brightness_west="{}" '
            'brightness_east="{}" wind_speed="{}" wind_bearing="{}" rain_alarm="{}" '
            'wind_alarm="{}" frost_alarm="{}" day_night="{}" '
            'air_pressure="{}" humidity="{}" />'.format(
                self.name,
                self._temperature.group_addr_str(),
                self._brightness_south.group_addr_str(),
                self._brightness_north.group_addr_str(),
                self._brightness_west.group_addr_str(),
                self._brightness_east.group_addr_str(),
                self._wind_speed.group_addr_str(),
                self._wind_bearing.group_addr_str(),
                self._rain_alarm.group_addr_str(),
                self._wind_alarm.group_addr_str(),
                self._frost_alarm.group_addr_str(),
                self._day_night.group_addr_str(),
                self._air_pressure.group_addr_str(),
                self._humidity.group_addr_str(),
            ))
 def test_wrong_value_type(self):
     """Test initializing with wrong value_type."""
     xknx = XKNX()
     with pytest.raises(ConversionError):
         RemoteValueSensor(xknx=xknx, value_type="wrong_value_type")
Example #5
0
class Sensor(Device):
    """Class for managing a sensor."""
    def __init__(self,
                 xknx,
                 name,
                 group_address_state=None,
                 sync_state=True,
                 value_type=None,
                 device_updated_cb=None):
        """Initialize Sensor class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value = RemoteValueSensor(
            xknx,
            group_address_state=group_address_state,
            sync_state=sync_state,
            value_type=value_type,
            device_name=self.name,
            after_update_cb=self.after_update)

    def _iter_remote_values(self):
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    @classmethod
    def from_config(cls, xknx, name, config):
        """Initialize object from configuration structure."""
        group_address_state = config.get('group_address_state')
        sync_state = config.get('sync_state', True)
        value_type = config.get('value_type')

        return cls(xknx,
                   name,
                   group_address_state=group_address_state,
                   sync_state=sync_state,
                   value_type=value_type)

    async def process_group_write(self, telegram):
        """Process incoming GROUP WRITE telegram."""
        await self.sensor_value.process(telegram)

    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def ha_device_class(self):
        """Return the home assistant device class as string."""
        return self.sensor_value.ha_device_class

    def resolve_state(self):
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self):
        """Return object as readable string."""
        return '<Sensor name="{0}" ' \
               'sensor="{1}" value="{2}" unit="{3}"/>' \
            .format(self.name,
                    self.sensor_value.group_addr_str(),
                    self.resolve_state(),
                    self.unit_of_measurement())

    def __eq__(self, other):
        """Equal operator."""
        return self.__dict__ == other.__dict__
Example #6
0
class Weather(Device):
    """Class for managing a weather device."""

    def __init__(
        self,
        xknx: XKNX,
        name: str,
        group_address_temperature: GroupAddressesType | None = None,
        group_address_brightness_south: GroupAddressesType | None = None,
        group_address_brightness_north: GroupAddressesType | None = None,
        group_address_brightness_west: GroupAddressesType | None = None,
        group_address_brightness_east: GroupAddressesType | None = None,
        group_address_wind_speed: GroupAddressesType | None = None,
        group_address_wind_bearing: GroupAddressesType | None = None,
        group_address_rain_alarm: GroupAddressesType | None = None,
        group_address_frost_alarm: GroupAddressesType | None = None,
        group_address_wind_alarm: GroupAddressesType | None = None,
        group_address_day_night: GroupAddressesType | None = None,
        group_address_air_pressure: GroupAddressesType | None = None,
        group_address_humidity: GroupAddressesType | None = None,
        create_sensors: bool = False,
        sync_state: bool = True,
        device_updated_cb: DeviceCallbackType | None = None,
    ) -> None:
        """Initialize Weather class."""
        super().__init__(xknx, name, device_updated_cb)

        self._temperature = RemoteValueSensor(
            xknx,
            group_address_state=group_address_temperature,
            sync_state=sync_state,
            value_type="temperature",
            device_name=self.name,
            feature_name="Temperature",
            after_update_cb=self.after_update,
        )

        self._brightness_south = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_south,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness south",
            after_update_cb=self.after_update,
        )

        self._brightness_north = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_north,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness north",
            after_update_cb=self.after_update,
        )

        self._brightness_west = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_west,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness west",
            after_update_cb=self.after_update,
        )

        self._brightness_east = RemoteValueSensor(
            xknx,
            group_address_state=group_address_brightness_east,
            sync_state=sync_state,
            value_type="illuminance",
            device_name=self.name,
            feature_name="Brightness east",
            after_update_cb=self.after_update,
        )

        self._wind_speed = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_speed,
            sync_state=sync_state,
            value_type="wind_speed_ms",
            device_name=self.name,
            feature_name="Wind speed",
            after_update_cb=self.after_update,
        )

        self._wind_bearing = RemoteValueSensor(
            xknx,
            group_address_state=group_address_wind_bearing,
            sync_state=sync_state,
            value_type="angle",
            device_name=self.name,
            feature_name="Wind bearing",
            after_update_cb=self.after_update,
        )

        self._rain_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_rain_alarm,
            device_name=self.name,
            feature_name="Rain alarm",
            after_update_cb=self.after_update,
        )

        self._frost_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_frost_alarm,
            device_name=self.name,
            feature_name="Frost alarm",
            after_update_cb=self.after_update,
        )

        self._wind_alarm = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_wind_alarm,
            device_name=self.name,
            feature_name="Wind alarm",
            after_update_cb=self.after_update,
        )

        self._day_night = RemoteValueSwitch(
            xknx,
            group_address_state=group_address_day_night,
            device_name=self.name,
            feature_name="Day/Night",
            after_update_cb=self.after_update,
        )

        self._air_pressure = RemoteValueSensor(
            xknx,
            group_address_state=group_address_air_pressure,
            sync_state=sync_state,
            value_type="pressure_2byte",
            device_name=self.name,
            feature_name="Air pressure",
            after_update_cb=self.after_update,
        )

        self._humidity = RemoteValueSensor(
            xknx,
            group_address_state=group_address_humidity,
            sync_state=sync_state,
            value_type="humidity",
            device_name=self.name,
            feature_name="Humidity",
            after_update_cb=self.after_update,
        )

        if create_sensors:
            self.create_sensors()

    def _iter_remote_values(self) -> Iterator[RemoteValue[Any, Any]]:
        """Iterate the devices remote values."""
        yield self._temperature
        yield self._brightness_south
        yield self._brightness_north
        yield self._brightness_east
        yield self._brightness_west
        yield self._wind_speed
        yield self._wind_bearing
        yield self._rain_alarm
        yield self._wind_alarm
        yield self._frost_alarm
        yield self._day_night
        yield self._air_pressure
        yield self._humidity

    @property
    def unique_id(self) -> str | None:
        """Return unique id for this device."""
        return f"{self._temperature.group_address_state}"

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        for remote_value in self._iter_remote_values():
            await remote_value.process(telegram)

    @property
    def temperature(self) -> float | None:
        """Return current temperature."""
        return self._temperature.value  # type: ignore

    @property
    def brightness_south(self) -> float:
        """Return brightness south."""
        if self._brightness_south.value is not None:
            return self._brightness_south.value  # type: ignore
        return 0.0

    @property
    def brightness_north(self) -> float:
        """Return brightness north."""
        if self._brightness_north.value is not None:
            return self._brightness_north.value  # type: ignore
        return 0.0

    @property
    def brightness_east(self) -> float:
        """Return brightness east."""
        if self._brightness_east.value is not None:
            return self._brightness_east.value  # type: ignore
        return 0.0

    @property
    def brightness_west(self) -> float:
        """Return brightness west."""
        if self._brightness_west.value is not None:
            return self._brightness_west.value  # type: ignore
        return 0.0

    @property
    def wind_speed(self) -> float | None:
        """Return wind speed in m/s."""
        return self._wind_speed.value  # type: ignore

    @property
    def wind_bearing(self) -> int | None:
        """Return wind bearing in °."""
        return self._wind_bearing.value  # type: ignore

    @property
    def rain_alarm(self) -> bool | None:
        """Return True if rain alarm False if not."""
        return self._rain_alarm.value

    @property
    def wind_alarm(self) -> bool | None:
        """Return True if wind alarm False if not."""
        return self._wind_alarm.value

    @property
    def frost_alarm(self) -> bool | None:
        """Return True if frost alarm False if not."""
        return self._frost_alarm.value

    @property
    def day_night(self) -> bool | None:
        """Return day or night."""
        return self._day_night.value

    @property
    def air_pressure(self) -> float | None:
        """Return pressure in Pa."""
        return self._air_pressure.value  # type: ignore

    @property
    def humidity(self) -> float | None:
        """Return humidity in %."""
        return self._humidity.value  # type: ignore

    @property
    def max_brightness(self) -> float:
        """Return highest illuminance from all sensors."""
        return max(
            self.brightness_west,
            self.brightness_south,
            self.brightness_north,
            self.brightness_east,
        )

    def create_sensors(self) -> None:
        """Expose sensors to xknx."""
        for suffix, group_address in (
            ("_rain_alarm", self._rain_alarm.group_address_state),
            ("_wind_alarm", self._wind_alarm.group_address_state),
            ("_frost_alarm", self._frost_alarm.group_address_state),
            ("_day_night", self._day_night.group_address_state),
        ):
            if group_address is not None:
                BinarySensor(
                    self.xknx,
                    name=self.name + suffix,
                    group_address_state=group_address,
                )

        for suffix, group_address, value_type in (
            (
                "_temperature",
                self._temperature.group_address_state,
                "temperature",
            ),
            (
                "_brightness_south",
                self._brightness_south.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_north",
                self._brightness_north.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_west",
                self._brightness_west.group_address_state,
                "illuminance",
            ),
            (
                "_brightness_east",
                self._brightness_east.group_address_state,
                "illuminance",
            ),
            (
                "_wind_speed",
                self._wind_speed.group_address_state,
                "wind_speed_ms",
            ),
            (
                "_wind_bearing",
                self._wind_bearing.group_address_state,
                "angle",
            ),
            (
                "_air_pressure",
                self._air_pressure.group_address_state,
                "pressure",
            ),
            (
                "_humidity",
                self._humidity.group_address_state,
                "humidity",
            ),
        ):
            if group_address is not None:
                Sensor(
                    self.xknx,
                    name=self.name + suffix,
                    group_address_state=group_address,
                    value_type=value_type,
                )

    def ha_current_state(self, current_date: date = date.today()) -> WeatherCondition:
        """Return the current state for home assistant."""

        def _get_season(now: date) -> Season:
            """Return winter or summer."""
            if isinstance(now, datetime):
                now = now.date()
            now = now.replace(year=YEAR)
            return next(
                season for season, (start, end) in SEASONS if start <= now <= end
            )

        if self.wind_alarm and self.rain_alarm:
            return WeatherCondition.LIGHTNING_RAINY

        if self.frost_alarm and self.rain_alarm:
            return WeatherCondition.SNOWY_RAINY

        if self.rain_alarm:
            return WeatherCondition.RAINY

        if self.wind_alarm:
            return WeatherCondition.WINDY

        current_season: Season = _get_season(current_date)
        _season: Season
        function: Callable[[float], bool]
        result: WeatherCondition
        for _season, function, result in ILLUMINANCE_MAPPING:
            if _season == current_season and function(self.max_brightness):
                return result

        if self.day_night is False:
            return WeatherCondition.CLEAR_NIGHT

        return WeatherCondition.EXCEPTIONAL

    def __str__(self) -> str:
        """Return object as readable string."""
        return (
            '<Weather name="{}" '
            "temperature={} brightness_south={} brightness_north={} brightness_west={} "
            "brightness_east={} wind_speed={} wind_bearing={} rain_alarm={} "
            "wind_alarm={} frost_alarm={} day_night={} "
            "air_pressure={} humidity={} />".format(
                self.name,
                self._temperature.group_addr_str(),
                self._brightness_south.group_addr_str(),
                self._brightness_north.group_addr_str(),
                self._brightness_west.group_addr_str(),
                self._brightness_east.group_addr_str(),
                self._wind_speed.group_addr_str(),
                self._wind_bearing.group_addr_str(),
                self._rain_alarm.group_addr_str(),
                self._wind_alarm.group_addr_str(),
                self._frost_alarm.group_addr_str(),
                self._day_night.group_addr_str(),
                self._air_pressure.group_addr_str(),
                self._humidity.group_addr_str(),
            )
        )
Example #7
0
class Sensor(Device):
    """Class for managing a sensor."""
    def __init__(
        self,
        xknx: "XKNX",
        name: str,
        group_address_state: Optional["GroupAddressableType"] = None,
        sync_state: bool = True,
        always_callback: bool = False,
        value_type: Optional[str] = None,
        device_updated_cb: Optional[DeviceCallbackType] = None,
    ):
        """Initialize Sensor class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value: Union[RemoteValueControl, RemoteValueSensor]
        if value_type in [
                "stepwise_dimming",
                "stepwise_blinds",
                "startstop_dimming",
                "startstop_blinds",
        ]:
            self.sensor_value = RemoteValueControl(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        self.always_callback = always_callback

    def _iter_remote_values(self) -> Iterator["RemoteValue"]:
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    @classmethod
    def from_config(cls, xknx: "XKNX", name: str, config: Any) -> "Sensor":
        """Initialize object from configuration structure."""
        group_address_state = config.get("group_address_state")
        sync_state = config.get("sync_state", True)
        always_callback = config.get("always_callback", False)
        value_type = config.get("value_type")

        return cls(
            xknx,
            name,
            group_address_state=group_address_state,
            sync_state=sync_state,
            always_callback=always_callback,
            value_type=value_type,
        )

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        await self.sensor_value.process(telegram,
                                        always_callback=self.always_callback)

    async def process_group_response(self, telegram: "Telegram") -> None:
        """Process incoming GroupValueResponse telegrams."""
        await self.sensor_value.process(telegram)

    def unit_of_measurement(self) -> Optional[str]:
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def ha_device_class(self) -> Optional[str]:
        """Return the home assistant device class as string."""
        return self.sensor_value.ha_device_class

    def resolve_state(self) -> Optional[Any]:
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self) -> str:
        """Return object as readable string."""
        return '<Sensor name="{}" ' 'sensor="{}" value="{}" unit="{}"/>'.format(
            self.name,
            self.sensor_value.group_addr_str(),
            self.resolve_state(),
            self.unit_of_measurement(),
        )
Example #8
0
class ExposeSensor(Device):
    """Class for managing a sensor."""
    def __init__(
        self,
        xknx: "XKNX",
        name: str,
        group_address: Optional["GroupAddressableType"] = None,
        value_type: Optional[str] = None,
        device_updated_cb: Optional[DeviceCallbackType] = None,
    ):
        """Initialize Sensor class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value: "RemoteValue"
        if value_type == "binary":
            self.sensor_value = RemoteValueSwitch(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update,
                value_type=value_type,
            )

    def _iter_remote_values(self) -> Iterator["RemoteValue"]:
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    @classmethod
    def from_config(cls, xknx: "XKNX", name: str,
                    config: Any) -> "ExposeSensor":
        """Initialize object from configuration structure."""
        group_address = config.get("group_address")
        value_type = config.get("value_type")

        return cls(xknx,
                   name,
                   group_address=group_address,
                   value_type=value_type)

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        await self.sensor_value.process(telegram)

    async def process_group_read(self, telegram: "Telegram") -> None:
        """Process incoming GROUP READ telegram."""
        await self.sensor_value.respond()

    async def set(self, value: Any) -> None:
        """Set new value."""
        await self.sensor_value.set(value)

    def unit_of_measurement(self) -> Optional[str]:
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def resolve_state(self) -> Any:
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self) -> str:
        """Return object as readable string."""
        return '<ExposeSensor name="{}" ' 'sensor="{}" value="{}" unit="{}"/>'.format(
            self.name,
            self.sensor_value.group_addr_str(),
            self.resolve_state(),
            self.unit_of_measurement(),
        )
Example #9
0
 def test_wrong_value_type(self):
     """Test initializing with wrong value_type."""
     xknx = XKNX(loop=self.loop)
     with self.assertRaises(ConversionError):
         RemoteValueSensor(xknx=xknx, value_type="wrong_value_type")
Example #10
0
class ExposeSensor(Device):
    """Class for managing a sensor."""

    def __init__(self,
                 xknx,
                 name,
                 group_address=None,
                 value_type=None,
                 device_updated_cb=None):
        """Initialize Sensor class."""
        # pylint: disable=too-many-arguments
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value = None
        if value_type == "binary":
            self.sensor_value = RemoteValueSwitch(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update)
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update,
                value_type=value_type)

    def _iter_remote_values(self):
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    @classmethod
    def from_config(cls, xknx, name, config):
        """Initialize object from configuration structure."""
        group_address = \
            config.get('group_address')
        value_type = \
            config.get('value_type')

        return cls(xknx,
                   name,
                   group_address=group_address,
                   value_type=value_type)

    async def process_group_read(self, telegram):
        """Process incoming GROUP READ telegram."""
        await self.sensor_value.send(response=True)

    async def set(self, value):
        """Set new value."""
        await self.sensor_value.set(value)

    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def resolve_state(self):
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self):
        """Return object as readable string."""
        return '<ExposeSensor name="{0}" ' \
               'sensor="{1}" value="{2}" unit="{3}"/>' \
            .format(self.name,
                    self.sensor_value.group_addr_str(),
                    self.resolve_state(),
                    self.unit_of_measurement())

    def __eq__(self, other):
        """Equal operator."""
        return self.__dict__ == other.__dict__
Example #11
0
class Sensor(Device):
    """Class for managing a sensor."""
    def __init__(
        self,
        xknx: XKNX,
        name: str,
        group_address_state: GroupAddressesType | None = None,
        sync_state: bool = True,
        always_callback: bool = False,
        value_type: int | str | None = None,
        ha_value_template: Any = None,
        device_updated_cb: DeviceCallbackType | None = None,
    ):
        """Initialize Sensor class."""
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value: RemoteValueControl | RemoteValueSensor
        if isinstance(value_type, str) and value_type in [
                "stepwise_dimming",
                "stepwise_blinds",
                "startstop_dimming",
                "startstop_blinds",
        ]:
            self.sensor_value = RemoteValueControl(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address_state=group_address_state,
                sync_state=sync_state,
                value_type=value_type,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        self.always_callback = always_callback
        self.ha_value_template = ha_value_template

    def _iter_remote_values(self) -> Iterator[RemoteValue[Any, Any]]:
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    @property
    def unique_id(self) -> str | None:
        """Return unique id for this device."""
        return f"{self.sensor_value.group_address_state}"

    @property
    def last_telegram(self) -> Telegram | None:
        """Return the last telegram received from the RemoteValue."""
        return self.sensor_value.telegram

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        await self.sensor_value.process(telegram,
                                        always_callback=self.always_callback)

    async def process_group_response(self, telegram: "Telegram") -> None:
        """Process incoming GroupValueResponse telegrams."""
        await self.sensor_value.process(telegram)

    def unit_of_measurement(self) -> str | None:
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def ha_device_class(self) -> str | None:
        """Return the home assistant device class as string."""
        return self.sensor_value.ha_device_class

    def resolve_state(self) -> Any | None:
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self) -> str:
        """Return object as readable string."""
        return '<Sensor name="{}" sensor={} value={} unit="{}"/>'.format(
            self.name,
            self.sensor_value.group_addr_str(),
            self.resolve_state().__repr__(),
            self.unit_of_measurement(),
        )
Example #12
0
class ExposeSensor(Device):
    """Class for managing a sensor."""
    def __init__(
        self,
        xknx: XKNX,
        name: str,
        group_address: GroupAddressesType | None = None,
        value_type: int | str | None = None,
        device_updated_cb: DeviceCallbackType | None = None,
    ):
        """Initialize Sensor class."""
        super().__init__(xknx, name, device_updated_cb)

        self.sensor_value: RemoteValueSensor | RemoteValueSwitch
        if value_type == "binary":
            self.sensor_value = RemoteValueSwitch(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update,
            )
        else:
            self.sensor_value = RemoteValueSensor(
                xknx,
                group_address=group_address,
                sync_state=False,
                device_name=self.name,
                after_update_cb=self.after_update,
                value_type=value_type,
            )

    def _iter_remote_values(self) -> Iterator[RemoteValue[Any, Any]]:
        """Iterate the devices RemoteValue classes."""
        yield self.sensor_value

    async def process_group_write(self, telegram: "Telegram") -> None:
        """Process incoming and outgoing GROUP WRITE telegram."""
        await self.sensor_value.process(telegram)

    async def process_group_read(self, telegram: "Telegram") -> None:
        """Process incoming GROUP READ telegram."""
        await self.sensor_value.respond()

    async def set(self, value: Any) -> None:
        """Set new value."""
        await self.sensor_value.set(value)

    def unit_of_measurement(self) -> str | None:
        """Return the unit of measurement."""
        return self.sensor_value.unit_of_measurement

    def resolve_state(self) -> Any:
        """Return the current state of the sensor as a human readable string."""
        return self.sensor_value.value

    def __str__(self) -> str:
        """Return object as readable string."""
        return '<ExposeSensor name="{}" sensor={} value={} unit="{}"/>'.format(
            self.name,
            self.sensor_value.group_addr_str(),
            self.resolve_state().__repr__(),
            self.unit_of_measurement(),
        )