Two gigabytes a minute,and nobody waitsfor the screen.
ESPx watches 120+ power plants. I own the real-time path: telemetry in, alarms judged as the data arrives, and the result on a control-room screen seconds later. Underneath it all sits a ten-year-old Web Forms application that we're taking apart while it keeps running.
- Product
- ESPx · plant monitoring
- Client
- BaxEnergy (Yokogawa)
- Engaged via
- Intellisync
- Role
- Senior Software Engineer
- Since
- Nov 2024
A decade-old system, asked to work in real time
ESPx began as an ASP.NET Web Forms and WCF application. It was reliable and it was slow, and the request was not 'make it faster' — it was 'make it live'. Turbine data had to land, be judged against alarm rules, and reach a control-room screen while the operator still cared. Rewriting from scratch was never on the table: the estate runs 120+ sites and cannot go dark for a migration.
- Ten years of Web Forms and WCF, still in production, still carrying the business
- ~2 GB of turbine telemetry arriving every minute, from heterogeneous SCADA systems
- Alarms that mattered were being noticed minutes late
- No freeze window — the modernisation had to ship alongside normal feature work
“120+ sites cannot go dark for a migration.”
The constraint that shaped everything
Ingest, judge, push — in that order, every time
Telemetry lands in Kafka, is written to TimescaleDB for history, and flows through Redis streams for the hot path. Alarm evaluation happens on the stream rather than on a timer against the database, which is the whole difference between a dashboard that reports the past and one that reports now. Results are pushed to React dashboards over SignalR. Exactly-once delivery throughout — a duplicated alarm costs an operator's trust, and you only get to spend that once.
- Kafka for ingest, TimescaleDB for time-series history, Redis streams for the live path
- Alarm rules evaluated on the stream, not polled against storage
- SignalR push to React dashboards, so screens update rather than refresh
- Event-driven gRPC and REST APIs on .NET 8 behind it all
Alarms are judgedon the stream —not after it.
A dashboard that polls storage reports the past. Evaluating rules against the stream as it arrives is what makes the control room's screen the present tense — and it is the difference between an operator noticing a gearbox at 82°C now or in four minutes.
- Evaluated
- 48,213
- Window
- rolling 60s
- waiting for the stream…
Infrastructure that scales without a meeting
The AWS side is Terraform and Helm on EKS with auto-scaling node groups, so a windy week in Texas doesn't require anyone to provision anything. The same pass that made it elastic made it cheaper: careful query work and Redis caching cut average API latency by 65%, and performance tuning took nearly half off the monthly EC2 bill. Automated builds and integration tests brought regressions down 35%.
- Terraform and Helm on EKS, auto-scaling node groups
- 65% lower average API latency from query optimisation and Redis caching
- ~50% lower monthly EC2 cost from performance tuning
- 35% fewer regression bugs via automated builds and integration tests
- Azure AD OAuth2 SSO, mTLS between services, ISO 27001 controls
- 2 GB/min
- Telemetry ingested, exactly once
- 120+
- Power-plant sites monitored
- −65%
- Average API latency
- −50%
- Monthly EC2 spend
- −35%
- Regression bugs
Operators now see what's happening rather than what happened. And the old system gets a bit smaller every quarter, without anyone ever giving up a weekend to a migration.
Stack