Skip to content

Monitor Sensor Thresholds

Send a notification whenever a sensor value rises above a configured limit — useful for temperature, humidity, CO2, or any numeric sensor in Home Assistant.

The code

from hassette import App, AppConfig, C, D, states


class ThresholdConfig(AppConfig):
    entity_id: str = "sensor.living_room_temperature"
    threshold: float = 28.0
    notify_target: str = "mobile_app_my_phone"


class SensorThresholdApp(App[ThresholdConfig]):
    """Alert when a sensor value exceeds a configured threshold."""

    async def on_initialize(self) -> None:
        await self.bus.on_state_change(
            self.app_config.entity_id,
            handler=self.on_threshold_exceeded,
            changed_to=C.Comparison("gt", self.app_config.threshold),
            name="threshold_monitor",
        )

    async def on_threshold_exceeded(
        self,
        new_state: D.StateNew[states.SensorState],
        entity_id: D.EntityId,
    ) -> None:
        value = new_state.value
        unit = new_state.attributes.unit_of_measurement or ""
        name = new_state.attributes.friendly_name or entity_id

        self.logger.warning("%s crossed threshold: %s%s", name, value, unit)

        await self.api.call_service(
            "notify",
            self.app_config.notify_target,
            title="Sensor Alert",
            message=f"{name} is now {value}{unit} (threshold: {self.app_config.threshold}{unit})",
        )

How it works

  • Typed configThresholdConfig exposes entity_id, threshold, and notify_target as environment-backed settings. Override any of them per-instance without touching the code.
  • Threshold filterC.Comparison("gt", threshold) is passed to changed_to, so the handler only fires when the new state value is greater than the configured limit. Events below the threshold are dropped before the handler runs.
  • DI extractionD.StateNew[states.SensorState] gives a typed state object. D.EntityId provides the entity ID as a plain string for logging.
  • Attributesnew_state.attributes.unit_of_measurement and friendly_name are read directly from the typed model, keeping the notification message readable without manual string parsing.
  • Notificationapi.call_service("notify", ...) sends the alert via any Home Assistant notify target (mobile app, persistent notification, etc.).

Variations

Lower threshold (below-limit alert): Change "gt" to "lt" to alert when the value drops below the limit — for example, alerting when battery level or water pressure falls too low.

Hysteresis to prevent alert storms: Subscribe to a second listener with changed_to=C.Comparison("le", threshold) that sets a flag when the sensor recovers. Check the flag in on_threshold_exceeded and skip the notification if the sensor has not yet recovered, preventing repeated alerts while the value hovers near the threshold.

Multiple sensors: Register the same handler for several entities using a glob pattern ("sensor.temp_*") or call on_state_change once per entity inside a loop over a list[str] config field.

See also

  • Filtering — full reference for C.Comparison and all other conditions
  • Dependency Injection — how D.StateNew and D.EntityId work
  • States — typed state models and the SensorState attributes