Compare commits
3 Commits
64a5d0ae7e
...
74b0d80717
| Author | SHA1 | Date | |
|---|---|---|---|
| 74b0d80717 | |||
| baa6382fba | |||
| b9b67f685a |
@@ -20,6 +20,8 @@ class ScheduleMonitor:
|
|||||||
self.last_check = 0
|
self.last_check = 0
|
||||||
self.current_schedule = None
|
self.current_schedule = None
|
||||||
self.last_applied_schedule = None
|
self.last_applied_schedule = None
|
||||||
|
self.temp_hold_start_time = None # When temporary hold was activated
|
||||||
|
self.temp_hold_duration = config.get('temp_hold_duration', 3600) # Use config value, default 1 hour
|
||||||
|
|
||||||
def should_run(self):
|
def should_run(self):
|
||||||
"""Check if it's time to run this monitor."""
|
"""Check if it's time to run this monitor."""
|
||||||
@@ -132,6 +134,45 @@ class ScheduleMonitor:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Check if schedule needs to be updated."""
|
"""Check if schedule needs to be updated."""
|
||||||
|
|
||||||
|
# ===== START: Check if temporary hold has expired =====
|
||||||
|
if not self.config.get('schedule_enabled', False) and not self.config.get('permanent_hold', False):
|
||||||
|
# We're in temporary hold mode
|
||||||
|
if self.temp_hold_start_time is None:
|
||||||
|
# Just entered hold mode, record start time
|
||||||
|
self.temp_hold_start_time = time.time()
|
||||||
|
print("⏸️ Temporary hold started - will auto-resume in {} minutes".format(
|
||||||
|
self.temp_hold_duration // 60
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
# Check if hold has expired
|
||||||
|
elapsed = time.time() - self.temp_hold_start_time
|
||||||
|
if elapsed >= self.temp_hold_duration:
|
||||||
|
# Hold expired, resume schedules
|
||||||
|
print("⏰ Temporary hold expired - resuming automatic mode")
|
||||||
|
self.config['schedule_enabled'] = True
|
||||||
|
self.config['permanent_hold'] = False
|
||||||
|
self.temp_hold_start_time = None
|
||||||
|
|
||||||
|
# Save updated config
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
with open('config.json', 'w') as f:
|
||||||
|
json.dump(self.config, f)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Send Discord notification
|
||||||
|
try:
|
||||||
|
from scripts.discord_webhook import send_discord_message
|
||||||
|
send_discord_message("⏰ Temporary hold expired - Automatic mode resumed")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Not in temporary hold, reset timer
|
||||||
|
self.temp_hold_start_time = None
|
||||||
|
# ===== END: Check if temporary hold has expired =====
|
||||||
|
|
||||||
# Find and apply active schedule
|
# Find and apply active schedule
|
||||||
active_schedule = self._find_active_schedule()
|
active_schedule = self._find_active_schedule()
|
||||||
if active_schedule:
|
if active_schedule:
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ class TempWebServer:
|
|||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response = self._get_status_page(sensors, ac_monitor, heater_monitor)
|
response = self._get_status_page(sensors, ac_monitor, heater_monitor, schedule_monitor)
|
||||||
|
|
||||||
if response is None:
|
if response is None:
|
||||||
response = self._get_status_page(sensors, ac_monitor, heater_monitor)
|
response = self._get_status_page(sensors, ac_monitor, heater_monitor, schedule_monitor)
|
||||||
|
|
||||||
conn.send('HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n')
|
conn.send('HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\n\r\n')
|
||||||
conn.sendall(response.encode('utf-8'))
|
conn.sendall(response.encode('utf-8'))
|
||||||
@@ -387,9 +387,9 @@ class TempWebServer:
|
|||||||
import sys
|
import sys
|
||||||
sys.print_exception(e)
|
sys.print_exception(e)
|
||||||
|
|
||||||
return self._get_status_page(sensors, ac_monitor, heater_monitor, show_success=True)
|
return self._get_status_page(sensors, ac_monitor, heater_monitor, schedule_monitor, show_success=True)
|
||||||
|
|
||||||
def _get_status_page(self, sensors, ac_monitor, heater_monitor, show_success=False):
|
def _get_status_page(self, sensors, ac_monitor, heater_monitor, schedule_monitor=None, show_success=False):
|
||||||
"""Generate HTML status page."""
|
"""Generate HTML status page."""
|
||||||
print("DEBUG: Generating status page...")
|
print("DEBUG: Generating status page...")
|
||||||
try:
|
try:
|
||||||
@@ -487,21 +487,61 @@ class TempWebServer:
|
|||||||
inside_temp_str = "{:.1f}".format(inside_temp) if isinstance(inside_temp, float) else str(inside_temp)
|
inside_temp_str = "{:.1f}".format(inside_temp) if isinstance(inside_temp, float) else str(inside_temp)
|
||||||
outside_temp_str = "{:.1f}".format(outside_temp) if isinstance(outside_temp, float) else str(outside_temp)
|
outside_temp_str = "{:.1f}".format(outside_temp) if isinstance(outside_temp, float) else str(outside_temp)
|
||||||
|
|
||||||
# ===== START: Add HOLD mode banner =====
|
# ===== START: Add HOLD mode banner with countdown timer =====
|
||||||
hold_banner = ""
|
hold_banner = ""
|
||||||
|
|
||||||
|
# Calculate remaining time for temporary hold
|
||||||
|
temp_hold_remaining = ""
|
||||||
|
if not config.get('schedule_enabled', False) and not config.get('permanent_hold', False):
|
||||||
|
# In temporary hold - check if we have schedule_monitor with timer
|
||||||
|
if schedule_monitor and hasattr(schedule_monitor, 'temp_hold_start_time'):
|
||||||
|
if schedule_monitor.temp_hold_start_time is not None:
|
||||||
|
# Calculate elapsed time
|
||||||
|
elapsed = time.time() - schedule_monitor.temp_hold_start_time
|
||||||
|
# Calculate remaining time
|
||||||
|
remaining = schedule_monitor.temp_hold_duration - elapsed
|
||||||
|
|
||||||
|
if remaining > 0:
|
||||||
|
# Convert to minutes
|
||||||
|
mins_remaining = int(remaining // 60)
|
||||||
|
|
||||||
|
# Format the display text
|
||||||
|
if mins_remaining > 60:
|
||||||
|
# Show hours and minutes for long durations
|
||||||
|
hours = mins_remaining // 60
|
||||||
|
mins = mins_remaining % 60
|
||||||
|
temp_hold_remaining = " - {}h {}m remaining".format(hours, mins)
|
||||||
|
elif mins_remaining > 1:
|
||||||
|
# Show just minutes
|
||||||
|
temp_hold_remaining = " - {} min remaining".format(mins_remaining)
|
||||||
|
elif mins_remaining == 1:
|
||||||
|
# Show singular "minute"
|
||||||
|
temp_hold_remaining = " - 1 minute remaining"
|
||||||
|
else:
|
||||||
|
# Less than 1 minute left
|
||||||
|
secs_remaining = int(remaining)
|
||||||
|
temp_hold_remaining = " - {}s remaining".format(secs_remaining)
|
||||||
|
else:
|
||||||
|
# Timer expired (should auto-resume soon)
|
||||||
|
temp_hold_remaining = " - Resuming..."
|
||||||
|
|
||||||
if config.get('permanent_hold', False):
|
if config.get('permanent_hold', False):
|
||||||
|
# PERMANENT HOLD - No timer, stays until user resumes or reboot
|
||||||
hold_banner = """
|
hold_banner = """
|
||||||
<div style="background: linear-gradient(135deg, #e74c3c, #c0392b); color: white; padding: 15px; border-radius: 10px; text-align: center; font-weight: bold; margin-bottom: 20px; box-shadow: 0 4px 8px rgba(0,0,0,0.2); animation: fadeIn 0.5s;">
|
<div style="background: linear-gradient(135deg, #e74c3c, #c0392b); color: white; padding: 15px; border-radius: 10px; text-align: center; font-weight: bold; margin-bottom: 20px; box-shadow: 0 4px 8px rgba(0,0,0,0.2); animation: fadeIn 0.5s;">
|
||||||
🛑 PERMANENT HOLD - Schedules disabled (Manual control only)
|
🛑 PERMANENT HOLD - Schedules disabled (Manual control only)
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
elif not config.get('schedule_enabled', False) and has_schedules:
|
elif not config.get('schedule_enabled', False) and has_schedules:
|
||||||
|
# TEMPORARY HOLD - Show countdown timer if available
|
||||||
|
# Note: We'll need to accept schedule_monitor as parameter to access timer
|
||||||
hold_banner = """
|
hold_banner = """
|
||||||
<div style="background: linear-gradient(135deg, #f39c12, #e67e22); color: white; padding: 15px; border-radius: 10px; text-align: center; font-weight: bold; margin-bottom: 20px; box-shadow: 0 4px 8px rgba(0,0,0,0.2); animation: fadeIn 0.5s;">
|
<div style="background: linear-gradient(135deg, #f39c12, #e67e22); color: white; padding: 15px; border-radius: 10px; text-align: center; font-weight: bold; margin-bottom: 20px; box-shadow: 0 4px 8px rgba(0,0,0,0.2); animation: fadeIn 0.5s;">
|
||||||
⏸️ TEMPORARY HOLD - Manual override active (Schedule paused)
|
⏸️ TEMPORARY HOLD - Manual override active{remaining}
|
||||||
</div>
|
</div>
|
||||||
"""
|
""".format(remaining=temp_hold_remaining)
|
||||||
# ===== END: Add HOLD mode banner =====
|
# ===== END: Add HOLD mode banner with countdown timer =====
|
||||||
|
# Final HTML assembly
|
||||||
html = """
|
html = """
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"ac_swing": 1.0,
|
"ac_swing": 1.0,
|
||||||
"heater_target": 72.0,
|
"heater_target": 72.0,
|
||||||
"heater_swing": 2.0,
|
"heater_swing": 2.0,
|
||||||
|
"temp_hold_duration": 3600,
|
||||||
"schedules": [
|
"schedules": [
|
||||||
{
|
{
|
||||||
"time": "06:00",
|
"time": "06:00",
|
||||||
|
|||||||
Reference in New Issue
Block a user