Skip to content

Add scheduled power on / off via Wake-on-LAN and ATX - #1537

Open
0xfacade wants to merge 6 commits into
jetkvm:devfrom
0xfacade:feat/power-scheduler
Open

Add scheduled power on / off via Wake-on-LAN and ATX#1537
0xfacade wants to merge 6 commits into
jetkvm:devfrom
0xfacade:feat/power-scheduler

Conversation

@0xfacade

@0xfacade 0xfacade commented Jul 26, 2026

Copy link
Copy Markdown

No existing issue.

Summary

I needed the ability to turn on a power-hungry home server on a schedule (and I don't have another device that could trigger it via MQTT), so I added a settings page that allows defining schedules to turn the host on and off.

Features:

  • choose between Wake-on-LAN and ATX extension
  • choose timezone, weekdays and time
  • choose between on, off and force off (Wake-on-LAN: only on)
  • supports multiple schedules
  • schedules can be toggled on and off

This was entirely coded by Claude Code with Opus 5, but I'll review it thoroughly if there is interest to merge this (I am a SWE). I did not find a policy regarding LLM contributions - if I missed it and such contributions are not welcome, my apologies! I've deployed this to my device and it appears to work fine. I'll keep it running for a while and repeat back on the reliability.

Screenshots:

image image image

Checklist

  • Ran make test_e2e locally and passed (mostly - currently don't have a guest that reads mouse events - can follow up if you'll consider merging this)
  • Linked to issue(s) above by issue number (e.g. Closes #<issue-number>)
  • One problem per PR (no unrelated changes)
  • Lints pass; CI green
  • Tricky parts are commented in code

Florian Behrens and others added 6 commits July 26, 2026 16:32
Describes a recurring power action as a weekday set plus a wall-clock time
in an IANA timezone, and renders it to the 6-field crontab format the
jiggler already uses.

Storing the schedule structurally rather than as a raw crontab lets the UI
offer a weekday/time picker and lets both ends render it consistently.

The model lives in internal/ and has no dependency on the device runtime,
so its rules can be unit tested on any platform. The root kvm package
cannot: its only test file is gated behind linux && arm, and adding an
untagged one there would force the test binary to link the ARM native libs
on an x86 CI runner.

Wake-on-LAN is restricted to powering on, since a magic packet cannot do
anything else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Locks down the format contract with gocron: a crontab we generate but the
library rejects would silently disable a schedule at runtime. Also asserts
the TZ= prefix is honoured rather than ignored, which is what makes
per-schedule timezones work at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Wires the schedule model to gocron and to the two power methods, and
persists schedules in the device config.

Two details worth calling out:

  - The scheduler uses its own gocron instance. rpcSetJigglerConfig removes
    every job on the jiggler's scheduler, which would silently drop all
    power schedules if the two shared one.

  - ATX actions consult the power LED before pressing, so a "power on"
    schedule can't toggle an already-running host off.

Disabled schedules are kept in the config but get no job, which is how
temporarily disabling one is implemented.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Registers getPowerSchedules/setPowerSchedules and starts the scheduler at
boot. Writes replace the whole list and are validated before they are
applied or persisted, so a rejected payload leaves the running schedule
untouched.

Timezone options reuse the existing getTimezones handler.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Source-locale strings only; other locales fall back until translated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds a Scheduler settings page listing every schedule with a checkbox for
temporarily disabling one without deleting it, a next-run line, and an
inline add/edit form.

The form derives its action options from the selected method, so
Wake-on-LAN offers only "power on" and the ATX method is disabled outright
unless the ATX extension is active. The MAC picker is populated from the
saved Wake-on-LAN devices with a custom-MAC fallback; the address is copied
onto the schedule rather than referenced, so deleting a saved device cannot
leave a schedule pointing at nothing.

Next-run labels compare wall-clock fields inside the schedule's own
timezone instead of converting to absolute time. This keeps the label
DST-safe to compute without a date library; it is display-only, as the
actual firing is gocron's job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Florian Behrens seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@0xfacade 0xfacade changed the title Feat/power scheduler Add scheduled power on / off via Wake-on-LAN and ATX Jul 26, 2026
Comment thread config.go
LocalAuthMode string `json:"localAuthMode"` //TODO: fix it with migration
LocalLoopbackOnly bool `json:"local_loopback_only"`
WakeOnLanDevices []WakeOnLanDevice `json:"wake_on_lan_devices"`
PowerSchedules []powersched.Schedule `json:"power_schedules"`

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose here it would make sense to use a shorter reference so that the diff becomes smaller.

@0xfacade

0xfacade commented Jul 27, 2026

Copy link
Copy Markdown
Author

Let me know if this is something you are interested in merging, then I'll review the LLM generated code very carefully and in detail (or close the PR if you are not interested).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants