GPS Filter is a Home Assistant custom integration that listens to a source
device_tracker entity, rejects noisy GPS updates, and exposes a cleaner
filtered tracker for dashboards, automations, and real-world testing.
The integration is designed to run quietly in the background. It keeps the Home Assistant entity surface small, while config entry diagnostics and debug logs retain the detailed data needed for drive analysis.
- Config flow for selecting a source
device_tracker - Options flow for tuning thresholds after setup
- Coordinator-based runtime state
- Filtered GPS
device_tracker - Device-scoped reset buttons
- Small diagnostic sensor platform for health dashboards
- Config entry diagnostics
- Reset services
- In-memory filter timeline with the latest 50 decisions
- Unit tests and GitHub Actions validation
The current filter accepts the first valid point, then rejects updates when:
- GPS accuracy exceeds the configured maximum accuracy
- The incoming point is an exact duplicate of the last accepted point
- The calculated movement speed exceeds the configured maximum speed
- The calculated movement speed and reported source speed differ by more than the configured maximum speed difference
- The first anchor after reset/restart has worse than 10 m GPS accuracy
The integration tracks both calculated speed and reported source speed. Reported speed is converted from m/s to km/h when present.
device_tracker.filtered
The filtered tracker exposes the most recent accepted GPS position.
- Reset Filter
- Reset Stats
The reset buttons are tied to one GPS Filter device. Use these for dashboard controls when multiple filtered trackers are configured. Home Assistant derives the exact entity IDs from the configured GPS Filter device name.
sensor.gps_filter_statussensor.gps_filter_last_reasonsensor.gps_filter_last_accuracysensor.gps_filter_last_received_timestampsensor.gps_filter_last_accepted_timestampsensor.gps_filter_acceptance_ratesensor.gps_filter_seconds_since_last_acceptedsensor.gps_filter_total_received_countsensor.gps_filter_total_rejected_count
These sensors are intended for a compact health dashboard. Detailed rejection counts, maximum values, threshold snapshots, and the recent decision timeline are available in config entry diagnostics instead of separate Home Assistant entities.
Sensor entity IDs are generated by Home Assistant from the GPS Filter device name and each sensor's translated entity name. The integration does not force entity IDs in code.
For one configured tracker, the default generated names are expected to be:
sensor.gps_filter_statussensor.gps_filter_last_reasonsensor.gps_filter_last_accuracysensor.gps_filter_last_received_timestampsensor.gps_filter_last_accepted_timestampsensor.gps_filter_acceptance_ratesensor.gps_filter_seconds_since_last_acceptedsensor.gps_filter_total_received_countsensor.gps_filter_total_rejected_count
When multiple GPS Filter entries are configured, each entry uses its config
entry title as the Home Assistant device name, for example
GPS Filter - Pixel 8 or GPS Filter - Car Tracker. This keeps generated
entity IDs readable and avoids relying on _2 suffixes.
The live status, reason, timing, accuracy, and acceptance sensors do not compile
long-term statistics. The received and rejected count sensors use
TOTAL_INCREASING.
- Copy
custom_components/gps_filterinto your Home Assistantcustom_componentsdirectory. - Restart Home Assistant.
- Go to Settings -> Devices & services -> Add integration.
- Search for GPS Filter.
- Select the source
device_tracker. - Set:
- Maximum speed in km/h
- Maximum GPS accuracy in meters
- Maximum speed difference in km/h
All threshold values must be greater than zero.
After setup, thresholds can be edited from the integration options:
- Maximum speed
- Maximum GPS accuracy
- Maximum speed difference
Changing options reloads the config entry so the coordinator and filter engine use the updated values.
The integration exposes two services:
gps_filter.reset_statistics- Clears diagnostic counters while keeping the current accepted GPS point.
gps_filter.reset_filter- Clears statistics, resets filter state, clears the in-memory timeline, and makes the next accepted point a new first point.
Both services accept an optional entry_id field. If omitted, all loaded GPS
Filter entries are reset. If provided, only that config entry is reset.
For dashboard controls, prefer the GPS Filter button entities instead of calling these services directly. Button entities are tied to one GPS Filter device, so pressing one only resets that filtered tracker.
Config entry diagnostics include:
- Integration version
- Redacted configuration
- Filter statistics
- Post-drive summary statistics
- Effective filter thresholds
- Maximum speed
- Maximum GPS accuracy
- Maximum speed difference
- Startup anchor accuracy
- Gap accepted seconds
- Last received point
- Last accepted point
- Last filter result
- Filter timeline
The filter timeline is in-memory only and keeps the latest 50 processed filter decisions. Each timeline entry contains:
- timestamp
- accepted
- reason
- latitude
- longitude
- accuracy
- distance_m
- calculated_speed_kmh
- reported_speed_kmh
- seconds_since_last_accepted
The timeline is not persisted and is reset when Home Assistant restarts or when
gps_filter.reset_filter is called.
The diagnostics summary includes:
- total_received_count
- total_rejected_count
- accepted_count
- duplicate_count
- accuracy_rejections
- startup_accuracy_rejections
- speed_rejections
- speed_consistency_rejections
- gap_accepted_count
- acceptance_rate_percent
- max_distance_m
- max_calculated_speed_kmh
- max_reported_speed_kmh
- max_accuracy_m
- max_rejected_distance_m
- max_rejected_calculated_speed_kmh
- max_rejected_reported_speed_kmh
- max_rejected_accuracy_m
- max_gap_distance_m
- max_gap_seconds_since_last_accepted
Summary statistics are in-memory only. They reset when
gps_filter.reset_statistics or gps_filter.reset_filter is called.
Routine GPS update diagnostics are logged at DEBUG level. This keeps normal
logs quieter during longer drives while preserving detailed per-point data when
debug logging is enabled.
Lifecycle events such as setup, unload, options reload, and reset services are
logged at INFO level.
Example logger configuration:
logger:
default: info
logs:
custom_components.gps_filter: debug- Confirm the source tracker is updating in Home Assistant.
- Open a compact dashboard with the raw and filtered tracker, status, reason, acceptance rate, accuracy, received count, rejected count, and reset buttons.
- Call
gps_filter.reset_filterbefore starting a test drive. - Drive normally.
- Review:
- Current filtered tracker position
- Status and last reason sensors
- Accuracy and acceptance rate
- Received and rejected counts
- If the map or counts look wrong, export config entry diagnostics or paste DEBUG logs for analysis. The diagnostics include the detailed counters, maximum values, thresholds, and latest decision timeline.
Use diagnostics and logs to tune existing thresholds before changing the filter algorithm.
Install dependencies in your local environment, then run:
.\.venv\Scripts\python.exe -m ruff check .
.\.venv\Scripts\python.exe -m pytestThe test suite covers the filter engine, coordinator behavior, config flow, options flow, diagnostics, sensors, and services.
GPS Filter is under active real-world testing. The immediate goal is a reliable debugging and tuning workflow before adding any new filtering algorithms.