Chapter 14

Notifications, openings, climate, and exception handling

Notifications and climate controls turn sensor data into external effects on people or equipment. A safe flow must validate door, window, and temperature data before applying deduplication, rate limiting, manual overrides, and routing for unavailable data. This chapter generates only “candidate intents”: every notification and climate Action remains disabled, and no real notification target, device ID, or entity ID is used.

Why this chapter matters

A door or window sensor switching on might indicate ventilation, a door left open, sensor jitter, or a stale state delivered after reconnection. A temperature above a threshold might instead reflect a string-parsing error, mismatched units, stale data, or an unavailable sensor. Sending a notification for every event will soon teach users to ignore alerts; directly controlling climate equipment from bad data can waste energy, cause rapid equipment cycling, or conflict with manual settings.

This chapter uses three non-safety-critical scenarios:

  • Generate one candidate reminder after a door or window remains open, then clear the event when it closes; do not control locks or alarms.
  • Generate a climate recommendation when an indoor value exceeds an approved threshold, but still check doors, windows, mode, and manual override before the final decision; do not set real equipment directly.
  • Route unknown, unavailable, non-numeric, expired, or excessively frequent notification data to exception paths; never treat an exception as an actionable condition.
This chapter does not send notifications or control climate equipment. All Home Assistant listener, query, entity, and Action nodes remain disabled. The placeholders PLACEHOLDER_NOTIFY_ACTION, PLACEHOLDER_CLIMATE_ENTITY, and PLACEHOLDER_OPENING_ENTITY must not be replaced with real values and deployed directly.
Installing the palette package is not the same as installing the HA custom integration. General nodes such as Events: calendar, Tag, Zone, and Action connect through the Home Assistant Server WebSocket/API. Sentence and HA entity nodes such as Select, Binary Sensor, Button, Number, Sensor, Switch, and Text additionally require the hass-node-red custom integration to be installed and loaded in Home Assistant. This chapter assumes no particular version; disable the relevant branches when the integration is absent. Review the connection and node classifications in Chapter 8 first.

Events, exceptions, reminders, and controls are separate paths

PathInput conditionsPermitted resultProhibited shortcut
State eventA known new state from an opening or climate entityCreate or update a candidate eventCall an Action as soon as an event arrives
Data exceptionunknown, unavailable, null, non-numeric, or expiredRedacted diagnostics and health countersConvert the exception to 0, false, or closed
NotificationEvent persists, deduplication passes, and rate quota remainsCandidate notification intentUse a dynamic upstream target or retry indefinitely
Climate controlValue, unit, openings, mode, and override are all validCandidate control intentOperate equipment based on one temperature alone

Notification is one use of an Action, but the action name, available targets, data schema, and actual response depend on the notification integration installed in Home Assistant. Do not claim that every notification action accepts the same fields, or interpret “the node reported no error” as proof that the recipient received anything. Climate actions likewise have no universal success response across integrations. Validate against the approved integration’s documentation and subsequent state, and limit retries.

Users can change climate settings through Home Assistant, an equipment panel, a remote control, or another automation. A manual override must be a first-class flow state, not an error. While an override is active, the flow may observe and report diagnostics but must not issue a counteracting control intent. Re-evaluate when the override expires; do not automatically restore the old setting.

Eight steps to a safe specification

  1. Define data contracts.

    List each source’s entity type, raw state, attributes, unit, update time, and allowed values. Use whole-value placeholders; never put real household IDs or notification targets in documentation, flows, or Debug output.

  2. Route exceptions first.

    Send unknown, unavailable, null, empty strings, NaN, Infinity, unit mismatches, and values outside a physically reasonable range to INVALID. Only explicitly validated values may enter opening or climate logic.

  3. Add duration and recovery events.

    An opening must remain open for an approved duration before a reminder is created. Closing it cancels unsent candidates and ends the event. Use hysteresis for climate thresholds to prevent repeated switching at the boundary.

  4. Design deduplication keys and rate limits.

    Build the deduplication key from an anonymous area, event type, and event generation. Define finite windows for each event’s cooldown, a per-area limit, and a global limit. Count excess notifications; do not queue a backlog of old notifications for later delivery.

  5. Check dependency states.

    Before a climate candidate reaches its deadline, use Current State to recheck the indoor value, openings, equipment mode, data freshness, and manual override. Any query failure means no control.

  6. Create only a disabled Action.

    Following 07-action.json, review the action, target, data, queue, and Block Input Overrides settings. Keep d: true, use placeholders only for the target, and leave the Action disconnected from upstream nodes.

  7. Run matrix tests with synthetic data.

    Cover opening jitter, recovery, duplicates, notification bursts, non-numeric values, unit errors, unavailable states, manual overrides, restarts, and simulated Action failures. Tests use only manual Inject and Debug nodes, with no external connections.

  8. Approve observation and action separately.

    If a test environment is needed, approve read-only monitoring first. Review the test notification target and climate test equipment separately. Production or real-home targets are outside this chapter’s test scope.

Notification Action: data, deduplication, and rate limits

Candidate notification data

First create the following abstract object in the pure message layer; do not pass it directly to an Action:

{
  "kind": "OPENING_STILL_OPEN",
  "anonymous_area": "PLACEHOLDER_AREA_ALIAS",
  "event_generation": "PLACEHOLDER_EVENT_GENERATION",
  "severity": "informational",
  "observed_at": "PLACEHOLDER_ISO_TIMESTAMP"
}

The transformation layer then builds data according to the official schema for the approved notification action. Ordinary use cases may require text, but do not assume field names or advanced data are portable across integrations. The examples provide no recipient, device, group, URL, image, or executable button. Message content should not reveal that “no one is home,” a precise address, an opening ID, or a person’s name.

Action node safeguards

  • Fix action to PLACEHOLDER_NOTIFY_ACTION; do not allow dynamic overrides from msg. Enable Block Input Overrides.
  • Fix target to PLACEHOLDER_NOTIFY_TARGET; do not use a real mobile-app device ID, person, area, label, or group.
  • Build data from an allowlist; do not merge the entire msg.payload, context, or original event.
  • A Queue policy is not a rate limit. Items queued during disconnection may all be delivered after recovery. Notification flows should generally discard expired intents rather than use queue all.
  • Action output represents only the result of the node’s call path. It does not prove that every notification service returns the same content or that an endpoint displayed the notification.
RuleExampleWhen exceeded
Event deduplicationSend at most one reminder for an opening generationDiscard the duplicate and increment an anonymous counter
Event cooldownDo not repeat reminders while the opening remains openCreate a new generation only after a confirmed recovery
Area rateLimit each anonymous area within a time windowDo not send; mark rate_limited
Global rateProtect recipients when multiple sensors failTrip the notification Action’s circuit breaker; retain a summary
Expiration windowAn old event exceeds the tolerated age after reconnectionDo not resend; record only a recovery summary

Never retry notification failures indefinitely. Set a maximum attempt count, backoff, and total time limit; retries remain subject to the same deduplication key and global limit. Safety-critical alerting requires a dedicated, monitored channel. The general notifications in this chapter offer no life-safety assurance.

Openings: sustained activity, recovery, and privacy

Doors and windows are usually represented by binary sensor entities, but you must verify the actual state and device class for your integration. Do not infer from an icon or name that on necessarily means open. Before defining the mapping, observe a known-open and known-closed state once in an isolated environment. This chapter continues to use PLACEHOLDER_OPENING_ENTITY instead of a real ID.

Known CLOSED → known OPEN
  → debounce → Create generation → Wait for duration
  → Recheck and still OPEN → Notification deduplication / rate limit → Candidate notification → Disabled Action

OPEN → CLOSED
  → Cancel unexpired candidate → Mark resolved
  → Create a candidate recovery notification only if an alert was actually sent earlier

Any state → unknown / unavailable / missing data
  → Cancel control intent → anomaly branch → Do not claim that the door is closed

If the opening closes within the required duration, do not send a “still open” reminder. If it closes after a reminder was generated, product rules determine whether a recovery notification is needed. A recovery notification shares the original event’s correlation key so that it is not treated as a new alert. After Node-RED or Home Assistant restarts, first query the current state and the freshness of last_changed; do not replay an old generation from context.

Opening events can reveal arrivals, departures, and daily routines. Debug output should contain only the anonymous area, OPEN/CLOSED/INVALID, a duration band, and the decision. Do not log opening names, user IDs, precise timelines, or raw attributes. Adding Zone, Tag, or Sentence to represent “someone approaching” increases the risk: Zone involves location, Tag may include a tag, device, or user ID, and Sentence may contain the original utterance. Only after separate approval may these nodes output an anonymous Boolean condition, and they must remain disabled.

Useful but conservative roles for Calendar, Zone, Tag, and Sentence

  • Calendar can produce an “approved time window” condition, but its approximately 15-minute polling interval and susceptibility to last-minute changes make it unsuitable as the sole security condition.
  • Zone can produce an anonymous enter/leave condition, but location drift or stale coordinates must not directly dismiss an opening reminder.
  • Tag can provide a manual confirmation input, but a tag ID is not identity verification and must not directly trigger unlocking or climate control.
  • Sentence can accept a “remind me later” intent. Because response mode sends an external response, keep it disabled; do not assume that speech recognition or the response will succeed.

Climate: numeric validation, hysteresis, and manual overrides

Six gates before comparing numeric values

  1. The value exists and is not unknown, unavailable, null, or an empty string.
  2. Explicitly convert it to a finite number; reject NaN, Infinity, and strings containing units.
  3. The unit matches the flow configuration; do not compare Celsius with Fahrenheit without conversion.
  4. The value falls within a reasonable range for the sensing purpose; an abnormally high or low value must not directly trigger control.
  5. last_updated or the receipt time is within the freshness threshold; a stale value loaded after reconnection is not a new event.
  6. The source is on an approved exact-match list and was not accidentally included by a substring or regular-expression match.

Do not use one threshold to switch back and forth. For example, a high threshold may generate a “cooling needed” candidate, which is cleared only after the value drops below a lower recovery threshold and remains there for a defined duration. Preserve the current decision between the two thresholds. Exact values depend on the space, equipment, health requirements, and energy policy; this chapter provides no temperature that can be applied directly.

Dependency checks before candidate control

  • Every relevant opening has a known CLOSED state; any OPEN or INVALID state blocks climate control.
  • The climate entity exists and is not unavailable; its current mode and available attributes match the integration documentation.
  • No manual override is active; if a user has just changed a setting, the flow must not counteract it.
  • A recent similar intent is not in cooldown, and the equipment is not at risk of short cycling.
  • The Action and data have been checked against the entity’s supported capabilities; do not assume a generic service response.
Never skip the final state validation. Opening and temperature events may be out of sync. Run Current State queries before a candidate message reaches the Action. If any dependency is unavailable or stale, or any query fails, output NO_ACTION_INVALID_DEPENDENCY.

Manual overrides and recovery

Manual-override data must include at least an anonymous control scope, direction, creation time, expiration time, and source category, and the override must have a maximum lifetime. While it is active, the flow may record “the candidate that would have been generated without the override” to help tune rules, but it must not send an Action. Query again when the override expires; do not replay candidates accumulated during the override. If Node-RED cannot confirm override state after a restart, the fail-closed default is no control.

The real Action remains disabled and uses PLACEHOLDER_CLIMATE_ACTION and PLACEHOLDER_CLIMATE_ENTITY. Its data contains no real setpoint; PLACEHOLDER_APPROVED_VALUE only marks a value awaiting approval. Any equipment operation requires separate validation in a non-production environment, against a limited target, with a manual abort available.

Exception paths and HA entity nodes

In 0.80.3, ordinary WebSocket nodes can read existing Home Assistant entities. With an Entity config and the separately installed hass-node-red custom integration, Node-RED can also create or interact with exposed entity nodes. Installing the palette package alone does not satisfy this prerequisite. These nodes are not “safer variables”: they may accept external operations from Home Assistant or update state there, so keep all of them disabled during testing. The following table summarizes nodes relevant to this scenario:

NodeRole in this chapterSafety boundary
Events: calendarCandidate condition for an approved time windowPolling delay and schedule privacy; must not be the only security condition
SentenceCandidate input for manually postponing a reminderThe original utterance and device/response ID are sensitive; a response has external side effects
TagCandidate input for manual confirmationTag/device/user IDs are sensitive; a scan is not strong authentication
ZoneAnonymous location conditionCoordinates are sensitive and may drift; never control a lock or climate equipment directly
Select entityOverride interface exposing limited optionslisten/get/set behavior depends on configuration; accept only listed options and keep the node disabled
Binary Sensor entityExpose an anonymous exception flagInput updates the integration entity; do not coerce unknown to false
Button entityManual candidate-confirmation buttonA press triggers the flow but is not authorization; do not connect it directly to an Action
Number entityExpose a constrained candidate thresholdValidate the number, bounds, and unit; set has side effects
Sensor entityPublish an anonymous health summaryMessages may override state/attributes; do not publish sensitive raw data
Switch entityTime-limited intent to enable automationWith no persisted value, state storage defaults to enabled; add a fail-closed startup gate
Text entityConstrained, non-sensitive annotationFor listen/get/set, validate length and content; never carry secrets or arbitrary actions

Unified exception envelope

{
  "category": "INVALID_STATE_OR_VALUE",
  "source_alias": "PLACEHOLDER_SOURCE_ALIAS",
  "observed_at": "PLACEHOLDER_ISO_TIMESTAMP",
  "decision": "NO_ACTION",
  "detail_code": "PLACEHOLDER_NON_SENSITIVE_CODE"
}

The exception envelope contains no raw state, attributes, location, schedule, utterance, notification target, or device ID. Catch and Status nodes can collect node errors and status, but must never create a “resend the Action on error” loop. When a counter reaches its threshold, trip the circuit for that path and restore it only after manual review.

Fail-closed defaults

  • Notification integration unavailable: do not queue indefinitely or switch to an unapproved target.
  • Climate equipment unavailable: do not control it or pretend that it reached the setpoint.
  • Opening sensor unavailable: do not treat it as closed; block climate candidates.
  • Entity config/integration not loaded: disable the exposed-entity path without changing the core no-action policy.
  • Reconnect or restart: clear expired candidates and query again; do not send old notifications or replay old controls.

Troubleshooting

  • Repeated notifications for the same opening event: Disable the notification Action. Check that the generation remains unchanged until CLOSED, that the deduplication key contains no unstable timestamp, and that a persistent event does not mistakenly create a new key. After correcting the flow, use a synthetic event to verify that one OPEN generation produces at most one candidate.
  • Many old notifications after reconnection: A Queue or retry path may retain expired intents. Add a maximum event age, a global rate limit, and a recovery circuit breaker. Record only an anonymous summary of expired events; do not resend them.
  • Reversed temperature comparisons: Check string-to-number conversion, Celsius versus Fahrenheit, NaN handling, the threshold, and hysteresis direction. Retain the raw value only for short-term, controlled diagnostics, and clear it immediately after confirmation.
  • An open door or window still produces a climate candidate: Confirm the integration’s on/off semantics, device-class mapping, Current State query output, and Switch rules. Block both OPEN and INVALID, not merely the literal string on.
  • Manual override ignored: Check the override scope, expiration time, time zone, and persistence across restarts. Check override state both before candidate generation and immediately before the Action. If it cannot be read, do not control.
  • The Action node reports no error, but no notification arrives: Do not infer a generic success response. Keep the node disabled and use the specific notification integration’s documentation to verify the action, target, data, authorization, and endpoint state. Do not repeatedly test delivery against a real target.
  • A Number/Select/Text entity receives an unexpected value: Disable the node and check its mode, Entity config, and message overrides. Define allowlists for options, ranges, lengths, and types; these entities are not trusted input boundaries.

Pinned sources and related nodes

This chapter covers 11 related nodes: Events: calendar, Select entity, Sentence, Tag, Zone, Binary Sensor entity, Button entity, Number entity, Sensor entity, Switch entity, and Text entity. The table above summarizes their roles and boundaries. Sentence and the seven entity nodes require the hass-node-red custom integration, and every writable, triggered, or externally responding mode must remain disabled. Action behavior depends on context; see the version-specific fields in Safe Example 07. Do not assume that notification or climate integrations share common data or responses.

FAQ

Can an unavailable door or window be treated as closed to avoid repeated reminders?
No. unavailable means unknown, not closed. Cancel the control intent, block the climate path, and route the condition to exception diagnostics. Any separate health reminder remains subject to deduplication and rate limits.
Can notification Action data be merged directly with msg.payload?
This is not recommended. Upstream data may include a target, sensitive content, or fields the integration does not accept. Rebuild data from an allowlist according to the approved action schema, and enable Block Input Overrides.
Can Queue all prevent missed notifications during a disconnection?
It provides neither a reliable notification guarantee nor a rate limit. Delivering accumulated messages after recovery can cause a notification storm. General state reminders should have an expiration window and discard expired intents.
Can a climate action run as soon as the temperature exceeds a threshold?
No. First validate the value, unit, reasonable range, freshness, hysteresis, openings, equipment state, cooldown, and manual override. If any input is ambiguous, do not control.
Can a Switch entity serve as a safe master switch for automation?
No. It can express enablement intent, but it is not access control. In 0.80.3, when no persisted value exists, state storage initializes as enabled, so you cannot claim that the default is off. Add an explicit fail-closed startup gate that opens only after state loading, authorization, and dependency checks have completed, then check it again before the Action.
Does Action output mean that a phone displayed the notification or the equipment finished its operation?
No general claim is possible. Responses differ by action and integration, and completion of the node call does not necessarily mean endpoint completion. Verify against the specific integration documentation and subsequent state, and never retry indefinitely.