Open
Conversation
- Fix TypeError 'Cannot read properties of undefined (reading toFixed)' in Charging.tsx by using typeof checks and nullish coalescing - Add nil checks to all Latest() API handlers (motor, climate, security, media, location) to return 404 instead of 200 with null body - Prevents frontend crash when API returns null/undefined for nullable fields Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix Energy.tsx: guard .toFixed() calls on session.cost, charge_energy_added, and charger breakdown data - Fix Dashboard.tsx: guard .toFixed() on inside_temp, outside_temp, charge_rate, and time_to_full_charge which can be null from API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 5-second context timeout was too short for 12+ sequential DB operations in the telemetry goroutine. When the first operation (UpdateState) exceeded 5s, the context was cancelled and ALL subsequent tracking functions (motor, climate, location, etc.) silently failed — no data was persisted to snapshot tables. Also add logging for VIN lookup failures which were previously completely silent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The comprehensive telemetry panels feature (#27) added new columns and tables to the Go code but no database migration was created. This caused all API endpoints to return 500 errors: - column 'hvac_ac_enabled' does not exist - column 'di_torque_actual_f' does not exist - column 'homelink_device_count' does not exist - relation 'location_snapshots' does not exist - relation 'media_snapshots' does not exist Adds 34 columns to motor_snapshots, 21 to climate_snapshots, 17 to security_events. Creates 7 new tables: location_snapshots, media_snapshots, safety_snapshots, user_preference_snapshots, vehicle_config_snapshots, tire_pressure_snapshots, charging_telemetry. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
With fleet telemetry batching every 100ms, each batch was spawning a goroutine with 12+ sequential DB operations. This saturated the 25-conn pool and caused context deadline exceeded on every write — including vehicle state updates and health checks. Now snapshot writes (motor, climate, security, charging, location, etc.) are throttled to once every 10 seconds per vehicle. This reduces DB write load by ~50-100x while still providing near-real-time data for the UI panels. Vehicle state updates are also gated to prevent the UpdateState call from consuming connections on every batch. SSE/MQTT broadcasting and signal counting remain unthrottled for real-time UI updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vehicle in standby/charging mode sends signals like ChargeRateMilePerHour, BatteryLevel, Soc, OutsideTemp, Gear, Odometer — but the tracking functions only gated on a narrow set of signals, causing all writes to be skipped during standby. Expanded gate conditions: - trackCharging: add BatteryLevel, Soc, ChargeRateMilePerHour, ChargeAmps - trackClimate: add OutsideTemp - trackMotor: add Gear, Odometer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…g 'online' - Extract detectVehicleState() helper used by both UpdateState and trackStateTransition - Add ChargeRateMilePerHour and ChargeAmps as charging state indicators - Vehicle now correctly shows 'charging' when charge rate > 0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backend returns 'is_read' (JSON) but frontend expected 'read', causing alerts to always appear unread. Updated all frontend references to use 'is_read'. Also fixed chatbot SQL query using wrong column name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
404 causes React Query to retry infinitely, resulting in the Security page flickering/skeleton looping. Changed all 5 latest handlers (security, climate, motor, media, location) to return 200 with null body when no data exists yet. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix division-by-zero in Charging, Drives, BatteryHealth, BatteryCells - Fix React hooks-in-loop violation in Vehicles.tsx (FleetSummary, BatteryComparison) - Fix InsightsEngine null safety on trend data access - Add retry:1 to Layout sidebar queries to prevent backend hammering - Invalidate vehicle state caches on vehicle delete - Add nil check to tire_pressure_handler Latest() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backend: - analytics_handler: check DB errors instead of ignoring, reduce limit 10K→2K - alert_handler: check GetByID error after UpdateRule - search_handler: remove duplicate rows.Close() (defer handles it) - tire_pressure_handler: nil check on Latest (prev commit) Telemetry: - Fix TOCTTOU race in write throttle - use single Lock for check+set - Log alert rule DB query failures instead of silent swallow Router: - Wire missing /api-keys routes (List, Create, Delete, Revoke) Database: - geofence_repo: wrap Update in transaction, check errors instead of _, _ - vehicle_state_repo: distinguish ErrNoRows from real DB errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- MotorSnapshot: add 34 fields (di_torque_actual, di_axle_speed, di_state, di_stator_temp, di_heatsink_t, di_inverter_t, di_motor_current, di_v_bat for all motor positions, plus hvil, brake_pedal_pos, cruise_set_speed, drive_rail) - ClimateSnapshot: add 21 fields (hvac_ac_enabled, seat heaters (5 positions), seat cooling/vent, steering wheel heat, climate keeper, defrost, wiper heat, rear display hvac) - SecurityEvent: add 17 fields (valet mode, speed limit, seat belts, tonneau, lights, guest mode mobile access, center display, paired phone keys) - AlertRule: remove phantom notify_push/notify_mqtt (not in Go model) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add StartCleanup() goroutine that removes stale streaming state entries every 10 minutes (3x past stale timeout threshold) - Cleans both streamingState and lastWriteAt maps to prevent unbounded growth - Simplify lastWriteMu from RWMutex to Mutex (only uses Lock now) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Position: add fan_status field - Geofence: add created_at, updated_at fields - NotificationLog: add scheduled_at, latency_ms fields - Dashboard: sort vehicle IDs in query key for cache stability Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When fleet telemetry is actively streaming for a vehicle, CurrentState() now builds the VehicleState from DB tables (positions, climate_snapshots, security_events, charging_telemetry) instead of making a Tesla API call. Priority order: 1. Fleet Telemetry (if IsVehicleStreaming) → build from DB snapshots 2. Fleet API (if token valid) → live Tesla API call 3. Cached position (if API suspended/unavailable) Benefits: - ~150x faster response (DB query vs Tesla API roundtrip) - Saves Tesla API quota (no unnecessary calls for streaming vehicles) - Prevents vehicle wake-up from API polling - data_source field in response indicates source for debugging The response now includes 'data_source' field: 'fleet_telemetry', 'fleet_api', or 'cached'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migration 18 adds SQL functions that mirror frontend conversion logic:
- convert_distance(val, 'mi') — km → miles
- convert_speed(val, 'mi') — km/h → mph
- convert_temp(val, 'F') — °C → °F
- convert_efficiency(val, 'mi') — Wh/km → Wh/mi
- convert_pressure(val, 'mi') — bar → psi
When target is NULL, reads user preference from settings table.
Also adds unit_*() helpers that return the label ('mph', '°F', etc).
Grafana usage:
SELECT convert_temp(inside_temp) FROM climate_snapshots;
SELECT convert_distance(distance) || ' ' || unit_distance() FROM drives;
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adding fan_status field accidentally dropped the 'export interface Drive {'
line, causing TS1128 build error.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Alerts.tsx: remove notify_push/notify_mqtt from createAlertRule call (fields removed from AlertRule interface) - api.ts: make Geofence created_at/updated_at optional (server-generated, not sent on create/update) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ction buildStateFromDB now: - Always checks charging_telemetry (not gated on state=='charging') - Overrides stale position battery_level with fresh charging telemetry value - Detects charging from ChargeRateMph/ChargeAmps/ChargeState in telemetry - Uses charging telemetry range values when available - Sets state to 'charging' and is_charging=true based on telemetry data Fixes: Dashboard showing 59% (stale position) instead of 75% (real from charging_telemetry), showing 'Online' instead of 'Charging' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vehicle may report IsStreaming=true but only send 1 signal (e.g. ChargeRateMilePerHour while charging). This left position data 17h stale and all panels empty because the worker skipped the vehicle. buildStateFromDB now checks if position is >5min old. If so, falls through to Fleet API to get complete fresh data. Charging telemetry enrichment still applies when fresh. This ensures Dashboard always shows accurate battery%, temps, lock status etc. regardless of how many telemetry signals the vehicle sends. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
State endpoint fixes: - Battery: use Soc when BatteryLevel is nil AND position is stale (was checking BatteryLevel==0 which missed stale 59% from position) - Charging detection: add ChargerVoltage>0, DCChargingPower>0, ACChargingPower>0 as indicators. Also treat fresh charging_telemetry record (<2min) as proof of charging - Lock status: remains false when no security snapshot exists (vehicle doesn't send Locked signal while sleeping/charging) — will be populated by Fleet API fallback when needed EnergyFlow page: - Add .toFixed(1) to charger_voltage and charge_amps display (was showing 112.001999... instead of 112.0) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
extractPosition() required GPS Location to create a position record. While charging/parked, vehicle doesn't send Location but DOES send Soc, OutsideTemp, BatteryLevel, ChargerVoltage, etc. All these signals were silently discarded because the GPS gate returned nil. Now creates position records when battery, temp, speed, or odometer signals are present even without GPS. Also expanded trackCharging gate conditions to include ChargerVoltage, EstBatteryRange, IdealBatteryRange, EnergyRemaining, PackVoltage, PackCurrent, ChargeLimitSoc — signals the vehicle actually sends while charging but were being rejected by the gate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Sidebar vehicle card: use convertDistance + distanceUnit for range (was hardcoded 'km') - Dashboard: fix hardcoded 'mi' on miles_to_arrival — now converts to user's preferred unit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When data is nil, writeJSON wrote nothing (empty body). Frontend res.json() throws SyntaxError parsing empty string, React Query treats it as error, retries every 3s → infinite skeleton loop. Now writes literal 'null' JSON which parses correctly to null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Migration 19 adds to settings table: - gas_price_per_unit (default 3.50) — price per gallon or liter - gas_unit (gallon/liter) — fuel volume unit - gas_efficiency_mpg (default 25) — comparison ICE vehicle MPG Updated: Go model, settings repo (SELECT/INSERT/Upsert), TS interface, Settings page UI with gas price, unit selector, and comparison MPG fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds gas_price_history table with effective_from/effective_to periods. When gas price is changed in Settings, the old period is closed and a new one is opened. Old charging sessions compare with the gas price that was active during that period. Includes gas_price_at(timestamp) SQL function for Grafana: SELECT g.price_per_unit FROM gas_price_at(session.start_date) g; Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add automated gas price polling from the U.S. Energy Information Administration (EIA) API for EV vs ICE cost comparison. Backend: - Add GasPriceConfig to config with env vars (GAS_PRICE_ENABLED, GAS_PRICE_POLL_INTERVAL, GAS_PRICE_API_KEY) - Create GasPriceWorker with time.Ticker pattern, runtime stop/resume via channels, and persistent state across restarts - Create gas_price_handler with 5 endpoints: GET /status, POST /poll, POST /toggle, PUT /config, GET /history - Wire worker in main.go with SafeGoLoop pattern - Add migration 20 for gas_price_poll_state table Helm: - Add gasPrice section to values.yaml (enabled, pollInterval, apiKey) - Add GAS_PRICE_ENABLED/POLL_INTERVAL to configmap.yaml - Add GAS_PRICE_API_KEY to secret.yaml Frontend: - Add GasPriceStatus/GasPriceHistory interfaces and API functions - Add Gas Price Auto-Poll section to Settings page with toggle, interval selector, poll-now button, and price display Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fixed facets[duession] → facets[duoarea][]=NUS (US national average) - Use context.Background() instead of request context for poll HTTP call (request context gets cancelled when handler returns, killing the poll) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Path: /petroleum/pri/gnd/data/ (not /pri/grt/) Product: EMM_EPMR_PTE_NUS_DPG (US avg regular gasoline, weekly, $/gal) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verified live: returns US Regular Gasoline .961/gal (2026-03-23). Previous facet EMM_EPMR_PTE_NUS_DPG was the series ID, not the product facet code. Need both product and duoarea facets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Vehicle sends different signals in each batch (Soc in one, PackVoltage in next, ChargerVoltage in another). GetLatest returns only the newest record which may have just PackVoltage — losing Soc, ChargeRate, Power. GetLatestMerged looks at last 20 records and fills nil fields from older records to build a composite view. Now charger_power, charge_rate, battery_level, time_to_full all show correctly even when the latest single record is sparse. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signals arrive as individual MQTT messages, each creating a separate batch. The 10s write throttle only writes on the first batch, losing all signals from subsequent batches (climate, security, motor, tire). Added signal accumulator per vehicle: signals from all batches within the throttle window are merged into a single map. When the throttle timer fires, ALL accumulated signals are written together. Before: 37 signals → only BatteryLevel written, 5 tables empty After: 37 signals → all 37 written, all 6 tables populated Verified locally with Docker compose + mosquitto_pub test suite. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Test scripts with VIN should not be in the repo. Added to .gitignore. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added ?? 0 guards to CostComparisonCard props and all metric display values. Prevents 'Cannot read properties of undefined (toFixed)' crash. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Motor cards were hardcoded with null for all temps/currents. Now maps: - Front Motor: di_stator_temp_f, di_heatsink_t_f, di_inverter_t_f, di_motor_current_f - Rear Motor: di_stator_temp, di_heatsink_t_r, di_inverter_t_r, di_motor_current_r - Rear-Left: di_stator_temp_rel, di_heatsink_t_rel, di_inverter_t_rel, di_motor_current_rel - Rear-Right: di_stator_temp_rer, di_heatsink_t_rer, di_inverter_t_rer, di_motor_current_rer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
End date '2026-03-30' was parsed as 00:00:00, excluding sessions created later that day. Now adds 24h-1s to include the full day. Fixes Charging page showing 'No charging sessions yet' when sessions exist on the end date. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- seed_snapshots.sql: realistic data for integration testing (motor temps/currents, climate, security, charging, tire pressure) - .gitignore: exclude package.json (Playwright test dependency) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace all hardcoded unit conversions and raw metric values in 26 dashboard JSON files with calls to the PostgreSQL conversion functions from migration 18: - convert_distance() for distance/range/odometer fields - convert_speed() for speed/speed_max/vehicle_speed fields - convert_temp() for inside/outside/stator/heatsink/inverter temp fields - convert_pressure() for tire pressure fields - convert_efficiency() for Wh/km computed efficiency values Also: - Replace inline CASE WHEN unit_length conversions with function calls - Wrap computed speed (distance/time) and efficiency (Wh/km) expressions - Update SQL aliases to remove hardcoded unit labels (km/h, °C, PSI, etc.) - Neutralize Grafana unit fields (celsius, velocitykmh, pressurepsi, km) to prevent double-conversion - Update byName override matchers to match new alias names Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add seed_comprehensive.sql: a large, realistic dataset generator for TeslaSync (Model Y) covering 2020-01-01 to 2026-03-31. The script truncates existing tables, creates monthly position partitions, seeds vehicle, tokens, settings, addresses, geofences and electricity rates, and generates extensive time series data (hourly positions ~54k rows), drives, charging sessions, charging telemetry, vehicle states, daily mileage, motor/climate/security/tire/battery snapshots, alerts and rules, notification channels/preferences/logs/metrics, visited locations, trips, gas price history, software updates, API/audit logs, API keys, command logs, vampire drain events, and other auxiliary tables. Includes setval calls for sequences and comments with docker psql instructions; uses fake tokens/keys for testing. Intended for local/dev testing and data visualization.
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.
Description
Closes #
Type of Change
Checklist
Screenshots (if applicable)