+
+
!==
+
+
adonis
r
surrealdb
svelte
jwt
+
+
+
smtp
+
+
cargo
vim
+
abap
+
ฯ€
htmx
|>
ada
+
+
weaviate
helm
pinecone
+
+
+
+
soap
bitbucket
+
+
+
mxnet
argocd
+
gradle
+
+
+
micronaut
redis
scala
zorin
rider
helm
pycharm
+
+
intellij
&&
+
nuxt
+
chef
+
haiku
haiku
ray
+
+
https
+
gradle
+
koa
babel
+
+
ray
+
+
+
matplotlib
+
yaml
+
c#
+
circle
*
+
mongo
pandas
Back to Blog
Smart Grid Management on Alpine Linux โšก
Alpine Linux IoT Energy Management

Smart Grid Management on Alpine Linux โšก

Published Jun 13, 2025

Learn how to build a smart grid management system on Alpine Linux. We will monitor energy usage, manage renewable sources, and optimize power distribution! ๐Ÿ”Œ

25 min read
0 views
Table of Contents

Smart grid management is like having an intelligent brain for your electrical network! ๐Ÿง  It monitors energy flow, balances supply and demand, and integrates renewable sources seamlessly. Letโ€™s build a complete smart grid management system on Alpine Linux! ๐Ÿš€

What is a Smart Grid? ๐Ÿค”

A smart grid includes:

  • Real-time monitoring - Track energy usage instantly
  • Demand response - Adjust consumption automatically
  • Renewable integration - Solar, wind, and battery systems
  • Grid analytics - Predict and optimize energy flow
  • Two-way communication - Devices talk to the grid

Think of it as upgrading your power grid to the digital age! โšก

Installing Core Components ๐Ÿ“ฆ

Set up the smart grid infrastructure:

# Update package list
sudo apk update

# Install MQTT broker for device communication
sudo apk add mosquitto mosquitto-clients

# Install time-series database
sudo apk add influxdb telegraf

# Install Python for analytics
sudo apk add python3 py3-pip python3-dev
sudo apk add gcc musl-dev linux-headers

# Install Node.js for real-time dashboard
sudo apk add nodejs npm

# Install monitoring tools
sudo apk add prometheus grafana

Setting Up Energy Monitoring ๐Ÿ“Š

Create the monitoring infrastructure:

# Create project structure
mkdir -p ~/smart-grid/{devices,analytics,dashboard,config}
cd ~/smart-grid

# Smart meter simulator
cat > devices/smart_meter.py << 'EOF'
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
import json
import time
import random
import math
from datetime import datetime

class SmartMeter:
    def __init__(self, meter_id, location):
        self.meter_id = meter_id
        self.location = location
        self.mqtt_client = mqtt.Client(f"meter_{meter_id}")
        self.base_consumption = random.uniform(1.0, 3.0)  # kW base load
        
    def connect(self, broker="localhost", port=1883):
        """Connect to MQTT broker"""
        self.mqtt_client.connect(broker, port, 60)
        self.mqtt_client.loop_start()
        print(f"Smart meter {self.meter_id} connected to broker")
        
    def simulate_consumption(self):
        """Simulate realistic power consumption"""
        hour = datetime.now().hour
        
        # Daily consumption pattern
        if 6 <= hour <= 9:  # Morning peak
            multiplier = 1.5
        elif 17 <= hour <= 21:  # Evening peak
            multiplier = 2.0
        elif 23 <= hour or hour <= 5:  # Night low
            multiplier = 0.5
        else:  # Day normal
            multiplier = 1.0
            
        # Add some randomness
        consumption = self.base_consumption * multiplier
        consumption += random.uniform(-0.2, 0.2)
        
        # Simulate appliance usage spikes
        if random.random() < 0.1:  # 10% chance of spike
            consumption += random.uniform(1.0, 3.0)
            
        return max(0, consumption)
        
    def read_meter(self):
        """Read current meter values"""
        consumption = self.simulate_consumption()
        voltage = 230 + random.uniform(-5, 5)  # Voltage fluctuation
        current = consumption * 1000 / voltage  # Calculate current
        power_factor = 0.9 + random.uniform(-0.05, 0.05)
        frequency = 50 + random.uniform(-0.1, 0.1)  # Grid frequency
        
        data = {
            "meter_id": self.meter_id,
            "timestamp": datetime.now().isoformat(),
            "location": self.location,
            "consumption_kw": round(consumption, 3),
            "voltage": round(voltage, 1),
            "current": round(current, 2),
            "power_factor": round(power_factor, 3),
            "frequency": round(frequency, 2),
            "energy_today_kwh": round(consumption * datetime.now().hour, 2)
        }
        
        return data
        
    def publish_reading(self):
        """Publish meter reading to MQTT"""
        data = self.read_meter()
        topic = f"smartgrid/meters/{self.meter_id}/reading"
        self.mqtt_client.publish(topic, json.dumps(data))
        return data
        
    def run(self, interval=5):
        """Run continuous monitoring"""
        try:
            while True:
                reading = self.publish_reading()
                print(f"Meter {self.meter_id}: {reading['consumption_kw']} kW")
                time.sleep(interval)
        except KeyboardInterrupt:
            print(f"Meter {self.meter_id} shutting down")
            self.mqtt_client.loop_stop()
            self.mqtt_client.disconnect()

if __name__ == "__main__":
    # Create multiple smart meters
    meters = [
        SmartMeter("SM001", "Building A"),
        SmartMeter("SM002", "Building B"),
        SmartMeter("SM003", "Building C")
    ]
    
    # Connect all meters
    for meter in meters:
        meter.connect()
        
    # Run first meter (in production, run each in separate process)
    meters[0].run()
EOF

chmod +x devices/smart_meter.py

Solar Panel Integration โ˜€๏ธ

Monitor renewable energy sources:

# Solar panel monitor
cat > devices/solar_monitor.py << 'EOF'
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
import json
import time
import math
from datetime import datetime

class SolarPanel:
    def __init__(self, panel_id, capacity_kw, location):
        self.panel_id = panel_id
        self.capacity_kw = capacity_kw
        self.location = location
        self.mqtt_client = mqtt.Client(f"solar_{panel_id}")
        self.efficiency = 0.85  # 85% efficiency
        
    def connect(self, broker="localhost"):
        self.mqtt_client.connect(broker, 1883, 60)
        self.mqtt_client.loop_start()
        
    def calculate_solar_output(self):
        """Calculate solar panel output based on time of day"""
        now = datetime.now()
        hour = now.hour + now.minute / 60
        
        # Sunrise at 6 AM, sunset at 6 PM (simplified)
        if 6 <= hour <= 18:
            # Solar intensity curve (bell curve)
            peak_hour = 12
            intensity = math.exp(-((hour - peak_hour) ** 2) / 18)
            
            # Weather factor (random clouds)
            weather_factor = 0.7 + random.uniform(0, 0.3)
            
            # Calculate output
            output = self.capacity_kw * intensity * weather_factor * self.efficiency
        else:
            output = 0  # No sun at night
            
        return max(0, output)
        
    def get_panel_data(self):
        """Get current panel data"""
        output_kw = self.calculate_solar_output()
        temperature = 25 + (output_kw / self.capacity_kw) * 20  # Panel temp
        
        data = {
            "panel_id": self.panel_id,
            "timestamp": datetime.now().isoformat(),
            "location": self.location,
            "output_kw": round(output_kw, 3),
            "capacity_kw": self.capacity_kw,
            "efficiency": round(output_kw / self.capacity_kw * 100, 1),
            "temperature_c": round(temperature, 1),
            "voltage_dc": round(400 + output_kw * 10, 1),
            "current_dc": round(output_kw * 1000 / 400, 2)
        }
        
        return data
        
    def publish_data(self):
        """Publish solar panel data"""
        data = self.get_panel_data()
        topic = f"smartgrid/solar/{self.panel_id}/status"
        self.mqtt_client.publish(topic, json.dumps(data))
        return data
        
    def run(self, interval=10):
        """Run continuous monitoring"""
        try:
            while True:
                data = self.publish_data()
                print(f"Solar {self.panel_id}: {data['output_kw']} kW ({data['efficiency']}%)")
                time.sleep(interval)
        except KeyboardInterrupt:
            self.mqtt_client.loop_stop()
            self.mqtt_client.disconnect()

# Battery storage system
class BatteryStorage:
    def __init__(self, battery_id, capacity_kwh, max_power_kw):
        self.battery_id = battery_id
        self.capacity_kwh = capacity_kwh
        self.max_power_kw = max_power_kw
        self.current_charge_kwh = capacity_kwh * 0.5  # Start at 50%
        self.mqtt_client = mqtt.Client(f"battery_{battery_id}")
        
    def connect(self, broker="localhost"):
        self.mqtt_client.connect(broker, 1883, 60)
        self.mqtt_client.loop_start()
        
        # Subscribe to grid commands
        self.mqtt_client.on_message = self.on_message
        self.mqtt_client.subscribe(f"smartgrid/battery/{self.battery_id}/command")
        
    def on_message(self, client, userdata, msg):
        """Handle charging/discharging commands"""
        try:
            command = json.loads(msg.payload.decode())
            if command["action"] == "charge":
                self.charge(command.get("power_kw", 1.0))
            elif command["action"] == "discharge":
                self.discharge(command.get("power_kw", 1.0))
        except Exception as e:
            print(f"Error processing command: {e}")
            
    def charge(self, power_kw):
        """Charge battery"""
        power = min(power_kw, self.max_power_kw)
        energy = power * (5/3600)  # 5 second interval in hours
        self.current_charge_kwh = min(
            self.current_charge_kwh + energy,
            self.capacity_kwh
        )
        
    def discharge(self, power_kw):
        """Discharge battery"""
        power = min(power_kw, self.max_power_kw)
        energy = power * (5/3600)
        self.current_charge_kwh = max(
            self.current_charge_kwh - energy,
            0
        )
        
    def get_status(self):
        """Get battery status"""
        soc = (self.current_charge_kwh / self.capacity_kwh) * 100
        
        return {
            "battery_id": self.battery_id,
            "timestamp": datetime.now().isoformat(),
            "state_of_charge": round(soc, 1),
            "current_charge_kwh": round(self.current_charge_kwh, 2),
            "capacity_kwh": self.capacity_kwh,
            "max_power_kw": self.max_power_kw,
            "available_power_kw": self.max_power_kw if soc > 10 else 0,
            "status": "charging" if soc < 90 else "ready"
        }
        
    def publish_status(self):
        """Publish battery status"""
        status = self.get_status()
        topic = f"smartgrid/battery/{self.battery_id}/status"
        self.mqtt_client.publish(topic, json.dumps(status))
        return status

if __name__ == "__main__":
    import random
    
    # Create solar panel
    solar = SolarPanel("SOLAR001", 10.0, "Rooftop A")
    solar.connect()
    
    # Create battery
    battery = BatteryStorage("BAT001", 50.0, 5.0)
    battery.connect()
    
    # Run solar panel monitoring
    solar.run()
EOF

Grid Analytics Engine ๐Ÿงฎ

Process and analyze grid data:

# Grid analytics
cat > analytics/grid_analytics.py << 'EOF'
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
import json
from influxdb_client import InfluxDBClient, Point
from datetime import datetime, timedelta
import numpy as np
from collections import defaultdict

class GridAnalytics:
    def __init__(self):
        self.mqtt_client = mqtt.Client("grid_analytics")
        self.influx_client = InfluxDBClient(
            url="http://localhost:8086",
            token="your-token",
            org="smartgrid"
        )
        self.write_api = self.influx_client.write_api()
        
        # Real-time data storage
        self.meter_data = defaultdict(dict)
        self.solar_data = defaultdict(dict)
        self.battery_data = defaultdict(dict)
        
        # Grid statistics
        self.total_consumption = 0
        self.total_generation = 0
        self.grid_frequency = 50.0
        
    def connect(self):
        """Connect to MQTT broker"""
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_message = self.on_message
        self.mqtt_client.connect("localhost", 1883, 60)
        self.mqtt_client.loop_start()
        
    def on_connect(self, client, userdata, flags, rc):
        """Subscribe to all grid topics"""
        print("Connected to MQTT broker")
        client.subscribe("smartgrid/+/+/+")
        
    def on_message(self, client, userdata, msg):
        """Process incoming messages"""
        try:
            topic_parts = msg.topic.split('/')
            device_type = topic_parts[1]
            device_id = topic_parts[2]
            data = json.loads(msg.payload.decode())
            
            # Store data by type
            if device_type == "meters":
                self.process_meter_data(device_id, data)
            elif device_type == "solar":
                self.process_solar_data(device_id, data)
            elif device_type == "battery":
                self.process_battery_data(device_id, data)
                
            # Run analytics
            self.analyze_grid_state()
            
        except Exception as e:
            print(f"Error processing message: {e}")
            
    def process_meter_data(self, meter_id, data):
        """Process smart meter data"""
        self.meter_data[meter_id] = data
        
        # Store in InfluxDB
        point = Point("meter_reading") \
            .tag("meter_id", meter_id) \
            .tag("location", data.get("location", "unknown")) \
            .field("consumption_kw", data["consumption_kw"]) \
            .field("voltage", data["voltage"]) \
            .field("current", data["current"]) \
            .field("power_factor", data["power_factor"]) \
            .field("frequency", data["frequency"]) \
            .time(datetime.utcnow())
            
        self.write_api.write(bucket="smartgrid", record=point)
        
    def process_solar_data(self, panel_id, data):
        """Process solar panel data"""
        self.solar_data[panel_id] = data
        
        # Store in InfluxDB
        point = Point("solar_output") \
            .tag("panel_id", panel_id) \
            .tag("location", data.get("location", "unknown")) \
            .field("output_kw", data["output_kw"]) \
            .field("efficiency", data["efficiency"]) \
            .field("temperature_c", data["temperature_c"]) \
            .time(datetime.utcnow())
            
        self.write_api.write(bucket="smartgrid", record=point)
        
    def process_battery_data(self, battery_id, data):
        """Process battery data"""
        self.battery_data[battery_id] = data
        
        # Store in InfluxDB
        point = Point("battery_status") \
            .tag("battery_id", battery_id) \
            .field("state_of_charge", data["state_of_charge"]) \
            .field("current_charge_kwh", data["current_charge_kwh"]) \
            .field("available_power_kw", data["available_power_kw"]) \
            .time(datetime.utcnow())
            
        self.write_api.write(bucket="smartgrid", record=point)
        
    def analyze_grid_state(self):
        """Analyze current grid state"""
        # Calculate totals
        self.total_consumption = sum(
            m["consumption_kw"] for m in self.meter_data.values()
        )
        self.total_generation = sum(
            s["output_kw"] for s in self.solar_data.values()
        )
        
        # Grid balance
        grid_balance = self.total_generation - self.total_consumption
        
        # Publish grid state
        grid_state = {
            "timestamp": datetime.now().isoformat(),
            "total_consumption_kw": round(self.total_consumption, 2),
            "total_generation_kw": round(self.total_generation, 2),
            "grid_balance_kw": round(grid_balance, 2),
            "renewable_percentage": round(
                (self.total_generation / self.total_consumption * 100) 
                if self.total_consumption > 0 else 0, 1
            ),
            "num_meters": len(self.meter_data),
            "num_solar": len(self.solar_data),
            "num_batteries": len(self.battery_data)
        }
        
        self.mqtt_client.publish(
            "smartgrid/analytics/state",
            json.dumps(grid_state)
        )
        
        # Demand response signals
        if grid_balance < -5:  # High demand
            self.trigger_demand_response("reduce", abs(grid_balance))
        elif grid_balance > 5:  # Excess generation
            self.trigger_battery_charging(grid_balance)
            
    def trigger_demand_response(self, action, amount_kw):
        """Send demand response signals"""
        dr_signal = {
            "timestamp": datetime.now().isoformat(),
            "action": action,
            "amount_kw": amount_kw,
            "duration_minutes": 15
        }
        
        self.mqtt_client.publish(
            "smartgrid/demand_response/signal",
            json.dumps(dr_signal)
        )
        
    def trigger_battery_charging(self, excess_kw):
        """Manage battery charging with excess power"""
        available_batteries = [
            b for b in self.battery_data.values()
            if b["state_of_charge"] < 90
        ]
        
        if available_batteries:
            power_per_battery = excess_kw / len(available_batteries)
            
            for battery in available_batteries:
                command = {
                    "action": "charge",
                    "power_kw": min(power_per_battery, battery["max_power_kw"])
                }
                
                self.mqtt_client.publish(
                    f"smartgrid/battery/{battery['battery_id']}/command",
                    json.dumps(command)
                )
                
    def predict_demand(self):
        """Predict future energy demand"""
        # Query historical data
        query = '''
        from(bucket: "smartgrid")
            |> range(start: -7d)
            |> filter(fn: (r) => r._measurement == "meter_reading")
            |> filter(fn: (r) => r._field == "consumption_kw")
            |> aggregateWindow(every: 1h, fn: mean)
        '''
        
        # Simple prediction based on historical patterns
        # In production, use ML models
        
    def calculate_cost_optimization(self):
        """Calculate optimal energy usage based on pricing"""
        # Time-of-use pricing
        hour = datetime.now().hour
        if 17 <= hour <= 21:  # Peak hours
            price_per_kwh = 0.25
        elif 9 <= hour <= 17:  # Mid-peak
            price_per_kwh = 0.15
        else:  # Off-peak
            price_per_kwh = 0.10
            
        current_cost = self.total_consumption * price_per_kwh
        
        return {
            "current_price_per_kwh": price_per_kwh,
            "current_hourly_cost": round(current_cost, 2),
            "recommendation": "Shift non-critical loads to off-peak hours"
        }

if __name__ == "__main__":
    analytics = GridAnalytics()
    analytics.connect()
    
    print("Grid Analytics Engine running...")
    
    try:
        while True:
            time.sleep(60)
            # Periodic reports
            cost = analytics.calculate_cost_optimization()
            print(f"Current cost: ${cost['current_hourly_cost']}/hour")
            
    except KeyboardInterrupt:
        print("Shutting down analytics engine")
EOF

Real-time Dashboard ๐Ÿ“ฑ

Create a web dashboard for grid monitoring:

# Dashboard backend
cd dashboard
npm init -y
npm install express socket.io mqtt influx

cat > server.js << 'EOF'
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const mqtt = require('mqtt');
const { InfluxDB } = require('@influxdata/influxdb-client');

const app = express();
const server = http.createServer(app);
const io = socketIo(server);

// MQTT client
const mqttClient = mqtt.connect('mqtt://localhost:1883');

// InfluxDB client
const influxDB = new InfluxDB({
    url: 'http://localhost:8086',
    token: 'your-token'
});
const queryApi = influxDB.getQueryApi('smartgrid');

// Serve static files
app.use(express.static('public'));

// Grid state storage
let gridState = {
    totalConsumption: 0,
    totalGeneration: 0,
    gridBalance: 0,
    renewablePercentage: 0,
    meters: {},
    solar: {},
    batteries: {}
};

// MQTT subscriptions
mqttClient.on('connect', () => {
    console.log('Connected to MQTT broker');
    mqttClient.subscribe('smartgrid/+/+/+');
    mqttClient.subscribe('smartgrid/analytics/+');
});

mqttClient.on('message', (topic, message) => {
    try {
        const data = JSON.parse(message.toString());
        const topicParts = topic.split('/');
        
        if (topic === 'smartgrid/analytics/state') {
            gridState = { ...gridState, ...data };
            io.emit('gridState', gridState);
        } else if (topicParts[1] === 'meters') {
            gridState.meters[topicParts[2]] = data;
            io.emit('meterUpdate', { id: topicParts[2], data });
        } else if (topicParts[1] === 'solar') {
            gridState.solar[topicParts[2]] = data;
            io.emit('solarUpdate', { id: topicParts[2], data });
        } else if (topicParts[1] === 'battery') {
            gridState.batteries[topicParts[2]] = data;
            io.emit('batteryUpdate', { id: topicParts[2], data });
        }
    } catch (error) {
        console.error('Error processing message:', error);
    }
});

// API endpoints
app.get('/api/state', (req, res) => {
    res.json(gridState);
});

app.get('/api/history/:measurement/:field', async (req, res) => {
    const { measurement, field } = req.params;
    const { start = '-1h' } = req.query;
    
    const query = `
        from(bucket: "smartgrid")
            |> range(start: ${start})
            |> filter(fn: (r) => r._measurement == "${measurement}")
            |> filter(fn: (r) => r._field == "${field}")
            |> aggregateWindow(every: 1m, fn: mean)
    `;
    
    try {
        const result = [];
        await queryApi.collectRows(query).then(rows => {
            rows.forEach(row => {
                result.push({
                    time: row._time,
                    value: row._value,
                    tag: row.meter_id || row.panel_id || row.battery_id
                });
            });
        });
        res.json(result);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Socket.io connection
io.on('connection', (socket) => {
    console.log('Client connected');
    
    // Send current state
    socket.emit('gridState', gridState);
    
    // Handle control commands
    socket.on('controlCommand', (command) => {
        mqttClient.publish(
            `smartgrid/${command.device}/${command.id}/command`,
            JSON.stringify(command.payload)
        );
    });
    
    socket.on('disconnect', () => {
        console.log('Client disconnected');
    });
});

server.listen(3000, () => {
    console.log('Smart Grid Dashboard running on port 3000');
});
EOF

# Dashboard frontend
mkdir -p public
cat > public/index.html << 'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Smart Grid Dashboard</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            background: #0a0a0a;
            color: #fff;
        }
        .header {
            background: #1a1a1a;
            padding: 1rem 2rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-bottom: 1px solid #333;
        }
        .container {
            padding: 2rem;
            max-width: 1400px;
            margin: 0 auto;
        }
        .grid-stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 1.5rem;
            margin-bottom: 2rem;
        }
        .stat-card {
            background: #1a1a1a;
            border-radius: 12px;
            padding: 1.5rem;
            border: 1px solid #333;
            transition: transform 0.2s;
        }
        .stat-card:hover {
            transform: translateY(-2px);
            border-color: #4CAF50;
        }
        .stat-value {
            font-size: 2.5rem;
            font-weight: bold;
            margin: 0.5rem 0;
        }
        .stat-label {
            color: #888;
            text-transform: uppercase;
            font-size: 0.85rem;
            letter-spacing: 1px;
        }
        .positive { color: #4CAF50; }
        .negative { color: #f44336; }
        .charts {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
            gap: 2rem;
            margin-bottom: 2rem;
        }
        .chart-container {
            background: #1a1a1a;
            border-radius: 12px;
            padding: 1.5rem;
            border: 1px solid #333;
        }
        .devices {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
            gap: 1.5rem;
        }
        .device-group {
            background: #1a1a1a;
            border-radius: 12px;
            padding: 1.5rem;
            border: 1px solid #333;
        }
        .device-item {
            background: #0a0a0a;
            padding: 1rem;
            margin: 0.5rem 0;
            border-radius: 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .device-status {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 0.5rem;
        }
        .status-online { background: #4CAF50; }
        .status-offline { background: #f44336; }
        .solar-icon { color: #FFC107; }
        .battery-icon { color: #2196F3; }
        .meter-icon { color: #9C27B0; }
        button {
            background: #4CAF50;
            color: white;
            border: none;
            padding: 0.5rem 1rem;
            border-radius: 6px;
            cursor: pointer;
            font-size: 0.9rem;
        }
        button:hover {
            background: #45a049;
        }
        .alert {
            background: #f44336;
            padding: 1rem;
            border-radius: 8px;
            margin: 1rem 0;
            display: flex;
            align-items: center;
        }
        .alert-icon {
            font-size: 1.5rem;
            margin-right: 1rem;
        }
    </style>
</head>
<body>
    <header class="header">
        <h1>โšก Smart Grid Control Center</h1>
        <div>
            <span id="time"></span>
            <span style="margin-left: 2rem;">Status: <span id="connection-status">Connecting...</span></span>
        </div>
    </header>
    
    <div class="container">
        <!-- Grid Statistics -->
        <div class="grid-stats">
            <div class="stat-card">
                <div class="stat-label">Total Consumption</div>
                <div class="stat-value" id="total-consumption">0.0</div>
                <div>kW</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Solar Generation</div>
                <div class="stat-value positive" id="total-generation">0.0</div>
                <div>kW</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Grid Balance</div>
                <div class="stat-value" id="grid-balance">0.0</div>
                <div>kW</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">Renewable %</div>
                <div class="stat-value positive" id="renewable-percentage">0</div>
                <div>Percent</div>
            </div>
        </div>
        
        <!-- Alerts -->
        <div id="alerts"></div>
        
        <!-- Charts -->
        <div class="charts">
            <div class="chart-container">
                <h3>Power Flow</h3>
                <canvas id="power-chart"></canvas>
            </div>
            <div class="chart-container">
                <h3>Energy Sources</h3>
                <canvas id="sources-chart"></canvas>
            </div>
        </div>
        
        <!-- Devices -->
        <div class="devices">
            <!-- Smart Meters -->
            <div class="device-group">
                <h3><span class="meter-icon">๐Ÿ“Š</span> Smart Meters</h3>
                <div id="meters-list"></div>
            </div>
            
            <!-- Solar Panels -->
            <div class="device-group">
                <h3><span class="solar-icon">โ˜€๏ธ</span> Solar Panels</h3>
                <div id="solar-list"></div>
            </div>
            
            <!-- Batteries -->
            <div class="device-group">
                <h3><span class="battery-icon">๐Ÿ”‹</span> Battery Storage</h3>
                <div id="batteries-list"></div>
            </div>
        </div>
    </div>
    
    <script>
        const socket = io();
        let powerChart, sourcesChart;
        let gridState = {};
        
        // Initialize charts
        function initCharts() {
            // Power flow chart
            const powerCtx = document.getElementById('power-chart').getContext('2d');
            powerChart = new Chart(powerCtx, {
                type: 'line',
                data: {
                    labels: [],
                    datasets: [{
                        label: 'Consumption',
                        data: [],
                        borderColor: '#f44336',
                        tension: 0.1
                    }, {
                        label: 'Generation',
                        data: [],
                        borderColor: '#4CAF50',
                        tension: 0.1
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        y: { beginAtZero: true }
                    }
                }
            });
            
            // Energy sources chart
            const sourcesCtx = document.getElementById('sources-chart').getContext('2d');
            sourcesChart = new Chart(sourcesCtx, {
                type: 'doughnut',
                data: {
                    labels: ['Solar', 'Grid', 'Battery'],
                    datasets: [{
                        data: [0, 0, 0],
                        backgroundColor: ['#FFC107', '#9E9E9E', '#2196F3']
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false
                }
            });
        }
        
        // Update display
        function updateDisplay(state) {
            document.getElementById('total-consumption').textContent = 
                state.total_consumption_kw?.toFixed(1) || '0.0';
            document.getElementById('total-generation').textContent = 
                state.total_generation_kw?.toFixed(1) || '0.0';
            
            const balance = state.grid_balance_kw || 0;
            const balanceEl = document.getElementById('grid-balance');
            balanceEl.textContent = balance.toFixed(1);
            balanceEl.className = balance >= 0 ? 'stat-value positive' : 'stat-value negative';
            
            document.getElementById('renewable-percentage').textContent = 
                Math.round(state.renewable_percentage || 0);
            
            // Update charts
            updateCharts(state);
            
            // Update device lists
            updateDeviceLists(state);
            
            // Check for alerts
            checkAlerts(state);
        }
        
        function updateCharts(state) {
            // Add data point to power chart
            const time = new Date().toLocaleTimeString();
            
            if (powerChart.data.labels.length > 20) {
                powerChart.data.labels.shift();
                powerChart.data.datasets[0].data.shift();
                powerChart.data.datasets[1].data.shift();
            }
            
            powerChart.data.labels.push(time);
            powerChart.data.datasets[0].data.push(state.total_consumption_kw || 0);
            powerChart.data.datasets[1].data.push(state.total_generation_kw || 0);
            powerChart.update();
            
            // Update sources chart
            const solarPower = state.total_generation_kw || 0;
            const gridPower = Math.max(0, (state.total_consumption_kw || 0) - solarPower);
            const batteryPower = 0; // Calculate from battery data
            
            sourcesChart.data.datasets[0].data = [solarPower, gridPower, batteryPower];
            sourcesChart.update();
        }
        
        function updateDeviceLists(state) {
            // Update meters
            const metersList = document.getElementById('meters-list');
            metersList.innerHTML = '';
            
            Object.entries(state.meters || {}).forEach(([id, meter]) => {
                const item = document.createElement('div');
                item.className = 'device-item';
                item.innerHTML = `
                    <div>
                        <span class="device-status status-online"></span>
                        ${id} - ${meter.location || 'Unknown'}
                    </div>
                    <div>${meter.consumption_kw?.toFixed(2) || 0} kW</div>
                `;
                metersList.appendChild(item);
            });
            
            // Update solar panels
            const solarList = document.getElementById('solar-list');
            solarList.innerHTML = '';
            
            Object.entries(state.solar || {}).forEach(([id, solar]) => {
                const item = document.createElement('div');
                item.className = 'device-item';
                item.innerHTML = `
                    <div>
                        <span class="device-status status-online"></span>
                        ${id} - ${solar.location || 'Unknown'}
                    </div>
                    <div>${solar.output_kw?.toFixed(2) || 0} kW (${solar.efficiency || 0}%)</div>
                `;
                solarList.appendChild(item);
            });
            
            // Update batteries
            const batteriesList = document.getElementById('batteries-list');
            batteriesList.innerHTML = '';
            
            Object.entries(state.batteries || {}).forEach(([id, battery]) => {
                const item = document.createElement('div');
                item.className = 'device-item';
                item.innerHTML = `
                    <div>
                        <span class="device-status status-online"></span>
                        ${id}
                    </div>
                    <div>
                        ${battery.state_of_charge?.toFixed(1) || 0}% 
                        <button onclick="chargeBattery('${id}')">Charge</button>
                    </div>
                `;
                batteriesList.appendChild(item);
            });
        }
        
        function checkAlerts(state) {
            const alertsDiv = document.getElementById('alerts');
            alertsDiv.innerHTML = '';
            
            // Check for high demand
            if (state.grid_balance_kw < -10) {
                const alert = document.createElement('div');
                alert.className = 'alert';
                alert.innerHTML = `
                    <span class="alert-icon">โš ๏ธ</span>
                    <div>
                        <strong>High Demand Alert</strong><br>
                        Grid demand exceeds generation by ${Math.abs(state.grid_balance_kw).toFixed(1)} kW
                    </div>
                `;
                alertsDiv.appendChild(alert);
            }
        }
        
        function chargeBattery(batteryId) {
            socket.emit('controlCommand', {
                device: 'battery',
                id: batteryId,
                payload: { action: 'charge', power_kw: 2.0 }
            });
        }
        
        // Socket events
        socket.on('connect', () => {
            document.getElementById('connection-status').textContent = 'Connected';
        });
        
        socket.on('disconnect', () => {
            document.getElementById('connection-status').textContent = 'Disconnected';
        });
        
        socket.on('gridState', (state) => {
            gridState = state;
            updateDisplay(state);
        });
        
        socket.on('meterUpdate', (data) => {
            if (!gridState.meters) gridState.meters = {};
            gridState.meters[data.id] = data.data;
            updateDisplay(gridState);
        });
        
        socket.on('solarUpdate', (data) => {
            if (!gridState.solar) gridState.solar = {};
            gridState.solar[data.id] = data.data;
            updateDisplay(gridState);
        });
        
        socket.on('batteryUpdate', (data) => {
            if (!gridState.batteries) gridState.batteries = {};
            gridState.batteries[data.id] = data.data;
            updateDisplay(gridState);
        });
        
        // Update time
        setInterval(() => {
            document.getElementById('time').textContent = new Date().toLocaleString();
        }, 1000);
        
        // Initialize
        initCharts();
    </script>
</body>
</html>
EOF

Grid Automation Rules ๐Ÿค–

Implement smart grid automation:

# Automation rules engine
cat > analytics/automation_rules.py << 'EOF'
#!/usr/bin/env python3
import json
from datetime import datetime, time

class GridAutomation:
    def __init__(self, mqtt_client):
        self.mqtt_client = mqtt_client
        self.rules = self.load_rules()
        
    def load_rules(self):
        """Load automation rules"""
        return [
            {
                "name": "Peak Shaving",
                "condition": lambda state: state["total_consumption_kw"] > 50,
                "action": self.peak_shaving
            },
            {
                "name": "Solar Excess Storage",
                "condition": lambda state: state["grid_balance_kw"] > 5,
                "action": self.store_excess_solar
            },
            {
                "name": "Night Load Balancing",
                "condition": lambda state: self.is_night_time() and state["total_consumption_kw"] > 30,
                "action": self.night_load_balance
            },
            {
                "name": "Emergency Response",
                "condition": lambda state: state.get("grid_frequency", 50) < 49.5,
                "action": self.emergency_response
            }
        ]
        
    def is_night_time(self):
        """Check if it's night time"""
        current_time = datetime.now().time()
        return current_time < time(6, 0) or current_time > time(22, 0)
        
    def evaluate_rules(self, grid_state):
        """Evaluate all automation rules"""
        for rule in self.rules:
            if rule["condition"](grid_state):
                print(f"Triggering rule: {rule['name']}")
                rule["action"](grid_state)
                
    def peak_shaving(self, state):
        """Reduce peak demand"""
        # Discharge batteries
        for battery_id in state.get("batteries", {}):
            command = {
                "action": "discharge",
                "power_kw": 5.0
            }
            self.mqtt_client.publish(
                f"smartgrid/battery/{battery_id}/command",
                json.dumps(command)
            )
            
        # Send demand response signal
        dr_signal = {
            "action": "reduce",
            "target_reduction_kw": 10,
            "incentive_per_kwh": 0.50
        }
        self.mqtt_client.publish(
            "smartgrid/demand_response/signal",
            json.dumps(dr_signal)
        )
        
    def store_excess_solar(self, state):
        """Store excess solar in batteries"""
        excess_kw = state["grid_balance_kw"]
        
        # Charge available batteries
        available_batteries = [
            b for b in state.get("batteries", {}).values()
            if b["state_of_charge"] < 90
        ]
        
        if available_batteries:
            power_per_battery = excess_kw / len(available_batteries)
            
            for battery in available_batteries:
                command = {
                    "action": "charge",
                    "power_kw": min(power_per_battery, 5.0)
                }
                self.mqtt_client.publish(
                    f"smartgrid/battery/{battery['battery_id']}/command",
                    json.dumps(command)
                )
                
    def night_load_balance(self, state):
        """Balance load during night hours"""
        # Shift flexible loads to night time
        load_shift_signal = {
            "action": "shift_to_now",
            "device_types": ["water_heater", "ev_charger"],
            "duration_hours": 4
        }
        self.mqtt_client.publish(
            "smartgrid/load_control/signal",
            json.dumps(load_shift_signal)
        )
        
    def emergency_response(self, state):
        """Emergency grid stabilization"""
        # Shed non-critical loads
        emergency_signal = {
            "action": "emergency_shed",
            "priority_levels": [3, 4, 5],  # Shed lowest priority loads
            "reason": "Grid frequency drop"
        }
        self.mqtt_client.publish(
            "smartgrid/emergency/signal",
            json.dumps(emergency_signal)
        )
        
        # Discharge all available batteries
        for battery_id in state.get("batteries", {}):
            command = {
                "action": "discharge",
                "power_kw": 10.0,  # Maximum discharge
                "emergency": True
            }
            self.mqtt_client.publish(
                f"smartgrid/battery/{battery_id}/command",
                json.dumps(command)
            )
EOF

Starting the Smart Grid System ๐Ÿš€

Create startup scripts:

# System startup script
cat > start_smartgrid.sh << 'EOF'
#!/bin/sh
# Start Smart Grid Management System

echo "Starting Smart Grid Management System..."

# Start MQTT broker
mosquitto -d

# Start InfluxDB
influxd &

# Start smart meters (in production, these would be real devices)
python3 devices/smart_meter.py &
python3 devices/solar_monitor.py &

# Start analytics engine
python3 analytics/grid_analytics.py &

# Start web dashboard
cd dashboard && npm start &

echo "Smart Grid System started!"
echo "Dashboard available at http://localhost:3000"

# Monitor logs
tail -f /var/log/mosquitto/mosquitto.log
EOF

chmod +x start_smartgrid.sh

Best Practices ๐Ÿ“Œ

  1. Redundancy - Multiple monitoring points
  2. Security - Encrypt all communications
  3. Scalability - Design for growth
  4. Real-time processing - Minimize latency
  5. Data retention - Balance storage vs. analysis needs

Troubleshooting ๐Ÿ”ง

MQTT Connection Issues

# Test MQTT broker
mosquitto_sub -t "smartgrid/#" -v

# Check MQTT logs
sudo tail -f /var/log/mosquitto/mosquitto.log

# Test publishing
mosquitto_pub -t "smartgrid/test" -m "Hello Grid"

Data Not Appearing

# Check InfluxDB
influx
> SHOW DATABASES
> USE smartgrid
> SHOW MEASUREMENTS
> SELECT * FROM meter_reading LIMIT 10

Quick Commands ๐Ÿ“‹

# Monitor all MQTT messages
mosquitto_sub -t "smartgrid/#" -v

# Check grid state
curl http://localhost:3000/api/state | jq

# Manually control battery
mosquitto_pub -t "smartgrid/battery/BAT001/command" -m '{"action":"charge","power_kw":5}'

# View analytics
curl http://localhost:3000/api/history/meter_reading/consumption_kw?start=-1h

Conclusion ๐ŸŽฏ

Youโ€™ve built a complete smart grid management system on Alpine Linux! From real-time monitoring to renewable integration and intelligent automation, your grid can now optimize energy distribution automatically. This system forms the foundation for a sustainable, efficient electrical infrastructure. Keep innovating with clean energy! โšกโœจ