Repository navigation
feat(climate): climate schedules, plus fan only and front defrost modes - #441
Merged
Merged
Conversation
…hedules Backend: - VehicleCommands moves to Core so the Worker can name a command's topic too. Validate now returns the English message; the Api adds the code. - VehicleCommandSender holds the topic, value check and gated publish that the command endpoint did inline, so other callers send commands the same way. Frontend: - Maintenance form classes become shared .form-stack/.form-row/.form-group/ .form-control, and .maintenance-list becomes .status-card-list. - The trip purpose buttons become a reusable ChipGroup (one-of-N or several-of-N, aria-pressed), with the purpose colours as modifiers. - useDistanceField becomes useMeasureField(units, quantity), so a temperature field round-trips the same way a distance does. - The climate popup's slider and switch rows become RangeControl and DetailListSwitch. The sliders now carry an aria-label, and the seat label follows the slider while dragging. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gateway takes four values on climate/remoteClimateState/set (on, off, front, blowingonly) and reports the same four back, but GarageStack only accepted on/off and folded the other two into ClimateOn. - The climate command accepts front and blowingonly. - New TelemetrySnapshot.ClimateMode (migration AddClimateMode) keeps the mode the gateway reports; ClimateOn is unchanged. - The climate popup shows the mode as chips while climate is switched on, sends the chosen mode, and confirms it from the reported mode. Fan only and front defrost take no temperature, so the slider is disabled for them (the gateway would restart normal climate to apply one). - The card names a running fan only or front defrost mode. - The popup's temperature and seat labels move to useClimateLabels, which the schedule form will share. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Switch climate on at a set time on chosen weekdays, or once (a schedule with
no day runs once and then switches itself off). A schedule sets the climate
mode and temperature, seat heating and the rear defroster, and can skip mild
days by the car's outside temperature. The gateway has no climate schedule of
its own, so GarageStack runs them.
Backend:
- ClimateSchedule (migration AddClimateSchedules) with a repository both
processes write through; a Version concurrency token keeps the Api's edits
and the Worker's claims and outcomes from overwriting each other.
- ClimateScheduleCalendar keeps the start time on the clock in the zone the
browser had, across daylight saving time (a skipped time runs just after the
jump, a repeated one runs once).
- /api/vehicles/{vin}/climate-schedules (list, create, update, delete).
- The Worker claims due schedules every 15 s before running them, records a
run found 10+ minutes late as missed, skips while the engine runs or on a
mild day (outside temperature from the last 3 hours only), and sends the
commands one at a time. It asks the Api to send each one on the new
vehicle_command_requested channel, so they pass the same checks and gate as
the browser's, and waits for the gateway's answer itself.
- One push per run in the new climate-schedule category (en and nl).
- tzdata named in the Api, Worker and all-in-one images.
Frontend:
- Climate schedules page (sidebar), built like Maintenance: a list of cards
and one form for add, edit, switch off and delete, reusing the climate
popup's controls, the shared chips (WeekdayPicker) and form classes.
- The climate popup links to the schedules; an optional dashboard card shows
the next start.
- StatusCard takes an optional note line under its value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neither theme told the browser its colour scheme, so the browser drew its own widgets light whatever the theme: the time picker popup of the schedule form, the Maintenance date picker, select dropdowns and the clock and calendar icons inside inputs. Each theme now sets color-scheme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The browser's time picker popup is drawn by the browser itself: no stylesheet reaches its selection colours, so even with the dark colour scheme the chosen minute showed as a light grey block. TimeOfDaySelect shows the time as hour and minute selects (minutes in steps of five, with a saved minute between steps kept), plus AM/PM when the interface language uses a 12-hour clock. The model stays a 24-hour HH:mm string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TimeOfDaySelect drops the 12-hour clock with its AM/PM select: hours 00 to 23 in every language. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dotnet format --verify-no-changes flagged the request object in ClimateSchedules_RoundTripThroughTheApi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Summary
Climate schedules: switch climate on at a set time on chosen weekdays, or once, so the car is warm (or cool) when you leave. The saic gateway has charging and battery-heating schedules but none for climate, so GarageStack runs them itself. The climate popup also gains the gateway's two other climate modes: fan only and front defrost.
How it runs
/api/vehicles/{vin}/climate-schedules) and works out each next run on save. A schedule keeps its start time on the clock in the IANA time zone the browser had when it was made, so 07:30 stays 07:30 across daylight saving time.vehicle_command_requested. The Api sends it through the same checks and one-at-a-time gate as the browser does, and handles it apart from its LISTEN loop so thecommand_resultthat frees the gate never queues behind it. The Worker waits for the gateway's answer itself.Versionconcurrency token keeps them from overwriting each other.Shared pieces (reused rather than rewritten)
VehicleCommandsmoves to Core so the Worker can name a command's topic.VehicleCommandSenderis now the one place a command is checked and published..form-stack/.form-row/.form-group/.form-control, and.maintenance-listbecomes.status-card-list.ChipGroup, which also drives the mode chips andWeekdayPicker.useDistanceFieldbecomesuseMeasureField(units, quantity), used for the °F/°C thresholds as well.RangeControlandDetailListSwitch. Its temperature and seat labels move touseClimateLabels.StatusCardtakes an optionalnoteline under its value.color-scheme, so the browser's own widgets (date pickers, select dropdowns, the icons inside inputs) follow dark mode. This also fixes the Maintenance date picker.tzdatais named in the Api, Worker and all-in-one images. All three bases ship it today; this keeps time zones working if a base drops it.Type of Change
Related Issues
None.
Checklist
AuthenticationFlowTests; frontend specs for the utils, API, store,ChipGroup,WeekdayPicker,RangeControl,TimeOfDaySelect, the form modal and the climate popup.pnpm lint,pnpm type-check, Prettier,dotnet build,dotnet format --verify-no-changes, no pending model changes)unraid/garagestack.xmlchanged (it did not; no new environment variables)Verification
/seton/result:on, then seat level 1, the schedule switched itself off, and a "Climate is on" notification was written.Failed: vehicle offline), a daily schedule stopped before the rear defroster, recordedfailedwith the car's reason, moved to the next day, and sent "Climate did not start".AddClimateMode,AddClimateSchedules) apply on PostgreSQL 18.Known limits
/setthe Api publishes. This already happens on main for manual commands.Upgrade note
Two migrations run on Api start. Update the Api and Worker together: the Worker's scheduled commands need an Api that LISTENs on
vehicle_command_requested.🤖 Generated with Claude Code