EV charging — network uptime & load
The problem. A charging network's reputation is its availability: a driver who rolls up to a dead charger doesn't come back. At the same time, a bank of fast chargers all drawing at once can exceed a site's grid connection and trip it — taking every charger down. The operator needs to know a charger has failed the moment it does, and to keep total site draw inside its limit.
What we solve here is uptime drivers can trust and grid limits the site never breaches.
Set up demo data
New workspace? Run this once (Python) to create a charger's status series, create the
subscription before we listen, and push a fault reading — so the loop below raises a
charger_down. Safe to re-run.
import datahub_sdk, pandas as pd
client = datahub_sdk.DataHubClient.from_env()
client.timeseries.create([datahub_sdk.TimeSeries(external_id="charger_oslo_14_status", name="Charger Oslo 14 status", unit="status", value_type="float")])
client.subscriptions.create([datahub_sdk.Subscription(
external_id="network_status", name="Charging network status", timeseries=["charger_oslo_14_status"])])
# status 1 = available; push a 0 (faulted) for the loop to catch
client.timeseries.insert_from_lists(timestamps=[pd.Timestamp.now(tz="UTC")], values=[0.0], ts="charger_oslo_14_status")
1. Detect a dead charger immediately
Each charge point reports status and power. A connector that stops responding or faults
raises a charger_down event straight into the dispatch queue. See
Consume live data.
- Java
- Python
- Rust
import ai.intellistream.datahub.sdk.subscriptions.SubscriptionMessage;
try (var stream = client.subscriptions().listen(List.of("network_status"))
.stream((SubscriptionMessage msg) -> { // auto-acks after each message
if (faulted(msg.payload())) {
EventModel down = new EventModel();
down.setExternalId("charger_down_oslo_14_" + System.currentTimeMillis());
down.setType("charger_down");
down.setStatus("open");
down.setMetadata(Map.of("charger", "charger_oslo_14", "connector", "2"));
down.setEventTime(ZonedDateTime.now());
client.events().create(List.of(down));
}
})) {
awaitShutdown(); // your app lifecycle; closing the stream ends delivery
}
with client.subscriptions.listen(["network_status"]) as listener:
for msg in listener:
if faulted(msg.payload):
client.events.create([datahub_sdk.Event(
external_id=f"charger_down_oslo_14_{int(pd.Timestamp.now().timestamp())}",
type="charger_down", status="open",
event_time=pd.Timestamp.now(tz="UTC"),
metadata={"charger": "charger_oslo_14", "connector": "2"})])
listener.ack([msg.message_id])
use chrono::Utc;
use dataplatform_rust_sdk::events::Event;
let mut listener = api.subscriptions.listen(&["network_status"]).await?;
while let Some(Ok(msg)) = listener.next().await {
if faulted(&msg.payload) {
let mut down = Event::new(format!("charger_down_oslo_14_{}", Utc::now().timestamp()));
down.r#type = Some("charger_down".into());
down.status = Some("open".into());
down.add_metadata("charger".into(), "charger_oslo_14".into());
down.add_metadata("connector".into(), "2".into());
down.set_event_time(Utc::now());
api.events.create(&vec![down]).await?;
}
listener.ack(&[msg.message_id.as_str()]).await?;
}
2. Report uptime and watch site load
Availability and per-site power are series. Daily uptime per charger gives the network-quality number; the site's summed draw, aggregated to the minute, shows how close it runs to its grid limit — the input to load-balancing. See Query & aggregate.
See the result
The faulted reading in the demo trips the loop, and a charger_down event lands:
for e in client.events.filter(datahub_sdk.EventFilter(
basic_filter=datahub_sdk.BasicEventFilter(type="charger_down"), limit=5)):
print(e.external_id, e.metadata)
# charger_down_oslo_14_… {'charger': 'charger_oslo_14', 'connector': '2'}
See also
- Consume live data — live charger status.
- Turn readings into events — the fault rule.
- Query & aggregate — uptime and site-load reporting.