Skip to content

How the platform knows a device is alive

The platform treats liveness as derived state, not as a stored flag. For devices, the durable fact is when ALYT last heard from them; for endpoints, offline state comes from a recorded failed reachability attempt. What clients show is computed when the record is read. That matters because stale state is not the same as a failed device, and local functions can keep working during a cloud outage while cloud-dependent connectors require the provider and network.

For platform devices, liveness comes from lastSeen at read time.

  • lastSeen means the platform accepted a message from that device.
  • online, not_heard_from, and offline are computed when the device is read.
  • The platform does not store a separate online flag for devices.

A device advances lastSeen only through accepted broker traffic. Every accepted device message uses the same path, and lastSeen has one writer.

Current hubs report their own liveness.

When a hub connects, it keeps its own broker session and reports:

  • retained online on its availability topic when connected
  • broker last-will offline when disconnected
  • a heartbeat every 90 seconds on telemetry

Those heartbeat messages include rssi, uptime_s, heap_free, and link_s, and each accepted message advances lastSeen the same way as any other device message.

Because of that, the hub is alive by the hub’s own report, with or without an agent.

  • In a hosted home, the hub writes its own status.
  • In a self-hosted home, the agent still relays the composite voice state for the hub, because that state combines device listening with a room setting and should have one latest writer.

Some homes still depend on the older relay shape for compatibility.

In that path:

  1. the board is probed every 15 seconds
  2. a probe has a 5 second timeout
  3. the voice service fetches link mapping every 60 seconds
  4. the agent relays liveness to the platform
  5. the relay publishes on the hub device’s own availability topic
  6. the broker ingestion path advances lastSeen

Rules that matter to developers:

  • Only probed state is relayed.
  • A quiet device is not reported offline.
  • The platform decides offline from its grace window, not from an immediate relay failure.
  • No platform_device_id means the platform does not know that device, so nothing is adopted by guesswork.
  • No uplink makes the platform view stale; it does not mean the home is down.

The device grace window is three missed beats, or 270 seconds.

Endpoint liveness is different from device liveness

Section titled “Endpoint liveness is different from device liveness”

Endpoints are polled or updated by connectors, so their offline state is not based on lastSeen alone.

An endpoint is offline only when a connector tried to reach it and got no answer for that endpoint. ALYT stores that first failed attempt time in Endpoint.unreachableSince.

A later failure does not move that timestamp.

Any later good state clears Endpoint.unreachableSince, including state from:

  • a refresh
  • a command read-back
  • a device push from the connector

An endpoint reads as offline when Endpoint.unreachableSince is later than stateUpdatedAt.

That lets clients show the real last good state time alongside offline state, such as “offline, last seen 14:02”.

These cases are not endpoint offline:

  • an old poll with no newer reachability attempt
  • a connector-wide failure, such as provider outage or refused credentials
  • a route that reports busy and did not ask the thing

A connector-wide outage says nothing about the individual things behind it. In that case, the platform keeps the previous endpoint state.

Retry before marking an endpoint unreachable

Section titled “Retry before marking an endpoint unreachable”

A failed refresh must be a real miss because it sticks.

When a refresh misses an endpoint, ALYT asks that endpoint again 2 seconds later and stores unreachable only on a second miss.

This second pass reduces false offline transitions caused by transient transport loss.

Automatic recheck for already-unreachable endpoints

Section titled “Automatic recheck for already-unreachable endpoints”

A thing marked unreachable now asks again on its own.

The recheck schedule is:

Time since marked unreachableRecheck interval
First 10 minutesevery 1 minute
After thatevery 5 minutes
Laterevery 30 minutes

This recheck applies only to things already marked unreachable. It does not fan out across the healthy house.

A household can disable an endpoint with PATCH /endpoints/:id and enabled: false.

Disabled wins over liveness:

  • the endpoint reads as disabled, never offline
  • it raises no room notice
  • it is skipped by room actions
  • it is skipped by “all the lights”
  • it remains in the list rather than being rediscovered as new

Turning it back on clears the stored failed attempt so the next refresh judges it afresh.

Battery Zigbee devices behave differently from mains-powered devices.

For these devices, long silence is normal. The platform can mark a battery device offline after a day of silence, but connector behavior is adjusted so the house does not treat every sleepy device as “did not answer”.

On the hub route, sleepy Zigbee devices are not actively read during refresh. If a previous unanswerable read wrote unreachableSince, that stored offline fact is cleared once, and lastSeen and stateUpdatedAt are left untouched. The result is “not checked” with the real last state, not a fake online timestamp.

For local kinds routed through a home’s hub, the platform waits for the hub’s reported state, not for a synthetic success.

Important timing values:

  • ordinary hub read or command wait: 5 seconds
  • lock confirmation wait: 15 seconds
  • fallback wake check: 1 second
  • hub considered alive within 200 seconds of its own activity

A refusal from the hub is surfaced as a refusal, including the hub’s reason when present. A route that is busy is not treated as endpoint failure.

For endpoints, a stale poll is rendered as not checked, not offline.

For devices and endpoints, client presentation keeps these distinctions:

  • online means there is current positive evidence
  • offline means there was a specific failed reachability attempt, or an overdue device-specific liveness rule
  • disabled is its own state
  • a thing with no usable check yet reads as not checked

A thing can also be considered “not connected” in lists when it is offline, disabled, or an endpoint has never answered state at all.

Local functions can keep working during a cloud outage; cloud-dependent connectors require the provider and network.

That means:

  • a connector-wide cloud failure does not prove endpoints are offline
  • local hub-routed or LAN-routed things may still work while cloud services are unavailable
  • the platform preserves prior state unless it has endpoint-specific evidence of failure

For developers, the key rule is to treat liveness as evidence-based. Use lastSeen for devices, Endpoint.unreachableSince plus state freshness for endpoints, and do not collapse stale, busy, disabled, and unreachable into one status.

A failed server queue or route, or a BUSY response, is not a negative device probe. For refreshes, the read window starts after enqueue and stays within the shared 17-second read work budget; this does not change physical write expiry. When an older failed refresh is followed by a newer device report, the newer report takes precedence under the canonical row lock.

Last updated