Files
wled-controller/backend/src/services/schedulerService.ts
2025-12-10 18:07:21 +00:00

141 lines
4.7 KiB
TypeScript

import cron from 'node-cron';
import { scheduleService, PresetActionPayload } from './scheduleService';
import { groupService } from './groupService';
import { WledPlaylist } from '../wled/types';
interface ScheduledTask {
startTask: cron.ScheduledTask;
endTask?: cron.ScheduledTask;
scheduleId: string;
}
export class SchedulerService {
private tasks: Map<string, ScheduledTask> = new Map();
async initialize(): Promise<void> {
console.log('Initializing scheduler...');
const schedules = await scheduleService.getAllSchedules();
const enabledSchedules = schedules.filter((s) => s.enabled);
console.log(`Found ${enabledSchedules.length} enabled schedules`);
for (const schedule of enabledSchedules) {
this.registerSchedule(schedule.id);
}
}
async registerSchedule(scheduleId: string): Promise<void> {
// Remove existing task if any
this.unregisterSchedule(scheduleId);
const schedule = await scheduleService.getScheduleById(scheduleId);
if (!schedule || !schedule.enabled) {
return;
}
try {
// Register start task
const startTask = cron.schedule(
schedule.cronExpression,
async () => {
console.log(`Executing schedule: ${schedule.name} (${schedule.id})`);
await this.executeSchedule(scheduleId);
},
{
timezone: schedule.timezone,
scheduled: true,
}
);
const scheduledTask: ScheduledTask = {
startTask,
scheduleId
};
// Register end task if endCronExpression exists
if (schedule.endCronExpression) {
const endTask = cron.schedule(
schedule.endCronExpression,
async () => {
console.log(`Executing end schedule (turning off): ${schedule.name} (${schedule.id})`);
await this.turnOffGroup(schedule.groupId);
},
{
timezone: schedule.timezone,
scheduled: true,
}
);
scheduledTask.endTask = endTask;
console.log(
`Registered schedule: ${schedule.name} with start: ${schedule.cronExpression}, end: ${schedule.endCronExpression} (${schedule.timezone})`
);
} else {
console.log(
`Registered schedule: ${schedule.name} with cron: ${schedule.cronExpression} (${schedule.timezone})`
);
}
this.tasks.set(scheduleId, scheduledTask);
} catch (error) {
console.error(`Failed to register schedule ${scheduleId}:`, error);
}
}
unregisterSchedule(scheduleId: string): void {
const existing = this.tasks.get(scheduleId);
if (existing) {
existing.startTask.stop();
if (existing.endTask) {
existing.endTask.stop();
}
this.tasks.delete(scheduleId);
console.log(`Unregistered schedule: ${scheduleId}`);
}
}
private async executeSchedule(scheduleId: string): Promise<void> {
try {
const schedule = await scheduleService.getScheduleById(scheduleId);
if (!schedule) {
console.error(`Schedule ${scheduleId} not found`);
return;
}
const actionPayload = scheduleService.parseActionPayload(schedule);
if (schedule.type === 'PRESET') {
const payload = actionPayload as PresetActionPayload;
console.log(`Applying preset ${payload.presetId} to group ${schedule.groupId}`);
const result = await groupService.applyPresetToGroup(schedule.groupId, payload.presetId);
console.log(`Preset applied. Success: ${result.results.success.length}, Failed: ${result.results.failed.length}`);
} else if (schedule.type === 'PLAYLIST') {
const payload = actionPayload as WledPlaylist;
console.log(`Applying playlist to group ${schedule.groupId}`);
const result = await groupService.applyPlaylistToGroup(schedule.groupId, payload);
console.log(`Playlist applied. Success: ${result.results.success.length}, Failed: ${result.results.failed.length}`);
}
} catch (error) {
console.error(`Error executing schedule ${scheduleId}:`, error);
}
}
private async turnOffGroup(groupId: string): Promise<void> {
try {
console.log(`Turning off group ${groupId}`);
const result = await groupService.turnOffGroup(groupId);
console.log(`Group turned off. Success: ${result.results.success.length}, Failed: ${result.results.failed.length}`);
} catch (error) {
console.error(`Error turning off group ${groupId}:`, error);
}
}
async shutdown(): Promise<void> {
console.log('Shutting down scheduler...');
for (const [scheduleId] of this.tasks) {
this.unregisterSchedule(scheduleId);
}
}
}
export const schedulerService = new SchedulerService();