diff --git a/Scripts/scheduler.py b/Scripts/scheduler.py new file mode 100644 index 0000000..8f59f54 --- /dev/null +++ b/Scripts/scheduler.py @@ -0,0 +1,143 @@ +import time + +class ScheduleMonitor: + """Monitor that checks and applies temperature schedules.""" + + def __init__(self, ac_monitor, heater_monitor, config, interval=60): + """ + Initialize schedule monitor. + + Args: + ac_monitor: ACMonitor instance + heater_monitor: HeaterMonitor instance + config: Configuration dict with schedules + interval: How often to check schedule (seconds) + """ + self.ac_monitor = ac_monitor + self.heater_monitor = heater_monitor + self.config = config + self.interval = interval + self.last_check = 0 + self.current_schedule = None + self.last_applied_schedule = None + + def _parse_time(self, time_str): + """Convert time string 'HH:MM' to minutes since midnight.""" + try: + parts = time_str.split(':') + hours = int(parts[0]) + minutes = int(parts[1]) + return hours * 60 + minutes + except: + return None + + def _get_current_minutes(self): + """Get current time in minutes since midnight.""" + t = time.localtime() + return t[3] * 60 + t[4] # hours * 60 + minutes + + def _find_active_schedule(self): + """Find which schedule should be active right now.""" + if not self.config.get('schedule_enabled', False): + return None + + schedules = self.config.get('schedules', []) + if not schedules: + return None + + current_minutes = self._get_current_minutes() + + # Sort schedules by time + sorted_schedules = [] + for schedule in schedules: + schedule_minutes = self._parse_time(schedule['time']) + if schedule_minutes is not None: + sorted_schedules.append((schedule_minutes, schedule)) + + sorted_schedules.sort() + + # Find the most recent schedule that has passed + active_schedule = None + for schedule_minutes, schedule in sorted_schedules: + if current_minutes >= schedule_minutes: + active_schedule = schedule + else: + break + + # If no schedule found (before first schedule), use last schedule from yesterday + if active_schedule is None and sorted_schedules: + active_schedule = sorted_schedules[-1][1] + + return active_schedule + + def _apply_schedule(self, schedule): + """Apply a schedule's settings to the monitors.""" + if not schedule: + return + + # Check if this is a different schedule than last applied + schedule_id = schedule.get('time', '') + schedule.get('name', '') + if schedule_id == self.last_applied_schedule: + return # Already applied + + try: + # Update AC settings if provided + if 'ac_target' in schedule: + self.ac_monitor.target_temp = float(schedule['ac_target']) + + if 'ac_swing' in schedule: + self.ac_monitor.temp_swing = float(schedule['ac_swing']) + + # Update heater settings if provided + if 'heater_target' in schedule: + self.heater_monitor.target_temp = float(schedule['heater_target']) + + if 'heater_swing' in schedule: + self.heater_monitor.temp_swing = float(schedule['heater_swing']) + + # Log the change + schedule_name = schedule.get('name', 'Unnamed') + print("\n" + "="*50) + print("Schedule Applied: {}".format(schedule_name)) + print("="*50) + print("AC Target: {}°F".format(self.ac_monitor.target_temp)) + print("Heater Target: {}°F".format(self.heater_monitor.target_temp)) + print("="*50 + "\n") + + # Send Discord notification + try: + from scripts.discord_webhook import send_discord_message + message = "🕐 Schedule '{}' applied - AC: {}°F | Heater: {}°F".format( + schedule_name, + self.ac_monitor.target_temp, + self.heater_monitor.target_temp + ) + send_discord_message(message) + except: + pass + + self.last_applied_schedule = schedule_id + + except Exception as e: + print("Error applying schedule: {}".format(e)) + + def run(self): + """Check if schedule needs to be updated.""" + current_time = time.time() + + # Only check at specified interval + if current_time - self.last_check < self.interval: + return + + self.last_check = current_time + + # Find and apply active schedule + active_schedule = self._find_active_schedule() + if active_schedule: + self._apply_schedule(active_schedule) + + def reload_config(self, new_config): + """Reload configuration (called when settings are updated via web).""" + self.config = new_config + self.last_applied_schedule = None # Force re-application + print("Schedule configuration reloaded") \ No newline at end of file