Sign in to keep reading
“Smart Grid Device Control” is free with an account. Your progress and bookmarks follow you across devices.
Sign in to continueNEW: ML Mock & Coaching with a 20+ year experience coach. Save $20 on sessions for Premium.ML Mock & Coaching now available
NEW: ML Mock & Coaching with a 20+ year experience coach. Save $20 on sessions for Premium.ML Mock & Coaching now available
Design a Smart Grid Device Control and Telemetry Reconciliation System - Millions of EV chargers, HVAC units, and industrial loads over the public internet, where devices go offline, commands get duplicated, ACKs prove nothing, and telemetry arrives hours late. The staff-level signal is recognizing a distributed closed-loop control system — not a monitoring dashboard.
Written by a Staff+ Engineer and an Engineering Manager
12+ years of experience in distributed systems and real-time messaging. Tech lead for large-scale chat applications serving billions of users. Over 12 years of industry experience with 6 years in engineering leadership, building and scaling tech infrastructure teams that deliver end-to-end large-scale distributed systems.
“Smart Grid Device Control” is free with an account. Your progress and bookmarks follow you across devices.
Sign in to continueWhat to Design?
Could you answer these today? Tick what you already know.
Video Walkthrough — Part I
Video Walkthrough — Part II
We'll scope to four FRs. Each one maps to exactly one flow in the High Level Design.
FR1 — Campaign planning
A user creates a campaign that defines the target devices, requested action, desired reduction, effective time, and expiry. The platform persists the campaign first, resolves eligible devices, and then fans the command out asynchronously.
FR2 — Send commands to devices
The platform reliably sends commands to targeted devices even when the network is unreliable. Online devices receive commands quickly; offline devices receive still-valid commands when they reconnect. Retries must be safe, stale commands must not take effect, and devices must be able to ACK or refuse.
FR3 — Feedback loop
Devices continuously report telemetry such as power usage. The platform uses this data to determine what actually happened after a command, aggregate the achieved reduction for the campaign, and decide whether the next action should be to hold, escalate, relax, or restore.
FR4 — Reconciliation
Telemetry may arrive substantially late after devices reconnect. The platform must assign late samples to the correct event-time window, deduplicate retries, recompute affected historical results, and publish corrected campaign results without erasing the evidence that earlier decisions were made using older information.
Out of scope (say this out loud): grid physics, demand forecasting, settlement/billing, device firmware internals, and detecting maliciously falsified telemetry. Each of these is its own interview.
The key principle behind FR3 and FR4
Command delivered != command executed
ACK != physical verification
No telemetry = UNKNOWN
Most of the design exists to keep those three distinctions honest.
NFR1 — Reliability. No accepted campaign is lost. Commands use at-least-once delivery with idempotent device behavior. Telemetry is ACKed to the device only after durable acceptance. We are controlling physical equipment over an unreliable network; "probably delivered" is not a contract.
NFR2 — Latency. P95 command delivery under 10 seconds for online devices; a provisional campaign result within a few minutes. The feedback loop has to react fast enough to be operationally useful during a grid event.
NFR3 — Scalability and burst headroom. ~10M registered devices; ~700K telemetry samples/sec steady state; several-times burst headroom. Reconnect storms create catch-up traffic that is orders of magnitude above steady state — and they arrive exactly when the operator most needs fresh data.
NFR4 — Correctness under uncertainty. Deduplicate retries, preserve event time, model UNKNOWN explicitly, and revise historical results when late data arrives. A wrong conclusion about missing or stale data makes the next control action wrong.
| Scale Assumptions | |
|---|---|
| Parameter | Value |
| Registered devices | 10M |
| Online on average | 7M |
| Telemetry cadence | 1 sample / device / 10 sec |
| Sample size | ~200 bytes compressed |
| Largest campaign | ~500K target devices |
| Steady-state ingestion | |
The number that identifies the real system:
Steady state = 700K samples/sec
Reconnect burst = 720M samples arriving within minutes
≈ 17 minutes of steady-state traffic, compressed into a spike
→ and it lands while the operator needs *current* data most
The exact number matters less than the architectural conclusion: steady-state ingestion is already large, and reconnect storms replay hours of buffered data on top of it. That strongly motivates asynchronous processing and a partitioned durable log between the device edge and downstream computation — and, more subtly, isolating live telemetry from catch-up telemetry so the control loop never goes blind during recovery.
Interviewer signal: candidates who name the reconnect storm and the live-vs-catch-up tension have found the real system; candidates who size a time-series database and stop have designed a dashboard.
These four questions give the rest of the design its purpose. Introduce them before drawing the final architecture — every component below exists because one of these forces it.
REDUCE 20% from executing after the RESTORE?Before drawing boxes, orient around three tensions that shape everything:
User plans a campaign
→ platform sends commands
→ devices produce telemetry
→ platform evaluates the result and adjusts the plan
→ late telemetry may revise an earlier conclusion
The design is not just about command delivery and not just about telemetry ingestion. The interesting part is the relationship between the two: telemetry is the evidence that closes the loop, and a later plan must be able to say exactly which evidence it was based on.
ACKED answers "what happened to the message?" VERIFIED answers "what did the device physically do?" They come from different channels (command transport vs. telemetry), they change at different times, and ACKED + NOT_VERIFIED is a perfectly valid state. Collapsing them into one SUCCESS state is the single most common mistake in this interview.
The platform will act before all the relevant telemetry has arrived — that is the nature of a grid event. So the design has to (a) make uncertainty explicit (UNKNOWN is a first-class result, not a failure), (b) process by event time rather than arrival time, and (c) version its conclusions so that a decision made on partial data remains auditable after the data completes.
The core recognition
This is a distributed closed-loop control system over an unreliable edge. Commands need at-least-once transport made safe by idempotency, per-device ordering, and expiry. Telemetry needs a durable, partitioned log that absorbs reconnect storms and feeds an event-time feedback processor. And the loop's outputs must be versioned, because late data will change the past while the next decision moves the future.
| Design Decisions | |
|---|---|
| Design choice | Reason |
| Persist Campaign before fan-out; DeviceCommand as the materialized target set | API returns 202 in milliseconds; fan-out to 500K devices resumes safely after a crash |
| At-least-once transport + command_id + device_seq + expires_at | |
Keep the model intentionally small — only the objects needed to explain the four FRs.
Useris the starting actor, but identity belongs to the auth system; the campaign keeps onlycreated_by_user_idfor audit. Presence lives in a TTL cache, not a domain table.
Enough to identify the device and resolve campaign targets.
| Device | ||
|---|---|---|
| Column | Type | Comment |
device_id | UUID | Primary key |
region_id | VARCHAR | Used by target selectors |
device_class | ENUM | |
The user's durable intent. Persisted before any device is contacted.
| Campaign | ||
|---|---|---|
| Column | Type | Comment |
campaign_id | UUID | Primary key |
created_by_user_id | UUID | Audit only — identity belongs to the auth system |
target_selector | JSONB | |
parent_campaign_id and based_on_rollup_ver are the two columns that make reconciliation auditable. A follow-up campaign records both the campaign it is reacting to and the exact evidence version that triggered it.
One row per (campaign, device). The composite key is the materialized target set: if (C1, D7) exists, D7 was part of C1 at fan-out time.
| DeviceCommand | ||
|---|---|---|
| Column | Type | Comment |
campaign_id | UUID | PK part 1; FK → Campaign.campaign_id |
device_id | UUID | PK part 2; FK → Device.device_id |
Transport state machine — deliberately small:
PENDING -> DELIVERED -> ACKED
\-> REFUSED
PENDING -> EXPIRED
DELIVERED -> EXPIRED
PENDING -> DELIVERED platform confirms the command reached the device session
DELIVERED -> ACKED device explicitly acknowledges
DELIVERED -> REFUSED device explicitly refuses (e.g. owner override)
* -> EXPIRED validity window ended before the command could be applied
There is no
VERIFIEDin this state machine. Verification comes from telemetry and answers a different question: what did the device physically do? (DD4)
| TelemetrySample | ||
|---|---|---|
| Column | Type | Comment |
device_id | UUID | PK part 1; FK → Device.device_id |
sample_seq | BIGINT | PK part 2 — makes retry deduplication trivial |
event_time | ||
The versioned, materialized result of a campaign. Late telemetry produces a new version; old versions are never overwritten.
| CampaignRollup | ||
|---|---|---|
| Column | Type | Comment |
campaign_id | UUID | PK part 1; FK → Campaign.campaign_id |
version | INT | PK part 2 — incremented on every recompute |
watermark | ||
Campaign C1, rollup v3 -> 30 MW confirmed
Campaign C1, rollup v4 -> 37 MW confirmed, after late telemetry
We keep both versions so a later reader can still understand why a follow-up campaign was created from v3.
| 7M / 10s = 700K samples/sec ≈ 140 MB/sec ≈ 12 TB/day raw |
| Reconnect storm (1M devices, 2h outage) | 1M × 720 buffered samples = 720M historical samples on top of live traffic |
| Effectively-once physical effect without pretending the network is exactly-once |
| Separate live and catch-up telemetry paths into one durable log | A reconnect storm becomes consumer lag, not data loss — and never blinds the live loop |
| Event-time processing with a visible watermark | Late samples land in the window where reality happened; staleness is exposed, not hidden |
| Versioned CampaignRollup + based_on_rollup_ver on follow-ups | Latest truth and decision-time truth are both preserved |
| Self-expiring commands | Devices fail safe when the platform itself disappears |
ev_charger / hvac / refrigeration / industrial / building |
priority_tier | INT | Lower tiers are shed first; critical equipment sits in the highest tier |
opt_out | BOOLEAN | Owner has opted out of demand-response campaigns |
| Region, device class, minimum priority tier |
action | ENUM | reduce_percent / cap_watts / restore |
parameters | JSONB | e.g. percent: 20 |
target_reduction_w | BIGINT | Desired aggregate reduction |
effective_from | TIMESTAMP | Start of the control window |
expires_at | TIMESTAMP | Travels with every command — see DD1 |
parent_campaign_id | UUID | Nullable — the campaign this one is reacting to |
based_on_rollup_ver | INT | Nullable — the exact evidence version that triggered this campaign (DD3) |
status | ENUM | active / completed / cancelled |
device_seqBIGINT |
| Monotonic per device — rejects superseded commands (DD1) |
delivery_state | ENUM | PENDING → DELIVERED → ACKED | REFUSED; PENDING/DELIVERED → EXPIRED |
device_response | JSONB | Refusal reason, applied set point, etc. |
TIMESTAMP |
| When the device *measured* the value |
ingest_time | TIMESTAMP | When the platform *received* it |
power_w | INT | Measured power draw |
applied_campaign_id | UUID | Nullable — which campaign the device believes it is following; supporting evidence, not proof |
TIMESTAMP |
| Event time before which data is believed substantially complete |
targeted_count | INT | Devices in the materialized target set |
verified_count | INT | Telemetry confirms the requested reduction |
refused_count | INT | Explicit device refusals |
unknown_count | INT | Insufficient telemetry coverage — neither success nor failure |
achieved_reduction_w | BIGINT | Confirmed reduction |
unknown_reduction_w | BIGINT | Reduction that *might* have happened but is unproven |
computed_at | TIMESTAMP | Wall-clock time of this version |