import socket import time class TempWebServer: """Simple web server for viewing temperatures and adjusting settings.""" def __init__(self, port=80): self.port = port self.socket = None self.sensors = {} def start(self): """Start the web server (non-blocking).""" try: self.socket = socket.socket() self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(('0.0.0.0', self.port)) self.socket.listen(1) self.socket.setblocking(False) # Non-blocking mode print(f"Web server started on port {self.port}") except Exception as e: print(f"Failed to start web server: {e}") def check_requests(self, sensors, ac_monitor=None, heater_monitor=None): """Check for incoming requests (call in main loop).""" if not self.socket: return try: conn, addr = self.socket.accept() conn.settimeout(3.0) request = conn.recv(1024).decode('utf-8') # Check if this is a POST request (form submission) 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('Content-Type: text/html; charset=utf-8\r\n') conn.send('Connection: close\r\n\r\n') conn.sendall(response.encode('utf-8')) conn.close() except OSError: pass # No connection, continue except Exception as e: print(f"Web server error: {e}") def _save_config_to_file(self, ac_monitor, heater_monitor): """Save current settings to config.json file.""" try: import json config = { 'ac_target': ac_monitor.target_temp, 'ac_swing': ac_monitor.temp_swing, 'heater_target': heater_monitor.target_temp, 'heater_swing': heater_monitor.temp_swing } with open('config.json', 'w') as f: json.dump(config, f) print("Settings saved to config.json") return True except Exception as e: print("Error saving config: {}".format(e)) return False 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("AC target updated to {}°F".format(params['ac_target'])) if 'ac_swing' in params and ac_monitor: ac_monitor.temp_swing = params['ac_swing'] print("AC swing updated to {}°F".format(params['ac_swing'])) # 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'])) # Save settings to file if self._save_config_to_file(ac_monitor, heater_monitor): print("Settings persisted to disk") # 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.""" # Get current temperatures inside_temps = sensors['inside'].read_all_temps(unit='F') outside_temps = sensors['outside'].read_all_temps(unit='F') inside_temp = list(inside_temps.values())[0] if inside_temps else "N/A" outside_temp = list(outside_temps.values())[0] if outside_temps else "N/A" # Get AC/Heater status ac_status = "ON" if ac_monitor and ac_monitor.ac.get_state() else "OFF" heater_status = "ON" if heater_monitor and heater_monitor.heater.get_state() else "OFF" # Get current time 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}" # Success message success_html = """
""" if show_success else "" html = """