Initial commit - EcoCharge backend API + admin
This commit is contained in:
106
app.py
Normal file
106
app.py
Normal file
@@ -0,0 +1,106 @@
|
||||
from flask import Flask, jsonify, render_template, request, redirect, url_for, session
|
||||
from flask_cors import CORS
|
||||
from config import Config
|
||||
import psycopg2
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object(Config)
|
||||
app.secret_key = app.config["SECRET_KEY"]
|
||||
|
||||
CORS(app)
|
||||
|
||||
conn = psycopg2.connect(
|
||||
host="localhost",
|
||||
port=5432,
|
||||
database="ecocharge",
|
||||
user="eco",
|
||||
password="eco_pass"
|
||||
)
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
return jsonify({
|
||||
"message": "API EcoCharge en ligne"
|
||||
})
|
||||
|
||||
@app.route("/api/status")
|
||||
def status():
|
||||
return jsonify({
|
||||
"project": "EcoCharge",
|
||||
"api": "ok",
|
||||
"database": "postgresql_connected"
|
||||
})
|
||||
|
||||
@app.route("/admin/login", methods=["GET", "POST"])
|
||||
def admin_login():
|
||||
if request.method == "POST":
|
||||
username = request.form.get("username")
|
||||
password = request.form.get("password")
|
||||
|
||||
if username == "admin" and password == "admin123":
|
||||
session["admin_logged_in"] = True
|
||||
return redirect(url_for("admin_dashboard"))
|
||||
|
||||
return render_template("login.html", error="Identifiants incorrects")
|
||||
|
||||
return render_template("login.html")
|
||||
|
||||
@app.route("/admin/dashboard", methods=["GET", "POST"])
|
||||
def admin_dashboard():
|
||||
if not session.get("admin_logged_in"):
|
||||
return redirect(url_for("admin_login"))
|
||||
|
||||
cur = conn.cursor()
|
||||
|
||||
if request.method == "POST":
|
||||
min_battery = request.form.get("min_battery")
|
||||
max_temp = request.form.get("max_temp")
|
||||
min_power = request.form.get("min_power")
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('min_battery_voltage', %s)
|
||||
ON CONFLICT (key)
|
||||
DO UPDATE SET value = EXCLUDED.value
|
||||
""", (min_battery,))
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('max_battery_temperature', %s)
|
||||
ON CONFLICT (key)
|
||||
DO UPDATE SET value = EXCLUDED.value
|
||||
""", (max_temp,))
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('min_solar_power', %s)
|
||||
ON CONFLICT (key)
|
||||
DO UPDATE SET value = EXCLUDED.value
|
||||
""", (min_power,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
cur.execute("SELECT value FROM settings WHERE key = 'min_battery_voltage'")
|
||||
row1 = cur.fetchone()
|
||||
|
||||
cur.execute("SELECT value FROM settings WHERE key = 'max_battery_temperature'")
|
||||
row2 = cur.fetchone()
|
||||
|
||||
cur.execute("SELECT value FROM settings WHERE key = 'min_solar_power'")
|
||||
row3 = cur.fetchone()
|
||||
|
||||
settings = {
|
||||
"min_battery": row1[0] if row1 else "10.5",
|
||||
"max_temp": row2[0] if row2 else "45",
|
||||
"min_power": row3[0] if row3 else "5"
|
||||
}
|
||||
|
||||
return render_template("admin_dashboard.html", settings=settings)
|
||||
|
||||
@app.route("/admin/logout")
|
||||
def admin_logout():
|
||||
session.pop("admin_logged_in", None)
|
||||
return redirect(url_for("admin_login"))
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000, debug=True)
|
||||
13
config.py
Normal file
13
config.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = os.getenv("SECRET_KEY", "ecocharge_secret_2026")
|
||||
|
||||
DB_HOST = os.getenv("DB_HOST", "localhost")
|
||||
DB_PORT = int(os.getenv("DB_PORT", 3306))
|
||||
DB_NAME = os.getenv("DB_NAME", "ecocharge")
|
||||
DB_USER = os.getenv("DB_USER", "root")
|
||||
DB_PASSWORD = os.getenv("DB_PASSWORD", "root")
|
||||
323
database.sql
Normal file
323
database.sql
Normal file
@@ -0,0 +1,323 @@
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
\restrict ijnV8LNUvXkT7zfNUtK8rYjTPMZ7E4a8Dp7BES0I4ggucAotiMgPl90yvhq0XQq
|
||||
|
||||
-- Dumped from database version 18.3 (Debian 18.3-1.pgdg13+1)
|
||||
-- Dumped by pg_dump version 18.3 (Debian 18.3-1.pgdg13+1)
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET transaction_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- Name: settings; Type: TABLE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE TABLE public.settings (
|
||||
id integer NOT NULL,
|
||||
key character varying(50),
|
||||
value character varying(100)
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.settings OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: settings_id_seq; Type: SEQUENCE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.settings_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE public.settings_id_seq OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.settings_id_seq OWNED BY public.settings.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: system_status; Type: TABLE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE TABLE public.system_status (
|
||||
id integer NOT NULL,
|
||||
device_name character varying(50),
|
||||
online boolean,
|
||||
last_seen timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.system_status OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: system_status_id_seq; Type: SEQUENCE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.system_status_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE public.system_status_id_seq OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: system_status_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.system_status_id_seq OWNED BY public.system_status.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: telemetry; Type: TABLE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE TABLE public.telemetry (
|
||||
id integer NOT NULL,
|
||||
"timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP,
|
||||
upv double precision,
|
||||
ipv double precision,
|
||||
ubat double precision,
|
||||
ibat double precision,
|
||||
power double precision,
|
||||
temperature double precision,
|
||||
luminosity double precision,
|
||||
humidity double precision
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.telemetry OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: telemetry_id_seq; Type: SEQUENCE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.telemetry_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE public.telemetry_id_seq OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: telemetry_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.telemetry_id_seq OWNED BY public.telemetry.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: users; Type: TABLE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE TABLE public.users (
|
||||
id integer NOT NULL,
|
||||
username character varying(50),
|
||||
password character varying(255),
|
||||
is_admin boolean DEFAULT false
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.users OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.users_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
ALTER SEQUENCE public.users_id_seq OWNER TO eco;
|
||||
|
||||
--
|
||||
-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: settings id; Type: DEFAULT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settings ALTER COLUMN id SET DEFAULT nextval('public.settings_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: system_status id; Type: DEFAULT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.system_status ALTER COLUMN id SET DEFAULT nextval('public.system_status_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: telemetry id; Type: DEFAULT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.telemetry ALTER COLUMN id SET DEFAULT nextval('public.telemetry_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: users id; Type: DEFAULT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: settings; Type: TABLE DATA; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
COPY public.settings (id, key, value) FROM stdin;
|
||||
1 temp_max 60
|
||||
2 battery_min 11
|
||||
3 solar_max 22
|
||||
\.
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: system_status; Type: TABLE DATA; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
COPY public.system_status (id, device_name, online, last_seen) FROM stdin;
|
||||
1 esp32 f 2026-03-05 15:07:28.827398
|
||||
\.
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: telemetry; Type: TABLE DATA; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
COPY public.telemetry (id, "timestamp", upv, ipv, ubat, ibat, power, temperature, luminosity, humidity) FROM stdin;
|
||||
1 2026-03-05 14:51:17.119119 18.5 0.7 12.4 0.5 13 32 500 45
|
||||
2 2026-03-05 15:07:19.878569 19 0.8 12.5 0.5 14 31 600 40
|
||||
\.
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
COPY public.users (id, username, password, is_admin) FROM stdin;
|
||||
1 admin admin123 t
|
||||
\.
|
||||
|
||||
|
||||
--
|
||||
-- Name: settings_id_seq; Type: SEQUENCE SET; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('public.settings_id_seq', 3, true);
|
||||
|
||||
|
||||
--
|
||||
-- Name: system_status_id_seq; Type: SEQUENCE SET; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('public.system_status_id_seq', 1, true);
|
||||
|
||||
|
||||
--
|
||||
-- Name: telemetry_id_seq; Type: SEQUENCE SET; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('public.telemetry_id_seq', 2, true);
|
||||
|
||||
|
||||
--
|
||||
-- Name: users_id_seq; Type: SEQUENCE SET; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('public.users_id_seq', 1, true);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settings settings_key_key; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settings
|
||||
ADD CONSTRAINT settings_key_key UNIQUE (key);
|
||||
|
||||
|
||||
--
|
||||
-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.settings
|
||||
ADD CONSTRAINT settings_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: system_status system_status_pkey; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.system_status
|
||||
ADD CONSTRAINT system_status_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: telemetry telemetry_pkey; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.telemetry
|
||||
ADD CONSTRAINT telemetry_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.users
|
||||
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: users users_username_key; Type: CONSTRAINT; Schema: public; Owner: eco
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.users
|
||||
ADD CONSTRAINT users_username_key UNIQUE (username);
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict ijnV8LNUvXkT7zfNUtK8rYjTPMZ7E4a8Dp7BES0I4ggucAotiMgPl90yvhq0XQq
|
||||
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Flask==3.0.3
|
||||
flask-cors==4.0.1
|
||||
python-dotenv==1.0.1
|
||||
mysql-connector-python==9.0.0
|
||||
Werkzeug==3.0.3
|
||||
78
templates/admin_dashboard.html
Normal file
78
templates/admin_dashboard.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Admin EcoCharge</title>
|
||||
<style>
|
||||
body{
|
||||
font-family: Arial;
|
||||
background:#f5f7fb;
|
||||
padding:40px;
|
||||
}
|
||||
|
||||
.card{
|
||||
background:white;
|
||||
padding:30px;
|
||||
border-radius:10px;
|
||||
box-shadow:0 4px 12px rgba(0,0,0,0.1);
|
||||
max-width:500px;
|
||||
}
|
||||
|
||||
h2{
|
||||
margin-top:0;
|
||||
}
|
||||
|
||||
label{
|
||||
display:block;
|
||||
margin-top:15px;
|
||||
}
|
||||
|
||||
input{
|
||||
width:100%;
|
||||
padding:8px;
|
||||
margin-top:5px;
|
||||
}
|
||||
|
||||
button{
|
||||
margin-top:20px;
|
||||
padding:10px;
|
||||
background:#2563eb;
|
||||
color:white;
|
||||
border:none;
|
||||
border-radius:6px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
a{
|
||||
display:block;
|
||||
margin-top:20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="card">
|
||||
|
||||
<h2>Administration EcoCharge</h2>
|
||||
|
||||
<form method="POST">
|
||||
|
||||
<label>Seuil batterie minimum</label>
|
||||
<input type="number" step="0.1" name="min_battery" value="{{ settings.min_battery }}">
|
||||
|
||||
<label>Température max batterie</label>
|
||||
<input type="number" step="0.1" name="max_temp" value="{{ settings.max_temp }}">
|
||||
|
||||
<label>Puissance solaire minimum</label>
|
||||
<input type="number" step="0.1" name="min_power" value="{{ settings.min_power }}">
|
||||
|
||||
<button type="submit">Sauvegarder</button>
|
||||
|
||||
</form>
|
||||
|
||||
<a href="/admin/logout">Se déconnecter</a>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
87
templates/login.html
Normal file
87
templates/login.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Connexion Admin - EcoCharge</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f4f7fb;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 360px;
|
||||
margin: 100px auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 18px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 25px;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
margin-top: 15px;
|
||||
color: #374151;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<h2>Connexion Admin</h2>
|
||||
<form method="POST" action="/admin/login">
|
||||
<label for="username">Nom d'utilisateur</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
|
||||
<label for="password">Mot de passe</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
|
||||
<button type="submit">Se connecter</button>
|
||||
</form>
|
||||
|
||||
{% if error %}
|
||||
<p class="error">{{ error }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user