Chapter 12

Home Assistant events, devices, time, and scheduled triggers

The same “trigger” may originate from the event bus, an entity state, device automation, or a local timer. These sources differ in their data, reconnection behavior, and side effects. Using the pinned HA WebSocket 0.80.3 source, this chapter defines their boundaries one by one and outlines a safe validation approach in which only Debug nodes are connected and all HA nodes remain disabled.

Why this chapter matters

Judging by node names alone, it is easy to assume that Events: all, Device, and Time all simply “send a message when something happens.” In practice, Events: all subscribes to Home Assistant events or WebSocket client lifecycle events; Device can operate in Trigger or Action mode; Time schedules messages from the state or an attribute of a specified entity; and Calendar polls a calendar and schedules timers. Choosing the wrong entry point can create a flood of events, repeat operations after reconnection, or turn a read-only flow into one that affects devices.

Every configuration in this chapter is a non-executable specification. All Events, Device, Calendar, Tag, Webhook, Zone, Sentence, Time, Time entity, and Fire Event nodes must remain disabled. Connect outputs only to Debug, and configure Debug to show only the necessary masked fields. Do not enter real webhook IDs, device IDs, tag IDs, person locations, sentences, or calendar content.

If you only need to detect an entity changing from off to on, start with Chapter 9, Events: state. If you need to query the current state after a trigger, use Chapter 10, Current State. The nodes in this chapter do not replace state nodes; they handle events and scheduling sources outside the entity-state model.

Distinguish between two integration layers first: general nodes such as Events: all, Events: calendar, Tag, Time, Zone, and Fire Event use the package’s Home Assistant Server WebSocket/API connection. In 0.80.3, Sentence, Webhook, Time entity, and Device automation also require the hass-node-red custom integration to be installed and loaded separately in Home Assistant. Installing only the Node-RED palette package is not enough, and you must not assume a custom integration version. Review Chapter 8 first for the overall classification and Server connection.

Do not mix the four trigger models

ModelObserved sourceSuitable usePrimary boundary
Event busHome Assistant event type and event dataDiscrete events that are not the state of a single entityA blank event type may receive a very high volume of events; event data may contain identifying information
Entity stateThe old_state and new_state of state_changedState transitions for doors, windows, lights, sensor readings, and similar entitiesAttribute updates may also create events; unknown and unavailable require separate handling
Device automationA device trigger/action supplied by a specific integrationButton gestures or device capabilities explicitly exposed by an integrationCapabilities depend on the integration and device; every device is not guaranteed to offer the same options
Time schedulingA time value in an entity, a calendar item, or a Node-RED timerGenerating a message at a future timeTime zones, daylight saving time, restarts, expired times, and data updates can all change the result

An event name is not an entity ID. An event type selects event-bus messages, an entity ID identifies a state, a device ID identifies an entry in the device registry, and tag IDs and webhook IDs occupy different identifier namespaces again. Do not interchange identifiers because their strings look similar, and do not treat a UI display name as a stable ID.

Receiving and sending also carry different risks. Events: all, Tag, and Zone are input nodes. Fire Event sends an event to Home Assistant. Device in Action mode sends a device action. Sentence in response mode—and a trigger-mode Sentence configured with a fixed response or timeout fallback—responds to the voice assistant. Time entity in set mode updates an entity value. In a test flow, every sending or response configuration must remain disabled and have no incoming connection.

Validate in six steps by observing, not executing

  1. Write one trigger contract.

    Record the source, narrowest filter, permitted fields, disconnection behavior, and duplicate-handling policy. Use whole-value placeholders such as PLACEHOLDER_EVENT_TYPE, PLACEHOLDER_ENTITY_ID, and PLACEHOLDER_DEVICE_ID; never include real environment data.

  2. Choose the narrowest node.

    Use Events: state for a state transition, Device Trigger only for an existing device-automation capability, Time for a time stored in an entity, and Calendar for a calendar item. Do not use Events: all with a blank event type as a universal entry point.

  3. Create an isolated copy and disable the HA nodes.

    In a test workspace, draw only “disabled trigger node → field allowlist → Debug.” Leave every sending node unwired, especially Device Action, Fire Event, Sentence response, a Sentence trigger with a fixed/fallback response, Time entity set, and any downstream Action.

  4. Test branches with synthetic messages.

    Use only core Inject/Change nodes to create data containing no real IDs. Check normal, duplicate, missing-field, unknown, unavailable, and expired-time branches. This tests data routing; it does not reproduce Home Assistant’s complete semantics for each event.

  5. Review reconnection and time behavior individually.

    Document the expected behavior for deployment, Node-RED restart, Home Assistant restart, WebSocket disconnection, midnight rollover, and DST transitions. Every uncertain case must take the “no action” branch; do not validate it by resending a real operation.

  6. Observe first; seek separate approval later.

    If your organization permits a connection to a test Home Assistant instance, enable only one read-only trigger node at a time and keep downstream Actions disabled. Verify only masked event counts and timestamps. Production actions require a separate change review; this chapter does not authorize enabling them.

Events: all, Sentence, and Fire Event

Events: all: use it only with an explicit event type

In 0.80.3, Events: all accepts an Event Type or, when left blank, receives all events. Both the editor and official documentation explicitly warn that a blank value can overwhelm the WebSocket message queue. Event data must be a JSON object; at runtime, it is matched as a subset of the event content. This matching can further narrow a known event, but it is not a substitute for input validation.

The special event type home_assistant_client receives client lifecycle events, but those messages indicate only a data-loading or client phase. They do not mean that a device state satisfies a business condition. Do not build a gate that waits for connected. Instead, use the lifecycle events actually emitted by the pinned version to update flow health, then query any required state again. Never send a catch-up action directly from a lifecycle event.

0.80.3 version detail: the controller also contains connecting, connected, disconnected, and error handlers, but actual event registration wires up only states_loaded, services_loaded, running, and ready. The unwired connected handler is not part of this node’s output contract. “Output only after Home Assistant is running” suppresses ordinary events, but client events are emitted separately, so reconnection requires a separate branch.
Reconnection gate: even after using the actually wired running/ready events as health signals, query required entities with Current State, check data timestamps and deduplication keys, and stop if state is missing. Lifecycle events may update flow health only; they must not directly trigger catch-up operations.

Sentence: triggers and responses travel in opposite directions

The Sentence node supports trigger and response modes and requires the separately installed hass-node-red custom integration. In trigger mode, the Home Assistant integration sends the sentence, match result, device ID, and response ID; the output message includes the internal _sentence_response_id. Response mode reads that ID and sends a dynamic response back to the integration. Sentences can reveal household activities and device locations, so Debug must retain only a classification result—not the original sentence or device ID.

A trigger does not need a response node to produce an external response: a fixed response is sent directly, and dynamic mode can send a fallback response after a timeout. For observation only, leave the fixed response and fallback blank or configured not to respond, and do not connect a response-mode node. A node is not purely input merely because mode=trigger. If a response ID expires or is lost, end that invocation; never retry with an old ID.

Fire Event: an output, not a test button

When Fire Event receives a message, it sends fire_event over WebSocket. The event type can come from configuration or the message, and data can be evaluated with a template or JSONata. Other Home Assistant automations may listen for that event, so even “just a custom event” can trigger an alarm, notification, or device control. The example contains only PLACEHOLDER_EVENT_TYPE and blank data. Keep the node disabled, do not connect an Inject node, and do not deploy it to try the button.

Identifier boundaries for Device, Tag, Webhook, and Zone

Device: verify the custom integration and device capability first

The Device node offers Trigger and Action modes. This device-automation path requires the hass-node-red custom integration to be loaded in Home Assistant. Trigger mode registers through the integration and emits a message when the device trigger fires. After receiving a Node-RED message, Action mode sends the configured action and capabilities to Home Assistant. Available triggers, actions, and capabilities come from the integration to which the device belongs; they are not a common list that 0.80.3 provides for every device. You therefore cannot claim that every sensor supports “single press,” every light has the same brightness field, or different brands produce identical data.

If the UI does not show an expected device capability, first confirm the device registry entry and integration support in Home Assistant. Do not hand-write a guessed object. A test should contain only a disabled Device Trigger; leave Device Action unwired. For actual service control, follow Chapter 11, Action node to review the action, target, and data.

Tag: both tags and scanners have sensitive IDs

Tag can listen for one tag or all tags and can restrict which scanning devices are accepted. When no devices are specified, 0.80.3 accepts any scanning device. Output can include the tag name, tag ID, device ID, and user ID. Those fields can reveal people and locations. Apply the narrowest filter and emit only an anonymous purpose code; never use “all tags” in a production flow.

Webhook: knowing the ID may be enough to invoke it

The Webhook node requires the separately installed hass-node-red custom integration in Home Assistant. It registers a webhook ID and the permitted POST, PUT, GET, and HEAD methods with that integration, then receives payload, headers, and params. It is not a Node-RED HTTP In node and does not imply authenticated user access. Actual reachability depends on Home Assistant’s network exposure and webhook mechanism. Do not expose Home Assistant for convenience, and never put a webhook ID in a tutorial, screenshot, repository, or Debug output.

This chapter does not create an endpoint. PLACEHOLDER_WEBHOOK_ID is only a non-resolvable marker. Keep the Webhook node disabled, enter no real value, run no curl test, and display no external URL. If a future requirement is approved, perform a separate threat model and define method allowlists, source validation, rate limits, and a revocation procedure.

Zone: crossing a boundary does not guarantee real-time presence

Zone compares the old and new coordinates of a person or tracked entity with zone coordinates to detect enter, leave, or both. It emits no output without old_state/new_state, location data, or zone data. Location latency, GPS drift, and radius boundaries can cause flapping, and location data is highly sensitive. A safe flow emits only “anonymous zone state changed,” adds a duration threshold or cooldown, and never stores coordinates.

Time and Time entity: scheduling and writable time entities

The Time node reads a property from a specified entity; the default is state. This chapter guarantees only a previously validated date string—preferably ISO 8601 with an offset—or HH:MM[:SS]. If an upstream value is a numeric epoch, explicitly convert it to an ISO string before passing it to Time; do not pass the number directly. The node applies a positive or negative offset, can optionally randomize within the offset range, and can repeat daily on selected weekdays. It rebuilds the timer when the entity state or attribute changes. Treat unavailable values, type mismatches, invalid dates, nonnumeric offsets, and a repeating schedule with no selected weekday as configuration or data errors that produce no output.

Input conditionSafe interpretationResponse
One-time value is in the pastIt must not run immediately as a catch-upRecord an expired status; even when ignoring the warning, do not treat the value as a catch-up
Daily repeating HH:MMThe schedule uses the runtime environment’s local timeManually verify the next run before and after a DST transition
Negative offset with randomizationIt may be constrained to avoid a time earlier than nowDo not use it for legally regulated or precision-critical times
Entity update or reconnectionThe schedule may be recalculatedCreate a downstream deduplication key from the event date and purpose
unknown/unavailableIt is not a valid timeTake the error branch; do not retain the previous value

DST is not simply a one-hour addition or subtraction. Some local times do not exist on a particular day; others occur twice. Test in isolation using the actual time zones of Home Assistant, the Node-RED host, and the source calendar. Record the expected behavior for both the spring-forward and fall-back transitions, and make downstream actions idempotent. When you need an absolute time, retain an ISO timestamp with an offset and convert it only for display; do not mix it with time-zone-free strings.

Time entity is a separate node. It requires the hass-node-red custom integration in Home Assistant and works with an Entity config to expose a time value to Home Assistant. Its modes are listen, get, and set. set is a write operation; in 0.80.3, it validates 24-hour HH:MM[:SS] and adds seconds when omitted. listen and get process the existing value. It is not a replacement for the ordinary WebSocket Time trigger. Keep all three modes disabled in testing, and in particular do not connect set to any untrusted message.

Calendar scheduling, restarts, and deduplication

Events: calendar selects one calendar entity and triggers at its start or end, adjusted by a positive or negative offset. Filter performs a substring match against the summary. The 0.80.3 source polls about every 15 minutes and uses a 1-minute overlap between query windows. After retrieving events, it schedules precise timers in an in-memory queue and reduces duplicates with a cache of emitted events. It aligns all-day events to midnight before applying the offset.

These mechanisms improve ordinary scheduling, but they do not mean “never miss and never duplicate.” A last-minute addition or modification between polls may not be discovered in time. Restarting Node-RED clears in-memory timers and the emitted-event cache, and the rescan result depends on the query window at that time. Network errors are retried, but no usable events remain if that polling round ultimately fails. Your business rules must define the recovery policy; do not claim that the node guarantees catch-up delivery.

A safe “meeting reminder” specification

  • Keep the Calendar node disabled and set calendar to PLACEHOLDER_CALENDAR_ENTITY. Use a classification term containing no name or location as the Filter.
  • Retain only an anonymized UID hash, event start time, and classification in output; do not record description, location, or the original summary.
  • Build a deduplication key from “anonymous UID + occurrence date + reminder type.” Give the key a reasonable expiry; do not retain schedule details indefinitely.
  • Send events that exceed the lateness tolerance, fail time parsing, arrive just after reconnection, or lack required data to a bounded diagnostic Debug—not to a notification Action.
  • Keep the real notification node disabled until the rate-limit and error-branch checks in Chapter 14, notifications and error branches receive separate approval.

If a schedule only needs to wait for an entity condition rather than a calendar time, use the Wait Until design in Chapter 13. These approaches respectively answer “when is the scheduled time?” and “when does the condition become true?” Do not use a long Delay to guess an external state.

Troubleshooting: disable first, then inspect the source

  • Events: all produces a message flood: disable the node immediately. Check whether Event Type is blank and whether the event data JSON actually narrows the match. Clear Debug, then review only the known PLACEHOLDER_EVENT_TYPE; do not use all-events mode to search for an answer.
  • The Device list lacks an expected trigger/action: the current integration or device usually does not expose that capability. Confirm the Home Assistant device registry entry, integration status, and 0.80.3 compatibility. Do not copy another device’s configuration or guess a capability by hand.
  • Time reports invalid, unavailable, or in the past: check the property path, original type, time zone, offset, and weekday selection. Route invalid data to an error branch; do not reuse an old time or mistake ignore past date for catch-up execution.
  • Calendar misses a last-minute change: compare the event update time with the approximately 15-minute polling boundary and check whether the API query exhausted its retries. If the requirement cannot tolerate polling latency, stop the automation and select a different architecture instead of shortening an undocumented internal constant.
  • An event appears duplicated after reconnection: compare the source event ID, business deduplication key, running timestamp, and deployment time. Block every Action first, then determine whether the source resent the event, states reloaded, or the flow restarted. Do not delete deduplication data merely to try again.
  • Webhook, Tag, Zone, or Sentence Debug output exposes data: disable the flow and delete that Debug message. Rotate an exposed webhook ID; mask tag, device, and user IDs, coordinates, and original sentences. Follow the incident-reporting procedure, and never paste raw output into a public issue.

Pinned sources and related nodes

This chapter uses the exact pinned commit of HA WebSocket 0.80.3 as its version boundary. Official node documentation supplements the operational semantics; if rolling documentation has changed, use the pinned source to determine this chapter’s baseline.

This chapter covers 10 related nodes: Device, Events: all, Events: calendar, Fire Event, Sentence, Tag, Time, Webhook, Zone, and Time entity. Fire Event, Device Action, Sentence response, a Sentence trigger with a fixed/fallback response, and Time entity set all have external side effects and must remain disabled in every example. Device automation, Sentence, Webhook, and Time entity also require the custom integration.

FAQ

Can I leave Event Type blank in Events: all to explore events?
This is not recommended. Version 0.80.3 explicitly warns that receiving all events can overwhelm the WebSocket message queue, and event data may contain sensitive information. First identify the exact event type from Home Assistant developer documentation or in an isolated environment, then observe it through a minimal field allowlist.
Why does my Device node lack options shown in another tutorial?
Device capabilities come from the Home Assistant integration and the actual device; every integration does not expose the same triggers, actions, or capabilities. Do not invent settings. When a capability is absent, use a verifiable entity state or a separately approved Action.
Can I use home_assistant_client connected to build a reconnection gate?
No. In 0.80.3, Events: all actually wires up only states_loaded, services_loaded, running, and ready; the connected handler is not wired. Even after using running/ready as a health signal, query the required state again and validate the time window and deduplication key. Take no action without an explicit catch-up rule.
Can Time Repeat Daily guarantee exactly one run on a DST transition day?
This chapter makes no such guarantee. The schedule is built in the runtime environment’s time, and DST can create a nonexistent or repeated local time. Test both transition directions in an isolated environment, and deduplicate downstream by date and purpose.
Can a Webhook ID be part of an ordinary public URL?
Do not treat it as public information. A caller who knows the ID may be able to trigger the flow. Never put it in a repository, screenshot, or log. Reachability, authentication, and abuse prevention require a separate assessment; this chapter neither creates nor tests a webhook.
Will Calendar send every missed event after a restart?
Do not claim that it will. Version 0.80.3 polls again and schedules items still within its query window, but the in-memory timer queue and emitted-event cache disappear when the process ends. Your flow must define a lateness tolerance, deduplication, and conditions under which no catch-up occurs.