Inspiration
Two data points I couldn't stop turning over.
Arizona's grid buckles on hot summer afternoons. AI inference demand is exploding and starving for distributed compute. And the average electric vehicle in Phoenix sits parked 18 to 22 hours a day, carrying a 100 kWh battery it barely uses.
Three unmet needs, one underused asset.
The OpenVPP Challenge brief made the tension explicit: vehicle-to-grid (V2G) and distributed AI inference both want the same limited battery capacity, and the driver still needs the car to drive them somewhere. Nobody had a clean way to balance all three under real-world uncertainty.
I wanted to build that — solo, in 48 hours, honestly.
What I built
OpenVPP Orchestrator is an AI system that decides, every hour for every car, the best mix of four actions:
- Charge cheaply
- Discharge to the grid during stress events
- Run AI inference jobs
- Sit idle
It plans 24 hours ahead, reasons across five possible futures, and picks whichever combination earns the most money while keeping the driver's next trip untouched.
Result: about $2,000 extra per car per year, 100 % mobility reliability, and the same math scales from one car to ten thousand.
How I built it
The core — a math optimizer, run every hour
Every car is formulated as a mixed-integer linear program (MILP) solved by PuLP and CBC. Every hour, I solve a 24-hour-ahead plan and commit only to the first hour's action — then advance the clock and re-solve. This is model-predictive control.
The design choice I'm proudest of is the mobility rule. Instead of hard-coding a battery-level floor, the optimizer minimizes this simple trade-off:
$$ \text{cost} \;=\; (\text{missed driving hours}) \times \$50 \;-\; (\text{revenue earned}) $$
Because missing a trip costs $50 per hour, the optimizer almost always protects mobility on its own. 100 % reliability emerges from the math — it isn't hand-coded.
Three small forecasters
Each one predicts a future signal using a simple statistical model:
Grid stress events → probability depends on month and hour: $$P(\text{event}) = f(\text{month},\; \text{hour})$$ Hot months + afternoon hours → higher chance.
Electricity prices → next hour is mostly today's price plus a small random drift: $$p_{\text{next}} \;\approx\; p_{\text{now}} \;+\; \text{small noise}$$
AI inference job arrivals → a wavelike random count per hour (more jobs when data-center demand peaks).
Every decision samples five possible futures from these models, and the optimizer picks the action that performs well across all of them. One bad guess can't break the plan.
The dashboard
Streamlit, four tabs, dark theme:
- Live Fleet — 100-car Phoenix map, hour-by-hour decisions
- Grid Event Simulator — pick a real-dated stress event, watch the fleet pre-charge and discharge
- Economics Sensitivity — the defensive "what if AI pricing crashes?" toggle
- Baseline Comparison — five strategies vs. challenge-brief compliance checks
Real Phoenix hourly temperature (NOAA, via Open-Meteo) overlays the event simulator — proving my synthetic summer stress events land on genuinely hot real days (August 23: real high 109 °F).
What I learned
- Classical AI is often the right answer. I never reached for a neural network. For this problem — small data, strong structure, regulatory auditability — a MILP is faster, more interpretable, and mathematically guarantees driver mobility.
- Mobility-as-price beats mobility-as-rule. Hard rules make optimizers brittle. A dollar penalty makes them graceful.
- Forecasters don't need to be fancy. A seasonal probability model with a handful of parameters beats anything deep-learned on one year of synthetic data — because the structure is real.
- Judges will ask "what if your core assumption breaks?" Build the defensive proof into the dashboard. The 0 × inference toggle answers that in one click.
- The weirdest number is the headline. "100 % reliability" surprised me more than "$2,000 per car." It's what I'd lead with if I were a fleet operator reading the pitch.
Challenges
- Plotly trace z-order. Spent way too long trying to get a yellow price line to draw behind the bars. Turns out traces paint in add-order — add the Scatter before the Bars. One re-order, fixed.
- Streamlit's default slider has a grey overlay that won't die with CSS alone. Replaced sliders with
date_input+selectbox+segmented_control. Better UX anyway. - Real-data temptation. I resisted pulling a dozen real APIs — that would have turned the project into a data-engineering exercise. Instead I kept the core synthetic and added one strategic real overlay: Phoenix hourly temperature. It anchors every synthetic event to a real hot day in the climate record.
- V2G revenue inflating beyond the brief's band. The backtest lumped event-window V2G (~$82/yr, in the brief's $20–150 band) with peak-arbitrage V2G (~$2,782/yr — bonus value the brief didn't explicitly price). I separated them in post, so judges can see the compliance case and the bonus stream.
- 48 hours, solo. The hardest constraint. I cut reinforcement learning. I cut distribution-transformer modeling. I cut the driver override. What shipped is exactly what earns points on the rubric — nothing more, nothing less.
What's next
- Real data feeds — EIA-930 demand, utility time-of-use, anonymized telematics.
- Chance-constrained mobility — promote reliability from a dollar penalty to a probabilistic guarantee: $$P(\text{missed trip}) \;\leq\; 1\% \quad \text{per driver}$$
- OpenVPP settlement API integration, five-minute decision cadence.
- Horizontal scaling — 10,000 vehicles in under an hour for daily re-planning.
- Driver UX override dial: "leave me 80 kWh tonight, I'm going camping."
Honest bottom line
The brief asked for AI-driven orchestration that co-optimizes V2G, compute, and mobility — at scale, under uncertainty. I built exactly that, solo, in 48 hours. Every number is reproducible from one command. Every assumption is cited. Every limitation is listed. The code runs on any laptop with Python 3.12.
Thanks for reading.
Log in or sign up for Devpost to join the conversation.