Skip to content

feat: estimate costs from user utility rates when TeslaMate prices are missing - #335

Open
raykellyjr wants to merge 8 commits into
vide:mainfrom
raykellyjr:cursor/utility-rate-cost-estimates-e380
Open

feat: estimate costs from user utility rates when TeslaMate prices are missing#335
raykellyjr wants to merge 8 commits into
vide:mainfrom
raykellyjr:cursor/utility-rate-cost-estimates-e380

Conversation

@raykellyjr

Copy link
Copy Markdown

Summary

Lets users set home (AC) and optional DC utility rates in Settings. When TeslaMate has no charge price (cost == null), MateDroid estimates cost from kWh × rate for Cost Analytics, Trips summary, and the Cost Summary widget.

Behavior

  • Recorded TeslaMate costs always win (including free 0.0)
  • Estimates only fill missing prices
  • DC uses DC rate if set, otherwise falls back to home rate
  • UI clearly labels sessions estimated from your utility rate
  • Cost/100 uses the effective total only when every charge has a numeric cost (recorded or estimated)

Why

Many TeslaMate setups never enter charge prices. Local rates unlock drive/trip/cost analysis without requiring backend cost configuration.

Test plan

  • ./gradlew :app:testDebugUnitTest
  • ./gradlew :app:lintDebug
  • Set a home rate in Settings → Costs screen shows estimates for unpriced charges
  • TeslaMate-priced charges still show as recorded
  • Clear rates → estimates disappear, partial coverage returns

Raymond Kelly added 8 commits July 18, 2026 02:03
Only show cost per 100 distance when every charge in the filtered
trips is priced. Keep known totals visible with clearer coverage
notes, including when charges exist but none are priced.
- TripIntelligenceCalculator surfaces per-trip standouts on top of
  the existing TripsSummaryCalculator: most/least efficient, cheapest
  and priciest per 100 km/mi (Complete cost-coverage only), longest,
  biggest charging-overhead share, plus ensemble energy gap and
  average charging minutes per trip.
- New IntelligenceCard on the Trips screen renders those highlights
  under the summary card; tapping a trip-backed row opens the trip.
- New BatteryHealthSnapshot Room entity + DAO records the max-range
  figure every time the Battery screen loads, debounced to at most
  once per day per car and pruned to 90 rows.
- Room migration 12 -> 13 adds the snapshots table; DatabaseModule
  provides the new DAO to Hilt consumers.
- BatteryScreen renders a max-range trend using OptimizedLineChart
  once at least two snapshots exist, with 5 X labels and a tap
  tooltip per the project chart rules.
- Full set of strings localized across en/it/es/ca/de/zh and the
  changelog entry updated.
- CostAnalyticsCalculator turns a range of ChargeSummary rows + total
  distance into an honest set of cost metrics: known cost, cost/100
  distance (Complete coverage only), avg cost/kWh, energy added, and
  missing/free session counts. Reuses TripCostCoverage semantics.
- CostAnalyticsRepository loads charges + distance from Room using the
  new ChargeSummaryDao.getInRange query, and stitches in the user's
  currency + unit-of-length from SettingsDataStore. All work happens on
  Dispatchers.IO and never touches the API.
- CostAnalyticsScreen (Material3, car palette) shows range chips
  (7/30/90/all-time), a headline card with the cost, energy and distance
  figures, and a coverage card that explains partial or missing pricing.
  Reachable from the dashboard via a new "Costs" nav button.
- CostSummaryWidget is a read-only Glance widget that mirrors the same
  numbers on the home screen with 7/30/90-day ranges, configurable per
  car. All formatting happens in the worker; the widget itself only
  renders preformatted strings and never talks to TeslaMate.
- CostSummaryWidgetUpdateWorker owns DB access + formatting; scheduled
  by the receiver on install (periodic 6h) and by DataSyncWorker after
  each successful sync so widgets refresh with the freshest cache.
- SettingsDataStore caches teslamate_units.unit_of_length under a new
  key; DashboardViewModel and SettingsViewModel update the cache when
  they fetch global settings so widgets can format distances offline.
- MainActivity honours EXTRA_SKIP_CAR_WIDGET_UPDATE so tapping the cost
  widget does not schedule an unrelated car-status refresh.
- New DAO queries for cost coverage: countWithCostInRange,
  countMissingCostInRange, countZeroCostInRange, getInRange.
- Unit tests cover the calculator's complete/partial/missing/zero-cost
  cases, the widget formatter's coverage semantics, and the widget's
  date-range helper.
Document the read-only widget stack and Room v13 battery history
cache so contributors know where cost/trip intelligence lives.
Use cached TeslaMate unit-of-length as a Cost Analytics fallback,
refresh units from global settings in the cost widget worker, and
update the cost widget after summary sync even when detail sync retries.
Cache unit-of-length during summary sync and stop live-fetching
TeslaMate units in the cost widget/worker so Room values and labels
cannot drift after a unit change.
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