Energy-Monitor / app.py
Valtry's picture
Update app.py
84656de verified
Raw History Blame Contribute Delete
4.98 kB
from fastapi import FastAPI
from pydantic import BaseModel
import numpy as np
import pandas as pd
import joblib
from supabase import create_client
import os
from dotenv import load_dotenv
from datetime import datetime
# ---------------- LOAD ENV ----------------
load_dotenv()
SUPABASE_URL = os.getenv("SUPABASE_URL")
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
# ---------------- LOAD MODEL ----------------
model = joblib.load("xgb_model.pkl")
scaler = joblib.load("xgb_scaler.pkl")
le = joblib.load("label_encoder.pkl")
# ---------------- FASTAPI ----------------
app = FastAPI(title="Energy Monitor API")
# ---------------- INPUT SCHEMA ----------------
class Features(BaseModel):
mean: float
max: float
min: float
std: float
range: float
peak_count: int
slope: float
power: float
relay: bool
# ---------------- FEATURE ENGINEERING ----------------
def transform_features(data: Features):
mean = data.mean
mx = data.max
mn = data.min
std = data.std
rng = data.range
peak = data.peak_count
slope = data.slope
energy = data.power * (40 * 0.04) / 3600
ratio = mx / (mn + 1)
cv = std / (mean + 1)
peak_ratio = peak / 40
delta_mean = std * 0.8
power_density = mean / (rng + 1)
return [
mean, mx, mn, std, rng,
peak, slope,
energy, ratio,
cv, peak_ratio,
delta_mean, power_density
]
# ---------------- ROOT ----------------
@app.get("/")
def root():
return {"message": "Energy API running ๐Ÿš€"}
# ---------------- HEALTH ----------------
@app.get("/health")
def health():
return {"status": "ok"}
# ---------------- PREDICT ----------------
@app.post("/predict")
def predict(data: Features):
if not data.relay:
# No power โ†’ skip prediction
appliance = "Overloaded"
confidence = 1.0
energy = 0.0 # no energy usage
# store in DB
supabase.table("energy_logs").insert({
"timestamp": datetime.utcnow().isoformat(),
"appliance": appliance,
"confidence": confidence,
"mean": data.mean,
"max": data.max,
"min": data.min,
"std": data.std,
"range": data.range,
"peak_count": data.peak_count,
"slope": data.slope,
"energy": energy,
"power": 0.0,
"relay": data.relay
}).execute()
return {
"appliance": appliance,
"confidence": confidence,
"relay": data.relay
}
features = transform_features(data)
columns = [
"mean","max","min","std","range",
"peak_count","slope",
"energy","ratio",
"cv","peak_ratio",
"delta_mean","power_density"
]
df = pd.DataFrame([features], columns=columns)
X = scaler.transform(df)
probs = model.predict_proba(X)[0]
pred_index = np.argmax(probs)
appliance = le.inverse_transform([pred_index])[0]
confidence = float(np.max(probs))
# ๐Ÿ”ฅ Optional threshold (lower to reduce Unknown)
if confidence < 0.3:
appliance = "Unknown"
# ---------------- ENERGY CALC ----------------
time_seconds = 40 * 0.04 # 40 samples ร— 40ms = 1.6 sec
energy = (data.power * time_seconds) / 3600.0
# ---------------- STORE IN SUPABASE ----------------
supabase.table("energy_logs").insert({
"timestamp": datetime.utcnow().isoformat(),
"appliance": appliance,
"confidence": confidence,
"mean": data.mean,
"max": data.max,
"min": data.min,
"std": data.std,
"range": data.range,
"peak_count": data.peak_count,
"slope": data.slope,
"energy": energy,
"power": data.power,
"relay": data.relay,
}).execute()
return {
"appliance": appliance,
"confidence": round(confidence, 3),
"relay": data.relay
}
# ---------------- GET LATEST ----------------
@app.get("/latest")
def latest():
res = supabase.table("energy_logs") \
.select("*") \
.order("timestamp", desc=True) \
.limit(1) \
.execute()
return res.data[0] if res.data else {}
# ---------------- GET HISTORY ----------------
@app.get("/history")
def history():
res = supabase.table("energy_logs") \
.select("*") \
.order("timestamp", desc=True) \
.limit(50) \
.execute()
return res.data
# ---------------- MONTHLY ENERGY ----------------
@app.get("/monthly-energy")
def monthly_energy():
res = supabase.table("energy_logs") \
.select("energy") \
.execute()
total = sum([r["energy"] for r in res.data])
return {
"total_energy": total
}
# ---------------- SERVER ----------------
if __name__ == "__main__":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=7860)