Compare commits
6 Commits
99afba25c4
...
eb34922da6
| Author | SHA1 | Date | |
|---|---|---|---|
| eb34922da6 | |||
| 6156f87b05 | |||
| e82fcf46aa | |||
| f53ae05842 | |||
| 8c92f86842 | |||
| 93b68098ea |
68
Scripts/heating.py
Normal file
68
Scripts/heating.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
from machine import Pin
|
||||||
|
import time
|
||||||
|
|
||||||
|
class HeaterController:
|
||||||
|
"""Control heater via opto-coupler relay."""
|
||||||
|
def __init__(self, relay_pin=16, min_run_time=300, min_off_time=180):
|
||||||
|
"""
|
||||||
|
relay_pin: GPIO pin connected to opto-coupler input
|
||||||
|
min_run_time: Minimum seconds heater must run before turning off (prevent short cycling)
|
||||||
|
min_off_time: Minimum seconds heater must be off before turning on (element protection)
|
||||||
|
"""
|
||||||
|
self.relay = Pin(relay_pin, Pin.OUT)
|
||||||
|
self.relay.off() # Start with heater off (relay normally open)
|
||||||
|
|
||||||
|
self.min_run_time = min_run_time
|
||||||
|
self.min_off_time = min_off_time
|
||||||
|
|
||||||
|
self.is_on = False
|
||||||
|
self.last_state_change = time.ticks_ms()
|
||||||
|
|
||||||
|
def turn_on(self):
|
||||||
|
"""Turn heater on if minimum off time has elapsed."""
|
||||||
|
if self.is_on:
|
||||||
|
return True # Already on
|
||||||
|
|
||||||
|
now = time.ticks_ms()
|
||||||
|
time_since_change = time.ticks_diff(now, self.last_state_change) / 1000
|
||||||
|
|
||||||
|
if time_since_change < self.min_off_time:
|
||||||
|
remaining = int(self.min_off_time - time_since_change)
|
||||||
|
print(f"Heater cooldown: {remaining}s remaining before can turn on")
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.relay.on()
|
||||||
|
self.is_on = True
|
||||||
|
self.last_state_change = now
|
||||||
|
print("Heater turned ON")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def turn_off(self):
|
||||||
|
"""Turn heater off if minimum run time has elapsed."""
|
||||||
|
if not self.is_on:
|
||||||
|
return True # Already off
|
||||||
|
|
||||||
|
now = time.ticks_ms()
|
||||||
|
time_since_change = time.ticks_diff(now, self.last_state_change) / 1000
|
||||||
|
|
||||||
|
if time_since_change < self.min_run_time:
|
||||||
|
remaining = int(self.min_run_time - time_since_change)
|
||||||
|
print(f"Heater minimum runtime: {remaining}s remaining before can turn off")
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.relay.off()
|
||||||
|
self.is_on = False
|
||||||
|
self.last_state_change = now
|
||||||
|
print("Heater turned OFF")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
"""Return current heater state."""
|
||||||
|
return self.is_on
|
||||||
|
|
||||||
|
def force_off(self):
|
||||||
|
"""Emergency shut off (bypasses timers)."""
|
||||||
|
self.relay.off()
|
||||||
|
self.is_on = False
|
||||||
|
self.last_state_change = time.ticks_ms()
|
||||||
|
print("Heater FORCE OFF")
|
||||||
@ -142,6 +142,52 @@ class ACMonitor(Monitor):
|
|||||||
|
|
||||||
# Else: within temp_swing range, maintain current state
|
# Else: within temp_swing range, maintain current state
|
||||||
|
|
||||||
|
class HeaterMonitor(Monitor):
|
||||||
|
"""Monitor temperature and control heater automatically."""
|
||||||
|
def __init__(self, heater_controller, temp_sensor, target_temp=70.0, temp_swing=2.0, interval=30):
|
||||||
|
"""
|
||||||
|
heater_controller: HeaterController instance
|
||||||
|
temp_sensor: TemperatureSensor instance (inside temp)
|
||||||
|
target_temp: Target temperature in °F
|
||||||
|
temp_swing: Temperature swing allowed (prevents rapid cycling)
|
||||||
|
interval: Seconds between checks
|
||||||
|
"""
|
||||||
|
super().__init__(interval)
|
||||||
|
self.heater = heater_controller
|
||||||
|
self.sensor = temp_sensor
|
||||||
|
self.target_temp = target_temp
|
||||||
|
self.temp_swing = temp_swing
|
||||||
|
self.last_notified_state = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Check temperature and control heater."""
|
||||||
|
temps = self.sensor.read_all_temps(unit='F')
|
||||||
|
if not temps:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Use first sensor reading (assuming single inside sensor)
|
||||||
|
current_temp = list(temps.values())[0]
|
||||||
|
|
||||||
|
# Heating logic with temperature swing
|
||||||
|
# Turn ON if: temp < target - temp_swing
|
||||||
|
# Turn OFF if: temp > target + temp_swing
|
||||||
|
|
||||||
|
if current_temp < (self.target_temp - self.temp_swing):
|
||||||
|
# Too cold, turn heater on
|
||||||
|
if self.heater.turn_on():
|
||||||
|
if not self.last_notified_state:
|
||||||
|
send_discord_message(f"🔥 Heater turned ON - Current: {current_temp:.1f}°F, Target: {self.target_temp:.1f}°F")
|
||||||
|
self.last_notified_state = True
|
||||||
|
|
||||||
|
elif current_temp > (self.target_temp + self.temp_swing):
|
||||||
|
# Warm enough, turn heater off
|
||||||
|
if self.heater.turn_off():
|
||||||
|
if self.last_notified_state:
|
||||||
|
send_discord_message(f"✅ Heater turned OFF - Current: {current_temp:.1f}°F, Target: {self.target_temp:.1f}°F")
|
||||||
|
self.last_notified_state = False
|
||||||
|
|
||||||
|
# Else: within temp_swing range, maintain current state
|
||||||
|
|
||||||
class WiFiMonitor(Monitor):
|
class WiFiMonitor(Monitor):
|
||||||
"""Monitor WiFi connection and handle reconnection."""
|
"""Monitor WiFi connection and handle reconnection."""
|
||||||
def __init__(self, wifi, led, interval=5, reconnect_cooldown=60):
|
def __init__(self, wifi, led, interval=5, reconnect_cooldown=60):
|
||||||
|
|||||||
@ -2,36 +2,65 @@ import network
|
|||||||
import time
|
import time
|
||||||
from secrets import secrets
|
from secrets import secrets
|
||||||
|
|
||||||
RECONNECT_COOLDOWN_MS = 60000 # 60 seconds
|
def connect_wifi(led=None):
|
||||||
|
"""Connect to WiFi using credentials from secrets.py"""
|
||||||
def connect_wifi(led=None, timeout=10):
|
try:
|
||||||
"""
|
wlan = network.WLAN(network.STA_IF)
|
||||||
Connect to WiFi using secrets['ssid'] / secrets['password'].
|
|
||||||
If `led` (machine.Pin) is provided, pulse it once on successful connect.
|
|
||||||
Returns the WLAN object or None on failure.
|
|
||||||
"""
|
|
||||||
wifi = network.WLAN(network.STA_IF)
|
|
||||||
wifi.active(True)
|
|
||||||
|
|
||||||
# print("Connecting to WiFi...", end="")
|
|
||||||
wifi.connect(secrets['ssid'], secrets['password'])
|
|
||||||
|
|
||||||
# Wait for connection with timeout
|
|
||||||
max_wait = timeout
|
|
||||||
while max_wait > 0:
|
|
||||||
if wifi.status() < 0 or wifi.status() >= 3:
|
|
||||||
break
|
|
||||||
max_wait -= 1
|
|
||||||
# print(".", end="")
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
if wifi.isconnected():
|
# Deactivate first if already active (fixes EPERM error)
|
||||||
# print("\nConnected! Network config:", wifi.ifconfig())
|
if wlan.active():
|
||||||
if led:
|
wlan.active(False)
|
||||||
led.on()
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
led.off()
|
|
||||||
return wifi
|
wlan.active(True)
|
||||||
else:
|
time.sleep(1) # Give it time to initialize
|
||||||
# print("\nConnection failed!")
|
|
||||||
return None
|
except OSError as e:
|
||||||
|
print(f"WiFi activation error: {e}")
|
||||||
|
print("Attempting reset...")
|
||||||
|
try:
|
||||||
|
# Force deinit and reinit
|
||||||
|
wlan.deinit()
|
||||||
|
time.sleep(2)
|
||||||
|
wlan = network.WLAN(network.STA_IF)
|
||||||
|
wlan.active(True)
|
||||||
|
time.sleep(1)
|
||||||
|
except Exception as e2:
|
||||||
|
print(f"WiFi reset failed: {e2}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not wlan.isconnected():
|
||||||
|
print('Connecting to WiFi...')
|
||||||
|
try:
|
||||||
|
wlan.connect(secrets['ssid'], secrets['password'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Connection attempt failed: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Wait for connection with timeout
|
||||||
|
max_wait = 20
|
||||||
|
while max_wait > 0:
|
||||||
|
if wlan.isconnected():
|
||||||
|
break
|
||||||
|
if led:
|
||||||
|
led.toggle()
|
||||||
|
time.sleep(0.5)
|
||||||
|
max_wait -= 1
|
||||||
|
print('.', end='')
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
if not wlan.isconnected():
|
||||||
|
print('WiFi connection failed!')
|
||||||
|
if led:
|
||||||
|
led.off()
|
||||||
|
return None
|
||||||
|
|
||||||
|
if led:
|
||||||
|
# Single pulse on successful connection
|
||||||
|
led.on()
|
||||||
|
time.sleep(0.5)
|
||||||
|
led.off()
|
||||||
|
|
||||||
|
print('Connected to WiFi')
|
||||||
|
return wlan
|
||||||
188
Scripts/web_server.py
Normal file
188
Scripts/web_server.py
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
import socket
|
||||||
|
import time
|
||||||
|
|
||||||
|
class TempWebServer:
|
||||||
|
"""Simple web server for viewing temperatures."""
|
||||||
|
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')
|
||||||
|
|
||||||
|
# Generate response
|
||||||
|
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\r\n')
|
||||||
|
conn.send('Connection: close\r\n\r\n')
|
||||||
|
conn.sendall(response)
|
||||||
|
conn.close()
|
||||||
|
except OSError:
|
||||||
|
pass # No connection, continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Web server error: {e}")
|
||||||
|
|
||||||
|
def _get_status_page(self, sensors, ac_monitor, heater_monitor):
|
||||||
|
"""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}"
|
||||||
|
|
||||||
|
html = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Auto Garden Status</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta http-equiv="refresh" content="10">
|
||||||
|
<style>
|
||||||
|
body {{
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}}
|
||||||
|
h1 {{
|
||||||
|
color: #2c3e50;
|
||||||
|
text-align: center;
|
||||||
|
}}
|
||||||
|
.card {{
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 10px 0;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}}
|
||||||
|
.temp-display {{
|
||||||
|
font-size: 48px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}}
|
||||||
|
.inside {{ color: #e74c3c; }}
|
||||||
|
.outside {{ color: #3498db; }}
|
||||||
|
.label {{
|
||||||
|
font-size: 18px;
|
||||||
|
color: #7f8c8d;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}}
|
||||||
|
.status {{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-top: 20px;
|
||||||
|
}}
|
||||||
|
.status-item {{
|
||||||
|
text-align: center;
|
||||||
|
}}
|
||||||
|
.status-indicator {{
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 10px;
|
||||||
|
}}
|
||||||
|
.on {{
|
||||||
|
background-color: #2ecc71;
|
||||||
|
color: white;
|
||||||
|
}}
|
||||||
|
.off {{
|
||||||
|
background-color: #95a5a6;
|
||||||
|
color: white;
|
||||||
|
}}
|
||||||
|
.footer {{
|
||||||
|
text-align: center;
|
||||||
|
color: #7f8c8d;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
}}
|
||||||
|
.targets {{
|
||||||
|
font-size: 14px;
|
||||||
|
color: #7f8c8d;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>🌱 Auto Garden Status</h1>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="label">Inside Temperature</div>
|
||||||
|
<div class="temp-display inside">{inside_temp}°F</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="label">Outside Temperature</div>
|
||||||
|
<div class="temp-display outside">{outside_temp}°F</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="status">
|
||||||
|
<div class="status-item">
|
||||||
|
<div class="label">❄️ Air Conditioning</div>
|
||||||
|
<div class="status-indicator {ac_class}">{ac_status}</div>
|
||||||
|
<div class="targets">Target: {ac_target}°F ± {ac_swing}°F</div>
|
||||||
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<div class="label">🔥 Heater</div>
|
||||||
|
<div class="status-indicator {heater_class}">{heater_status}</div>
|
||||||
|
<div class="targets">Target: {heater_target}°F ± {heater_swing}°F</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
Last updated: {time}<br>
|
||||||
|
Auto-refresh every 10 seconds
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""".format(
|
||||||
|
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,
|
||||||
|
ac_status=ac_status,
|
||||||
|
ac_class="on" if ac_status == "ON" else "off",
|
||||||
|
heater_status=heater_status,
|
||||||
|
heater_class="on" if heater_status == "ON" else "off",
|
||||||
|
ac_target=ac_monitor.target_temp if ac_monitor else "N/A",
|
||||||
|
ac_swing=ac_monitor.temp_swing if ac_monitor else "N/A",
|
||||||
|
heater_target=heater_monitor.target_temp if heater_monitor else "N/A",
|
||||||
|
heater_swing=heater_monitor.temp_swing if heater_monitor else "N/A",
|
||||||
|
time=time_str
|
||||||
|
)
|
||||||
|
return html
|
||||||
78
main.py
78
main.py
@ -1,21 +1,56 @@
|
|||||||
from machine import Pin
|
from machine import Pin
|
||||||
import time
|
import time
|
||||||
from scripts.networking import connect_wifi
|
import network
|
||||||
from scripts.discord_webhook import send_discord_message
|
|
||||||
from scripts.monitors import TemperatureMonitor, WiFiMonitor, ACMonitor, run_monitors
|
|
||||||
from scripts.temperature_sensor import TemperatureSensor, get_configured_sensors
|
|
||||||
from scripts.air_conditioning import ACController
|
|
||||||
|
|
||||||
# Initialize pins (LED light onboard)
|
# Initialize pins (LED light onboard)
|
||||||
led = Pin("LED", Pin.OUT)
|
led = Pin("LED", Pin.OUT)
|
||||||
led.low()
|
led.low()
|
||||||
|
|
||||||
|
# Hard reset WiFi interface before connecting
|
||||||
|
print("Initializing WiFi...")
|
||||||
|
try:
|
||||||
|
wlan = network.WLAN(network.STA_IF)
|
||||||
|
wlan.deinit()
|
||||||
|
time.sleep(2)
|
||||||
|
print("WiFi interface reset complete")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"WiFi reset warning: {e}")
|
||||||
|
|
||||||
|
# Import after WiFi reset
|
||||||
|
from scripts.networking import connect_wifi
|
||||||
|
from scripts.discord_webhook import send_discord_message
|
||||||
|
from scripts.monitors import TemperatureMonitor, WiFiMonitor, ACMonitor, HeaterMonitor, run_monitors
|
||||||
|
from scripts.temperature_sensor import TemperatureSensor
|
||||||
|
from scripts.air_conditioning import ACController
|
||||||
|
from scripts.heating import HeaterController
|
||||||
|
from scripts.web_server import TempWebServer
|
||||||
|
|
||||||
# Connect to WiFi
|
# Connect to WiFi
|
||||||
wifi = connect_wifi(led)
|
wifi = connect_wifi(led)
|
||||||
|
|
||||||
# Send startup message if connected
|
# Print WiFi details
|
||||||
if wifi and wifi.isconnected():
|
if wifi and wifi.isconnected():
|
||||||
|
ifconfig = wifi.ifconfig()
|
||||||
|
print("\n" + "="*50)
|
||||||
|
print("WiFi Connected Successfully!")
|
||||||
|
print("="*50)
|
||||||
|
print(f"IP Address: {ifconfig[0]}")
|
||||||
|
print(f"Subnet Mask: {ifconfig[1]}")
|
||||||
|
print(f"Gateway: {ifconfig[2]}")
|
||||||
|
print(f"DNS Server: {ifconfig[3]}")
|
||||||
|
print(f"Web Interface: http://{ifconfig[0]}")
|
||||||
|
print("="*50 + "\n")
|
||||||
|
|
||||||
|
# Send startup message
|
||||||
send_discord_message("Pico W online and connected ✅")
|
send_discord_message("Pico W online and connected ✅")
|
||||||
|
else:
|
||||||
|
print("\n" + "="*50)
|
||||||
|
print("WiFi Connection Failed!")
|
||||||
|
print("="*50 + "\n")
|
||||||
|
|
||||||
|
# Start web server
|
||||||
|
web_server = TempWebServer(port=80)
|
||||||
|
web_server.start()
|
||||||
|
|
||||||
# Sensor configuration registry (moved from temperature_sensor.py)
|
# Sensor configuration registry (moved from temperature_sensor.py)
|
||||||
SENSOR_CONFIG = {
|
SENSOR_CONFIG = {
|
||||||
@ -32,8 +67,9 @@ SENSOR_CONFIG = {
|
|||||||
'alert_low': 68.0
|
'alert_low': 68.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Initialize sensors based on configuration
|
# Initialize sensors based on configuration
|
||||||
def get_configured_sensors(): # define the function here
|
def get_configured_sensors():
|
||||||
"""Return dictionary of configured sensor instances."""
|
"""Return dictionary of configured sensor instances."""
|
||||||
sensors = {}
|
sensors = {}
|
||||||
for key, config in SENSOR_CONFIG.items():
|
for key, config in SENSOR_CONFIG.items():
|
||||||
@ -41,20 +77,35 @@ def get_configured_sensors(): # define the function here
|
|||||||
return sensors
|
return sensors
|
||||||
|
|
||||||
# Get configured sensors
|
# Get configured sensors
|
||||||
sensors = get_configured_sensors() # Call the function here
|
sensors = get_configured_sensors()
|
||||||
|
|
||||||
# AC Controller options
|
# AC Controller options
|
||||||
ac_controller = ACController(
|
ac_controller = ACController(
|
||||||
relay_pin=15,
|
relay_pin=15,
|
||||||
min_run_time=30, # min run time in seconds
|
min_run_time=30, # min run time in seconds
|
||||||
min_off_time=5 # min off time in seconds
|
min_off_time=5 # min off time in seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
ac_monitor = ACMonitor(
|
ac_monitor = ACMonitor(
|
||||||
ac_controller=ac_controller,
|
ac_controller=ac_controller,
|
||||||
temp_sensor=sensors['inside'], # <-- This is your inside temperature sensor
|
temp_sensor=sensors['inside'],
|
||||||
target_temp=77.0, # target temperature in Fahrenheit
|
target_temp=77.0, # target temperature in Fahrenheit
|
||||||
temp_swing=1.0, # temp swing target_temp-temp_swing to target_temp+temp_swing
|
temp_swing=1.0, # temp swing target_temp-temp_swing to target_temp+temp_swing
|
||||||
|
interval=30 # check temp every x seconds
|
||||||
|
)
|
||||||
|
|
||||||
|
# Heater Controller options
|
||||||
|
heater_controller = HeaterController(
|
||||||
|
relay_pin=16,
|
||||||
|
min_run_time=30, # min run time in seconds
|
||||||
|
min_off_time=5 # min off time in seconds
|
||||||
|
)
|
||||||
|
|
||||||
|
heater_monitor = HeaterMonitor(
|
||||||
|
heater_controller=heater_controller,
|
||||||
|
temp_sensor=sensors['inside'],
|
||||||
|
target_temp=80.0, # target temperature in Fahrenheit
|
||||||
|
temp_swing=2.0, # temp swing
|
||||||
interval=30 # check temp every x seconds
|
interval=30 # check temp every x seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,6 +113,7 @@ ac_monitor = ACMonitor(
|
|||||||
monitors = [
|
monitors = [
|
||||||
WiFiMonitor(wifi, led, interval=5, reconnect_cooldown=60), # Wifi monitor, Check WiFi every 5s
|
WiFiMonitor(wifi, led, interval=5, reconnect_cooldown=60), # Wifi monitor, Check WiFi every 5s
|
||||||
ac_monitor, # AC monitor
|
ac_monitor, # AC monitor
|
||||||
|
heater_monitor, # Heater monitor
|
||||||
TemperatureMonitor( # Inside temperature monitor
|
TemperatureMonitor( # Inside temperature monitor
|
||||||
sensor=sensors['inside'],
|
sensor=sensors['inside'],
|
||||||
label=SENSOR_CONFIG['inside']['label'],
|
label=SENSOR_CONFIG['inside']['label'],
|
||||||
@ -84,7 +136,11 @@ monitors = [
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
print("Starting monitoring loop...")
|
||||||
|
print("Press Ctrl+C to stop\n")
|
||||||
|
|
||||||
# Main monitoring loop
|
# Main monitoring loop
|
||||||
while True:
|
while True:
|
||||||
run_monitors(monitors)
|
run_monitors(monitors)
|
||||||
|
web_server.check_requests(sensors, ac_monitor, heater_monitor)
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
Loading…
x
Reference in New Issue
Block a user