HomeGrid — Home Energy Monitor
Technology Stack:
- Python
- FastAPI
- Apache Kafka
- Datasette
- SQLite
- Electricity Price API
You've been given a live grid operations dashboard for an electricity company. It's running, but all three panels are empty — no meter readings, no appliance data, no pricing.
Your job: add three sidecars to the workspace, one at a time. Each one wires up a data source. When all three are running, the dashboard tells a complete story.
- OpenShift Dev Spaces workspace open with this repository
- Run "1. Install dependencies" from the Dev Spaces command palette before starting
- After any workspace restart, re-run "1. Install dependencies" before continuing — and once you have created the topic, re-run commands 2, 3 and 4 as well (see Task 4)
| File | Role |
|---|---|
app/main.py |
FastAPI app — serves the dashboard, /api/events, /api/appliances, /api/price |
app/consumer.py |
Background thread — polls Kafka for meter readings |
app/producer.py |
Standalone script — generates fake meter readings |
data/seed.py |
Seeds appliances.db with reference data |
sidecar/ |
Source for the electricity price API container image |
devfile.yaml |
Workspace definition — you edit this in Tasks 1, 4, and 6 |
Open devfile.yaml and paste in the following components under the first TODO comment — the Kafka broker and Kafbat UI, a web console for browsing topics, messages and consumer groups:
- name: kafka
container:
image: apache/kafka:3.9.0
endpoints:
- name: kafka-broker
exposure: internal
targetPort: 9092
env:
- name: KAFKA_NODE_ID
value: "1"
- name: KAFKA_PROCESS_ROLES
value: broker,controller
- name: KAFKA_LISTENERS
value: PLAINTEXT://:9092,CONTROLLER://:9093
- name: KAFKA_ADVERTISED_LISTENERS
value: PLAINTEXT://localhost:9092
- name: KAFKA_CONTROLLER_QUORUM_VOTERS
value: 1@localhost:9093
- name: KAFKA_CONTROLLER_LISTENER_NAMES
value: CONTROLLER
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
value: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
- name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
value: "1"
- name: KAFKA_AUTO_CREATE_TOPICS_ENABLE
value: "false"
cpuLimit: '1'
memoryLimit: '1Gi'
- name: kafka-ui
container:
image: ghcr.io/kafbat/kafka-ui:v1.5.0
endpoints:
- name: kafka-ui
exposure: public
protocol: https
targetPort: 8081
path: /
env:
- name: SERVER_PORT
value: "8081"
- name: KAFKA_CLUSTERS_0_NAME
value: homegrid
- name: KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS
value: localhost:9092
cpuLimit: '500m'
memoryLimit: '1Gi'Kafbat UI listens on port
8081because the dashboard already uses8080— all sidecars in a workspace share one network.
Save, commit, push, restart the workspace. Re-run "1. Install dependencies".
Run "2. Start HomeGrid dashboard" and open the grid-dashboard endpoint.
All three panels are empty — there is no topic to read from yet.
Run "3. Create meter-readings topic" from the command palette.
Topic 'meter-readings' created on localhost:9092
Run "4. Start meter reading producer" — the Live Readings panel fills with live data.
Open the kafka-ui endpoint in a new browser tab. Under Topics → meter-readings → Messages you can watch each reading arrive as raw JSON.
Open devfile.yaml and paste in the following component under the second TODO comment:
- name: datasette
container:
image: datasetteproject/datasette:0.65.5
endpoints:
- name: datasette
exposure: internal
targetPort: 8001
command: ["sh", "-c", "datasette serve \"$PROJECT_SOURCE/data/\" --host 0.0.0.0 --port 8001"]
cpuLimit: '500m'
memoryLimit: '512Mi'
mountSources: true
mountSources: truegives datasette access to the project volume, and$PROJECT_SOURCEpoints at this repository inside it. The dashboard reads directly from SQLite — datasette is your browser-based DB explorer.
Save, commit, push, restart the workspace. Re-run "1. Install dependencies", then "2. Start HomeGrid dashboard", "3. Create meter-readings topic" and "4. Start meter reading producer" — a restart stops everything that was running, and the Kafka sidecar does not keep its data, so the topic has to be created again.
Open a terminal and run:
python3.11 data/seed.pyThis creates data/appliances.db with 10 appliances. Open the datasette endpoint in a browser tab to explore the data.
Add your own appliances using the SQLite Explorer extension (zknpr.sqlite-explorer):
- Open
data/appliances.dbin the editor - Add rows for any appliances you want to track
- The Appliance Reference panel updates within 2 seconds
Bonus challenge: Add 10 more appliances to the database. Get creative — think home automation, workshop tools, entertainment systems. Each appliance needs a name and daily kWh consumption. Watch the Appliance Reference panel update in real time as you add them!
Open sidecar/price_api.py — take a look at how it works. It returns the current electricity rate based on time of day (off-peak / mid-peak / peak).
Open devfile.yaml and paste the following under the third TODO comment:
- name: price-api
container:
image: image-registry.openshift-image-registry.svc:5000/workspace-images/electricity-price-api:latest
endpoints:
- name: price-api
exposure: internal
targetPort: 5000
cpuLimit: '250m'
memoryLimit: '256Mi'Save, commit, push, restart the workspace. Re-run "1. Install dependencies", then "2. Start HomeGrid dashboard", "3. Create meter-readings topic" and "4. Start meter reading producer" — a restart stops everything that was running, and the Kafka sidecar does not keep its data, so the topic has to be created again.
The price ticker in the header shows the current rate. Appliance daily costs and circuit reading costs update automatically.
Stop the dashboard — press Ctrl+C in the terminal running "2. Start HomeGrid dashboard" — and leave the producer running.
Now check the consumer lag. The Kafka tools live in the kafka sidecar, not in your terminal's container, so run them there:
oc exec $(oc get pod -l controller.devfile.io/devworkspace_id=$DEVWORKSPACE_ID -o name) -c kafka -- \
/opt/kafka/bin/kafka-consumer-groups.sh \
--bootstrap-server localhost:9092 \
--describe \
--group grid-dashboardRun it a few times and watch the LAG column grow — the producer keeps writing a reading every two seconds, but nobody is reading them. Restart the dashboard and run it again: the consumer catches up and the lag drops back to zero.
You can watch the same lag in Kafbat UI under Consumers → grid-dashboard.
In the next session we'll use KEDA to automatically scale the consumer based on this lag.
"Doc Brown needs 1.21 gigawatts on the flux-capacitor circuit. Can you send it through the grid?"
Hint: you don't need the producer script — Kafbat UI can send a message too. You'll know when you've found it. 🏆