One schedule for every charger, and a clock on the server to keep it
The charger's own cloud schedule is one window inside one box: charge between these hours, every day, and that is the whole vocabulary. A third tab on Charging holds a list instead — each line an action, a time, the days it repeats on and the chargers it acts on — and one list covers the whole account rather than each charger hiding its own. The clock is the server's. A schedule that only fires while a tab is open is a reminder, so a ticker sweeps every enabled task and fires whichever minute has come. It sends by handing a synthesised request to the same control endpoint the page's buttons use, so a scheduled command goes through the same cascade, ownership gate, rate limit and audit trail — what the owner cannot press by hand, the scheduler cannot send for them. A task names its chargers, or names none, which means all of them and keeps meaning that for a charger imported next year. Times are stored as a wall clock plus the zone they were written in, so 23:00 stays 23:00 wherever the server sits. One action per task: a charging window is the two tasks that open and close it, which is how it is read back, edited and switched off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8e4c22cfcf
commit
5a4515978f
15 files changed
+1856
-7
No files matched your search
@@ -152,6 +152,48 @@ type HomeCharger struct {
|
||||
Created string `json:"created,omitempty"`
|
||||
}
|
||||
|
||||
// ChargingTask is one line of the home-charger scheduler: an action, a time of
|
||||
// day, the days it repeats on, and the chargers it acts on. It belongs to the
|
||||
// person, like the chargers themselves — one list covering every charger they
|
||||
// own, rather than a separate schedule inside each one.
|
||||
//
|
||||
// The charger's own cloud schedule can only say "charge between these hours,
|
||||
// every day, on this one box". This says "at 23:00 on weeknights, cap these two
|
||||
// chargers at 10 A" — several tasks, each naming its own chargers.
|
||||
type ChargingTask struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// The home-charger records this task acts on. Empty means every charger the
|
||||
// owner has, including ones imported after the task was written — "all of
|
||||
// them" is a standing wish, not the list that happened to exist that day.
|
||||
Chargers []string `json:"chargers"`
|
||||
|
||||
// What to do: start, stop, limit (to Amps) or boost. One action per task; a
|
||||
// charging window is the two tasks that open and close it, which is also how
|
||||
// it is edited and how it is switched off.
|
||||
Action string `json:"action"`
|
||||
Amps float64 `json:"amps,omitempty"`
|
||||
|
||||
// When, as a 24-hour "HH:MM" read in Zone — the IANA zone the browser was in
|
||||
// when the task was written. The server's own clock is not the one the user
|
||||
// set the time by, and a laptop that travels must not move the schedule.
|
||||
Time string `json:"time"`
|
||||
Zone string `json:"zone,omitempty"`
|
||||
|
||||
// The weekdays it repeats on, 0=Sunday … 6=Saturday. Empty means every day.
|
||||
Days []int `json:"days"`
|
||||
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
// What happened the last time it fired, so a task that has been failing
|
||||
// quietly for a week says so in the list rather than in a log nobody reads.
|
||||
LastRun string `json:"lastRun,omitempty"` // RFC3339, UTC
|
||||
LastResult string `json:"lastResult,omitempty"`
|
||||
|
||||
Created string `json:"created,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceRecord is one row of the Service log for a car.
|
||||
type ServiceRecord struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
Reference in new issue
Block a user