Skip to content

Watch the bench live

Bring-up is watching. This notebook reads the inverter's state right now, polls it for a bounded thirty seconds, then uses window() to recover every mode transition — including the ones the poll slept through.

You'll use: latest() · watch() with interval and until · window() snapshot and changes · plot()

Run it

zelos live demo --backfill 5m --duration 30m    # terminal 1: demo data

Copy the notebook below into live-pulse.md, then:

zelos notebook run live-pulse.md

The notebook

---
description: Read current values, watch them tick, and reconstruct every state transition.
requires-python: ">=3.10"
dependencies:
  - zelos-sdk[notebook]
params:
  interval: 5.0
  watch_for: "30s"
  replay: "1m"
---

Bring-up work is watching: is the inverter in the right mode, did anything
flip while you were flashing firmware? This notebook is the bounded version of
staring at a terminal — read the state now, poll it, and then recover what the
poll missed.

## The state right now

```python
from zelos_sdk import connect

agent = connect()
agent.latest([
    "bus1/inverter_status.mode",
    "bus1/inverter_controls.control_mode",
])
```

## Watch it tick

`watch()` polls on an interval and yields a snapshot per tick. `until` bounds
it with the same duration grammar as everything else, so the cell finishes on
its own and the notebook can run unattended:

```python
for tick in agent.watch(
    "bus1/inverter_status.mode",
    interval=params.interval,
    until=params.watch_for,
):
    mode = tick["bus1/inverter_status.mode"]
    print(f"{mode.time:%H:%M:%S}  {mode.value}")
```

## Reconstruct what the poll missed

The demo inverter changes mode every four seconds; the poll above looks every
five. `window()` doesn't sample at all — it returns the opening state plus
**every change** in the interval, which is why it is the flight recorder for
mode flags and state machines and a poll is only a dashboard:

```python
replay = agent.window(
    "bus1/inverter_status.mode",
    start=f"-{params.replay}",
    duration=params.replay,
)
replay
```

## The same minute, charted

A numeric line over the same window rounds out the picture — the transitions
above tell you what the inverter was doing, the chart tells you what it was
doing it to:

```python
agent.query(
    "bus1/inverter_status.grid_frequency",
    start=f"-{params.replay}",
).plot()
```

Point the same four cells at your own state signals and this notebook is a
bench monitor you can re-run — or export as a page — any time.

What the poll missed

One run of this notebook against the demo bench — the tick loop, then the replay of the minute around it:

17:06:23  Hybrid
17:06:28  Off-Grid
17:06:33  Hybrid
17:06:38  Grid-Tied
17:06:43  Off-Grid
17:06:48  Grid-Tied

ReplayWindow(2026-09-04 17:05:53.661 → 17:06:53.661 · 1 signals · 16 changes)

Six values in thirty seconds of polling; sixteen recorded changes in the minute that contains them. Every tick landed on a real mode, and no tick is wrong — the poll simply never saw most of the flips.

What to notice

  • watch(..., until="30s") is self-terminating — a live loop with a deadline, so the notebook always finishes and can run unattended. Without until it runs until you interrupt it.
  • A tick is a Snapshot, the same read-only mapping latest() returns for a list of paths: tick[path] gives a value that carries its own time, unit, and label.
  • Polling misses; window() doesn't. Ticks five seconds apart cannot see a signal that flips every four; the change stream has every transition with a timestamp. Use the first for a dashboard, the second for evidence.
  • "-1m" and "1m" are the two grammars. A signed offset is a time; an unsigned one is a duration. start= takes the first, duration= and until= take the second. See Time and duration grammar.
  • Swap in your own mode signals and re-run; params.interval and params.watch_for set how often and how long the live section observes.