Energy-Monitor / app.py
Valtry's picture
Update app.py
84656de verified
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)