This series of repos is designed to teach real world skills when implementing modern energy systems. It covers everything from the sensors, to the UI (mobile and web), to predictive models, to AI agents. The three languages used are
- 🌊 Typescript: Realtime UIs and APIs
- 🐍 Python: LLM/ML Apps and Platform Engineering
- 🦀 Rust: Grid Protocols and Embedded Systems
The EMS (Energy Management System) suite is the software that runs on a deployed Arcnode stack. It allows you to model different smart grid systems. For example, you could model a dynamic dlr system with a datacenter load. The bess could be modeled with canbus measurements and the datacenter could be modeled as snmp and bacnet readings.
collections "mock_industrial_protocols**" as mock_industrial_protocols
rectangle "front of the meter" #line.dashed {
collections dlr_sensors
rectangle phase_shift_transformer
}
cloud ercot_api
cloud third_party_apis
rectangle cluster #line.dashed {
rectangle industrial_gateway
rectangle line_controller
rectangle device_api
database timeseries
database vector
database graph
collections analyst_api
database document
collections ems_hmi
person llm
rectangle domain_mcp_server
dlr_sensors -d- line_controller
phase_shift_transformer -d- line_controller
mock_industrial_protocols -d- industrial_gateway
ercot_api -r- timeseries
line_controller -d- device_api
industrial_gateway -d- device_api
device_api -d- ems_hmi
device_api -r- document
timeseries -r- analyst_api
domain_mcp_server -u- llm
vector -u- domain_mcp_server
graph -u- domain_mcp_server
analyst_api -d- ems_hmi
llm -u- analyst_api
llm -l- third_party_apis* MQTT broker ommited for simplicity
** canbus, modbus, dnp3, snmp, bacnet, and ocpp,
actor operator
participant device_api
database document
participant industrial_gateway
participant line_controller
participant broker
database timeseries
database vector
database graph
participant domain_mcp_server
participant llm
participant analyst_api
participant ems_hmi
participant ercot_api
collections third_party_apis
operator -> device_api: POST /topology (from DTM)
device_api -> document: generate AsyncAPI v3 spec
== distribute topics ==
industrial_gateway -> device_api: GET /asyncapi
line_controller -> device_api: GET /asyncapi
ems_hmi -> device_api: GET /asyncapi
== initialize messaging ==
industrial_gateway -> broker: pub grid protocols
line_controller -> broker: pub direct sensor data
broker -> timeseries: writes to db
broker -> ems_hmi: renders live data
== ml workflows ==
ercot_api -> analyst_api: GET /solar-production
timeseries <- analyst_api: trains model
analyst_api -> ems_hmi: renders prediction
== ai agent workflows ==
ems_hmi -> analyst_api: GET /chat/completions
analyst_api -> llm: query
llm -> domain_mcp_server: tool call
domain_mcp_server -> vector: agentic rag
domain_mcp_server -> graph: graph rag
llm -> third_party_apis: external api tool call
llm -> analyst_api: api prediction tool call
analyst_api -> llm: prediction response
llm -> analyst_api: synthesizes rag dbs and apis call
analyst_api -> ems_hmi: renders chatrectangle ecs_cluster #line.dashed {
rectangle analyst_agent
rectangle analyst_model
rectangle device_api
queue emqx
rectangle ems_hmi
rectangle mlflow
rectangle prometheus
rectangle grafana
rectangle industrial_gateway
rectangle analyst_server
}
database s3
rectangle managed_persistence #line.dashed {
cloud timescale_cloud
cloud neon_vector
cloud neon_document
cloud neo4j_aura
}
rectangle third_party_apis #line.dashed {
cloud ercot_api
cloud openweather
cloud yes_energy
cloud permutable
}
rectangle daemons #line.dashed {
database postgres_timescale
database postgres_document
database postgres_vector
database neo4j
database minio
rectangle ollama {
rectangle llama
rectangle nomic_embed
}
}
rectangle docker_runtime #line.dashed {
rectangle device_api
rectangle industrial_gateway
rectangle analyst_server
rectangle analyst_agent
rectangle analyst_model
rectangle ems_hmi
rectangle mlflow
queue emqx
rectangle prometheus
rectangle grafana
}
Nightly job in a staging environment. Exercises the full data flow across all services.
participant ci_runner
participant device_api
participant industrial_gateway
participant industrial_fixtures
queue broker
participant ems_hmi
database timeseries
participant analyst_api
ci_runner -> device_api: POST /topology (test DTM)
device_api -> device_api: generate AsyncAPI spec
industrial_gateway -> device_api: GET /asyncapi
industrial_fixtures -> device_api: GET /asyncapi
ems_hmi -> device_api: GET /asyncapi
== fixture telemetry ==
industrial_fixtures -> broker: publish sim measurements
broker -> industrial_gateway: forward
broker -> ems_hmi: forward
broker -> timeseries: persist
== analyst ==
analyst_api -> timeseries: query
analyst_api -> ci_runner: predictions + chat response
== assertions ==
ci_runner -> timeseries: verify measurements persisted
ci_runner -> ems_hmi: verify render (headless)
ci_runner -> analyst_api: verify predictions + chatThe following repositories make up the EMS suite: