Subtitle: How I Built an Agent to Slash Electricity Bills by 40% Using Solar & Price Forecasting
TL;DR
I built an autonomous AI agent that manages a home battery system. By simulating real-time electricity prices (Time-of-Use) and solar generation, the agent decides when to charge, discharge, or hold energy. In my simulations, this optimize-first approach reduced electricity costs by over 40% compared to a standard "use-as-needed" strategy. This article breaks down the architecture, the Python implementation, and my lessons learned from this experiment.
Introduction
We are living in an era where energy prices are as volatile as stock markets. With the rise of renewable energy, utility companies are increasingly shifting to Time-of-Use (TOU) pricing models, where electricity is cheap when the sun shines or the wind blows, and expensive during evening peaks.
For a homeowner with solar panels and a battery, this presents a complex optimization problem. Do you use your solar energy now? Do you store it? Do you sell it back to the grid? Or do you charge your battery from the grill when prices are negative (yes, that happens!)?
I realized that a simple "if-else" timer isn't enough. I needed an agent—something that could look at the forecast, look at the current battery state, and make a decision to maximize savings.
So, I decided to build autonomous-energy-optimizer.
What's This Article About?
This article is a deep dive into my journey of building a Python-based energy management agent. I wanted to simulate a realistic environment where:
- Grid Prices fluctuate every hour.
- Solar Production follows the sun but is affected by random weather.
- Home Load varies based on morning and evening routines.
- An Agent sits in the middle, making high-stakes decisions to save money.
I will walk you through the architecture, the decision logic, and the code itself.
Tech Stack
For this experiment, I kept the stack improved but focused on Python's strengths in simulation and modeling:
- Python 3.12: The core language.
- Rich: For that beautiful, dashboard-like terminal output you saw in the header.
- Dataclasses: For structured data modeling (Prices, State, Decisions).
- Matplotlib/Mermaid: For visualizing the logic and results.
Why Read It?
If you are interested in:
- AI Agents: Beyond just LLMs, seeing how rule-based and utility-based agents work in numerical environments.
- Green Tech: Applying coding skills to sustainability problems.
- Simulation: Learning how to model complex systems (weather, markets) in code.
- Python Design Patterns: Seeing clean separation of concerns between Environment, Agent, and Simulation Controller.
Then this post is for you.
Let's Design
Before writing a single line of code, I grabbed my digital whiteboard to map out the system. I needed to visualize how the agent interacts with the grid and the home.
System Architecture
The system mimics a real-world setup. We have simulation models acting as the "Environment" (Grid, Sun, Home), and an Agent acting as the "Controller".
The Logic Flow
The decision-making process is critical. Every hour, the simulation loop asks the agent: "Here is the state, what do we do?" The agent then evaluates the net load (Consumption - Solar) and the price signal to choose an action.
Sequence of Operations
Here is how a single tick (one hour) of the simulation executes:
Let’s Get Cooking
Now, let's look at the code. I structured the project to be modular, making it easy to swap out the pricing model or the agent logic later.
1. Modeling the World (models.py)
First, I defined the data structures. I used Python's dataclass to keep things strict and clean. EnergyState tracks the battery and load, while Decision captures what the agent wants to do.
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime
@dataclass
class PriceData:
timestamp: datetime
grid_price: float # Current grid price in $/kWh
solar_production: float # Current solar production in kW
@dataclass
class EnergyState:
battery_level: float # Current battery level in kWh
battery_capacity: float # Max battery capacity in kWh
current_load: float # Current house load in kW
@property
def battery_percentage(self) -> float:
return (self.battery_level / self.battery_capacity) * 100
@dataclass
class Decision:
action: str # "CHARGE", "DISCHARGE", "HOLD"
amount: float # Amount of energy in kWh
reason: str
2. The Forecasting System (forecasting.py)
To make the simulation interesting, I needed dynamic data. PriceForecaster simulates a typical "Duck Curve" pricing model where electricity is expensive in the evening. SolarPredictor generates a bell curve for sun output, adding random cloud cover for realism.
class PriceForecaster:
def __init__(self):
# Base TOU pricing: Low (Night), High (Evening), Mid (Day)
self.base_prices = {
# ... (hourly breakdown) ...
17: 0.45, 18: 0.45, 19: 0.40, # Peak Evening
# ...
}
def get_price(self, timestamp: datetime) -> float:
hour = timestamp.hour
base = self.base_prices.get(hour, 0.15)
# Add random volatility simulation
volatility = random.uniform(-0.02, 0.05)
return max(0.05, round(base + volatility, 3))
3. The Brains: Energy Agent (agents.py)
This is where the magic happens. The agent looks at the PriceData and EnergyState.
If solar production exceeds household load (net_load < 0), it prioritizes charging the battery. Free energy!
If there is a deficit (we need power), it checks the price.
-
High Price (
> discharge_threshold): Discharge the battery. Avoid paying the utility. -
Low Price (
< charge_threshold): Charge the battery from the grid, anticipating future high prices. - Normal Price: Just self-consume from the battery if available.
class EnergyAgent:
def decide(self, state: EnergyState, market: PriceData) -> Decision:
net_load = state.current_load - market.solar_production
# Scenario A: Excess Solar
if net_load < 0:
excess = abs(net_load)
if state.battery_level < state.battery_capacity:
return Decision("CHARGE", excess, "Excess Solar -> Battery")
else:
return Decision("HOLD", 0, "Battery Full, Solar to Grid")
# Scenario B: Solar Deficit (Need Energy)
# High price time! Use battery if possible.
if market.grid_price >= self.discharge_threshold:
if state.battery_level > 0:
amount = min(state.battery_level, net_load)
return Decision("DISCHARGE", amount, "Peak Price -> Discharge Battery")
# Low price time! Charge battery for later.
if market.grid_price <= self.charge_threshold:
if state.battery_level < state.battery_capacity:
charge_amount = min(5.0, state.battery_capacity - state.battery_level)
return Decision("CHARGE", charge_amount, f"Low Price (${market.grid_price}) -> Charge")
return Decision("HOLD", 0, "Using Grid (Normal Operation)")
4. The Simulation Loop (main.py)
Finally, I tied it all together with Rich to create that engaging terminal output. The loop steps through 24 hours, updates the simulated environment, asks the agent for a decision, calculates the costs, and updates the live table.
def main():
# ... setup models ...
with Live(table, refresh_per_second=4) as live:
for _ in range(24): # Simulate 24 hours
# 1. Update Environment
market = PriceData(...)
# 2. Agent Decision
decision = agent.decide(state, market)
# 3. Calculate Physics & Economics
# ... (Cost calculation logic) ...
# 4. Update UI
table.add_row(...)
time.sleep(0.15) # Cinematic effect
Let's Setup
If you want to run this simulation yourself, here is how you can set it up in minutes.
-
Clone the Repository:
git clone https://github.com/aniket-work/autonomous-energy-optimizer cd autonomous-energy-optimizer -
Create Virtual Environment:
python3 -m venv venv source venv/bin/activate -
Install Dependencies:
pip install pandas numpy requests rich
Let's Run
Running the simulation is straightforward:
python main.py
You will see the terminal come alive. The agent starts negotiating with the simulated grid.
In my test runs, the results were consistent:
- Standard Cost (No Agent): ~$18.00 / day
- AI Agent Cost: ~$10.00 / day
- Savings: ~45%
The agent successfully dodged the "Peak Evening" prices (5 PM - 9 PM) by discharging the battery it charged cheaply during the sunny afternoon or the deep night.
Closing Thoughts
Building this Autonomous Home Energy Manager was a fantastic exercise in thinking about systems. It showed me that "Smart Homes" don't just need connectivity; they need intelligence.
A simple rule-based agent like the one I built can save significant money. Imagine what you could do with Reinforcement Learning (RL), predicting your specific household habits, or integrating with a real Tesla Powerwall API.
The future of energy is distributed and intelligent. And as developers, we have the tools to build that future.
Disclaimer
The views and opinions expressed here are solely my own and do not represent the views, positions, or opinions of my employer or any organization I am affiliated with. The content is based on my personal experience and experimentation and may be incomplete or incorrect. Any errors or misinterpretations are unintentional, and I apologize in advance if any statements are misunderstood or misrepresented.




Top comments (0)