feat: auto-timezone update from source node GPS position#2925
Draft
rancur wants to merge 1 commit into
Draft
Conversation
Adds an opt-in service that periodically reads a designated source node's GPS position and computes the local IANA timezone via geo-tz. When the source node moves more than a configurable distance (default 20 mi) or the computed tz changes, the new timezone is persisted to settings. Designed for mobile MeshMonitor deployments (RV / boat / overlanding) where the source node moves between timezones but the server's TZ env stays static. Closes/relates to upstream issue Yeraze#2924. Scope of this PR is intentionally backend-only: - New service src/server/services/geofenceTimezoneService.ts modeled after autoDeleteByDistanceService for consistency. - 3 user-configurable settings (default off): geofenceTzEnabled, geofenceTzSourceNodeId, geofenceTzThresholdMiles. - 4 service-managed settings: geofenceTzDetected, geofenceTzLastLat, geofenceTzLastLon, geofenceTzLastCheckedAt. - Service registration in startup flow (src/server/server.ts) plus settings-change restart hook (src/server/routes/settingsRoutes.ts). - 13 vitest tests covering disabled / no-node / no-gps / first-run / debounce / threshold-trigger / tz-change / lookup-failure paths. NOT in this PR (deliberate, see Yeraze#2924 discussion): - React admin UI for the new settings (follow-up) - Auto-restart of the server on tz change (TZ env is startup-only in current architecture; this is the harder design question) Default off — zero behavior change unless operator opts in.
Owner
|
So this is just to reconfigure the MeshMonitor install, not the actual node? |
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.
Closes/relates
Relates to #2924 — opening as DRAFT so the maintainer can react to concrete code without committing to merge. The issue thread has the full design proposal; this PR is the foundational backend implementation.
Motivation
Mobile MeshMonitor instances (RV / boat / overlanding setups) typically have a GPS-equipped node that moves with the deployment. The server's
TZenv stays static, so log timestamps and scheduled tasks (backup_time,system_backup_time,maintenanceTime) drift relative to local time as the deployment crosses timezones.This PR adds an opt-in service that reads a designated source node's GPS position and persists the detected IANA timezone to settings whenever the node crosses a configurable distance threshold or the computed tz changes.
Design summary
geofenceTzEnabled: boolean— defaultfalsegeofenceTzSourceNodeId: string— accepts!hexor bare node-numgeofenceTzThresholdMiles: number— default20geofenceTzIntervalMinutes— default15)geofenceTzDetected— last computed IANA tzgeofenceTzLastLat/geofenceTzLastLon— last-applied position (for debounce)geofenceTzLastCheckedAt— ms timestampautoDeleteByDistanceServicefor consistency: same lifecycle (start/stop/runNow/getStatus), same isRunning guard, same staggered initial delay.geo-tz(8.1.6, MIT) — chosen overtz-lookupbecause:calculateDistanceHaversine util (src/utils/distance.ts) — same primitive used byautoDeleteByDistanceService.VALID_SETTINGS_KEYSwas extended.TZenv is startup-only — applying a detected tz to running schedulers/log timestamps requires a process restart. That's the harder design question and is deferred to a follow-up PR per the issue's "design alignment first" comment.What's in this PR
src/server/services/geofenceTimezoneService.tssrc/server/services/geofenceTimezoneService.test.tssrc/server/constants/settings.tsVALID_SETTINGS_KEYSsrc/server/server.tssrc/server/routes/settingsRoutes.tsSettingsCallbacksextension + change-handlerpackage.json/package-lock.jsongeo-tz^8.1.6 depREADME.mdNet signal LOC (excluding lock file): ~624 added, ~14 removed.
What's NOT in this PR (deliberate)
SettingsTab.tsxextension following the documenteduseCallbackdep-array pattern inCLAUDE.md).TZenv is startup-only in this architecture. Open design space:process.env.TZ = newTzand accept that already-runningsetInterval/setTimeoutschedules don't pick it upprocess.exit(0)and rely on container/PM2 restart policyOption 3 is what this PR does. I think it's the right minimal foundation.
Tests
13 new tests in
src/server/services/geofenceTimezoneService.test.ts:start()/stop()lifecyclestart()is idempotentAll pass under
npx vitest run. Full suite (4696 tests) also green.Backwards compat
Default OFF — zero behavior change unless the operator explicitly enables
geofenceTzEnabled. No schema migration, no new tables. New settings keys are append-only additions toVALID_SETTINGS_KEYS.Maintainer-respect notes
This is filed as DRAFT to respect the design-alignment-first workflow in
CLAUDE.md. Happy to:geofenceTz*prefix vs.autoTimezone*vs. something else)SettingsTabextension vs. dedicated panel)POST /api/services/geofence-tz/run-now,GET /api/services/geofence-tz/status) if that pattern is preferred over implicit restart-on-settings-changeReference implementation
A working personal-deployment version (Python single-script that polls + restarts the docker container) has been running on the contributor's mobile node for several weeks. This PR ports the algorithm into the upstream architecture rather than asking operators to bolt on a host-level cron.