Add form handling for AC and heater settings with Discord notification

This commit is contained in:
Aaron 2025-11-05 20:34:18 -05:00
parent a4329da607
commit 02db62725d

View File

@ -2,7 +2,7 @@ import socket
import time import time
class TempWebServer: class TempWebServer:
"""Simple web server for viewing temperatures.""" """Simple web server for viewing temperatures and adjusting settings."""
def __init__(self, port=80): def __init__(self, port=80):
self.port = port self.port = port
self.socket = None self.socket = None
@ -30,8 +30,12 @@ class TempWebServer:
conn.settimeout(3.0) conn.settimeout(3.0)
request = conn.recv(1024).decode('utf-8') request = conn.recv(1024).decode('utf-8')
# Generate response # Check if this is a POST request (form submission)
response = self._get_status_page(sensors, ac_monitor, heater_monitor) if 'POST /update' in request:
response = self._handle_update(request, sensors, ac_monitor, heater_monitor)
else:
# Regular GET request
response = self._get_status_page(sensors, ac_monitor, heater_monitor)
conn.send('HTTP/1.1 200 OK\r\n') conn.send('HTTP/1.1 200 OK\r\n')
conn.send('Content-Type: text/html; charset=utf-8\r\n') conn.send('Content-Type: text/html; charset=utf-8\r\n')
@ -43,7 +47,55 @@ class TempWebServer:
except Exception as e: except Exception as e:
print(f"Web server error: {e}") print(f"Web server error: {e}")
def _get_status_page(self, sensors, ac_monitor, heater_monitor): def _handle_update(self, request, sensors, ac_monitor, heater_monitor):
"""Handle form submission and update settings."""
try:
# Extract form data from POST body
body = request.split('\r\n\r\n')[1] if '\r\n\r\n' in request else ''
params = {}
for pair in body.split('&'):
if '=' in pair:
key, value = pair.split('=', 1)
params[key] = float(value)
# Update AC settings
if 'ac_target' in params and ac_monitor:
ac_monitor.target_temp = params['ac_target']
print(f"AC target updated to {params['ac_target']}°F")
if 'ac_swing' in params and ac_monitor:
ac_monitor.temp_swing = params['ac_swing']
print(f"AC swing updated to {params['ac_swing']}°F")
# Update heater settings
if 'heater_target' in params and heater_monitor:
heater_monitor.target_temp = params['heater_target']
print("Heater target updated to {}°F".format(params['heater_target']))
if 'heater_swing' in params and heater_monitor:
heater_monitor.temp_swing = params['heater_swing']
print("Heater swing updated to {}°F".format(params['heater_swing']))
# Send Discord notification
from scripts.discord_webhook import send_discord_message
ac_target_str = str(params.get('ac_target', 'N/A'))
ac_swing_str = str(params.get('ac_swing', 'N/A'))
heater_target_str = str(params.get('heater_target', 'N/A'))
heater_swing_str = str(params.get('heater_swing', 'N/A'))
message = "Settings Updated - AC: {}F +/- {}F | Heater: {}F +/- {}F".format(
ac_target_str, ac_swing_str, heater_target_str, heater_swing_str
)
send_discord_message(message)
except Exception as e:
print("Error updating settings: {}".format(e))
# Return updated page
return self._get_status_page(sensors, ac_monitor, heater_monitor, show_success=True)
def _get_status_page(self, sensors, ac_monitor, heater_monitor, show_success=False):
"""Generate HTML status page.""" """Generate HTML status page."""
# Get current temperatures # Get current temperatures
inside_temps = sensors['inside'].read_all_temps(unit='F') inside_temps = sensors['inside'].read_all_temps(unit='F')
@ -60,13 +112,20 @@ class TempWebServer:
current_time = time.localtime() current_time = time.localtime()
time_str = f"{current_time[0]}-{current_time[1]:02d}-{current_time[2]:02d} {current_time[3]:02d}:{current_time[4]:02d}:{current_time[5]:02d}" time_str = f"{current_time[0]}-{current_time[1]:02d}-{current_time[2]:02d} {current_time[3]:02d}:{current_time[4]:02d}:{current_time[5]:02d}"
# Success message
success_html = """
<div class="success-message">
Settings updated successfully!
</div>
""" if show_success else ""
html = """ html = """
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>🌱 Auto Garden</title> <title>🌱 Auto Garden</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="refresh" content="10"> <meta http-equiv="refresh" content="30">
<meta charset="utf-8"> <meta charset="utf-8">
<style> <style>
* {{ * {{
@ -185,6 +244,69 @@ class TempWebServer:
0%, 100% {{ opacity: 1; }} 0%, 100% {{ opacity: 1; }}
50% {{ opacity: 0.8; }} 50% {{ opacity: 0.8; }}
}} }}
.controls {{
margin-top: 20px;
padding: 20px;
background: #f8f9fa;
border-radius: 10px;
}}
.control-group {{
margin: 15px 0;
}}
.control-label {{
display: block;
font-size: 16px;
font-weight: 600;
color: #34495e;
margin-bottom: 8px;
}}
input[type="number"] {{
width: 100%;
padding: 12px;
font-size: 18px;
border: 2px solid #ddd;
border-radius: 8px;
transition: border-color 0.3s;
}}
input[type="number"]:focus {{
outline: none;
border-color: #667eea;
}}
.btn {{
width: 100%;
padding: 15px;
font-size: 18px;
font-weight: bold;
color: white;
background: linear-gradient(135deg, #667eea, #764ba2);
border: none;
border-radius: 10px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 1px;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
transition: transform 0.2s;
}}
.btn:hover {{
transform: translateY(-2px);
}}
.btn:active {{
transform: translateY(0);
}}
.success-message {{
background: #2ecc71;
color: white;
padding: 15px;
border-radius: 10px;
text-align: center;
font-weight: bold;
margin-bottom: 20px;
animation: fadeIn 0.5s;
}}
@keyframes fadeIn {{
from {{ opacity: 0; }}
to {{ opacity: 1; }}
}}
.footer {{ .footer {{
text-align: center; text-align: center;
color: white; color: white;
@ -207,12 +329,17 @@ class TempWebServer:
.temp-grid {{ .temp-grid {{
grid-template-columns: 1fr; grid-template-columns: 1fr;
}} }}
.status {{
flex-direction: column;
}}
}} }}
</style> </style>
</head> </head>
<body> <body>
<h1>🌱 Auto Garden Dashboard</h1> <h1>🌱 Auto Garden Dashboard</h1>
{success_message}
<div class="temp-grid"> <div class="temp-grid">
<div class="card temp-card"> <div class="card temp-card">
<div class="temp-icon">🏠</div> <div class="temp-icon">🏠</div>
@ -242,15 +369,48 @@ class TempWebServer:
<div class="targets">Target: {heater_target}°F ± {heater_swing}°F</div> <div class="targets">Target: {heater_target}°F ± {heater_swing}°F</div>
</div> </div>
</div> </div>
<form method="POST" action="/update" class="controls">
<h2 style="text-align: center; color: #34495e; margin-bottom: 20px;"> Adjust Settings</h2>
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px;">
<div>
<div class="control-group">
<label class="control-label"> AC Target (°F)</label>
<input type="number" name="ac_target" value="{ac_target}" step="0.5" min="60" max="85">
</div>
<div class="control-group">
<label class="control-label"> AC Swing (°F)</label>
<input type="number" name="ac_swing" value="{ac_swing}" step="0.5" min="0.5" max="5">
</div>
</div>
<div>
<div class="control-group">
<label class="control-label">🔥 Heater Target (°F)</label>
<input type="number" name="heater_target" value="{heater_target}" step="0.5" min="60" max="85">
</div>
<div class="control-group">
<label class="control-label">🔥 Heater Swing (°F)</label>
<input type="number" name="heater_swing" value="{heater_swing}" step="0.5" min="0.5" max="5">
</div>
</div>
</div>
<div class="control-group" style="margin-top: 20px;">
<button type="submit" class="btn">💾 Save Settings</button>
</div>
</form>
</div> </div>
<div class="footer"> <div class="footer">
Last updated: {time}<br> Last updated: {time}<br>
🔄 Auto-refresh every 10 seconds 🔄 Auto-refresh every 30 seconds
</div> </div>
</body> </body>
</html> </html>
""".format( """.format(
success_message=success_html,
inside_temp=f"{inside_temp:.1f}" if isinstance(inside_temp, float) else inside_temp, inside_temp=f"{inside_temp:.1f}" if isinstance(inside_temp, float) else inside_temp,
outside_temp=f"{outside_temp:.1f}" if isinstance(outside_temp, float) else outside_temp, outside_temp=f"{outside_temp:.1f}" if isinstance(outside_temp, float) else outside_temp,
ac_status=ac_status, ac_status=ac_status,