How the TeslaMate Geocoder Module Performs Automatic Address Lookup
The TeslaMate Geocoder module performs automatic address lookup by wrapping the Nominatim OpenStreetMap API, using Tesla with Finch to fetch detailed location data from latitude and longitude coordinates.
The TeslaMate.Locations.Geocoder module in the teslamate-org/teslamate repository provides the core functionality for converting raw GPS coordinates into structured address information. By leveraging the open-source Nominatim service, this Elixir module enables TeslaMate to automatically resolve vehicle locations without relying on proprietary mapping APIs.
HTTP Client Configuration with Tesla and Finch
The Geocoder establishes its HTTP connection in lib/teslamate/locations/geocoder.ex by configuring a Tesla client with the Finch adapter. The base URL is hardcoded to https://nominatim.openstreetmap.org, ensuring all requests route to the public Nominatim instance. A custom User-Agent header containing the current TeslaMate version is injected into every request to comply with Nominatim's usage policy. JSON middleware and a logger middleware complete the stack, handling serialization and observability respectively.
Reverse Geocoding with reverse_lookup/3
The primary entry point for coordinate resolution is reverse_lookup/3, which accepts lat, lon, and an optional language parameter defaulting to "en". This function constructs a query string requesting the JSON v2 format with detailed address components, extra tags, namedetails, and a high zoom level of 19 for maximum precision. These parameters ensure Nominatim returns granular address data suitable for vehicle location tracking.
Executing Queries and Handling HTTP Responses
A private query/3 helper manages the actual HTTP GET request execution. It attaches an Accept-Language header to the request and dispatches it via Tesla's get/3 function. Successful HTTP 200 responses return {:ok, body}, while any network or server errors normalize to {:error, reason} tuples. This consistent error handling allows upstream callers to reliably pattern match on results.
Parsing Nominatim JSON into Address Structs
Raw API responses undergo transformation via into_address/1, which converts Nominatim's JSON maps into TeslaMate's internal Address struct format. When Nominatim returns {"error":"Unable to geocode"}, the function generates a placeholder "unknown" address rather than crashing. For other errors, it returns {:error, {:geocoding_failed, reason}}. Successful responses extract fields like display_name, osm_id, osm_type, house number, road, neighbourhood, city, county, postcode, state, and country using alias lists to accommodate varying OpenStreetMap tag conventions.
Batch Address Refresh with details/2
To minimize API round-trips when updating stored locations, the module exposes details/2. This function accepts a list of existing Address structs, extracts their OSM identifiers (osm_id and osm_type), and constructs a comma-separated osm_ids parameter. A single request to the /lookup endpoint fetches current details for all entities simultaneously, significantly improving efficiency when refreshing historical location data.
Request Logging and Middleware Configuration
The logger middleware implements log_level/1 to maintain clean log output. Successful responses log at :info level, while any response with an HTTP status code greater than or equal to 400 triggers a warning. This differentiation helps operators identify problematic API calls without cluttering logs with routine successful geocoding operations.
Practical Code Examples
# Simple reverse lookup (latitude, longitude)
{:ok, address} = TeslaMate.Locations.Geocoder.reverse_lookup(52.5200, 13.4050)
# → %{
# display_name: "Berlin, Germany",
# city: "Berlin",
# country: "Germany",
# latitude: "52.5200",
# longitude: "13.4050",
# …}
# Batch refresh of address details for a list of stored addresses
addresses = [
%TeslaMate.Locations.Address{osm_id: 12345, osm_type: "way"},
%TeslaMate.Locations.Address{osm_id: 67890, osm_type: "node"}
]
{:ok, updated_addresses} = TeslaMate.Locations.Geocoder.details(addresses, "de")
Summary
- The
TeslaMate.Locations.Geocodermodule wraps the Nominatim OpenStreetMap API to convert GPS coordinates into readable addresses. - It uses Tesla with the Finch adapter and configures a custom User-Agent header for API compliance.
reverse_lookup/3handles single coordinate resolution with detailed address component extraction.into_address/1parses JSON responses, handling both successful lookups and "Unable to geocode" errors gracefully.details/2enables efficient batch updates by querying multiple OSM IDs in a single request.- Comprehensive logging middleware differentiates between routine operations and warnings for failed requests.
Frequently Asked Questions
What geocoding service does the TeslaMate Geocoder use?
The module utilizes the Nominatim service from OpenStreetMap, specifically targeting https://nominatim.openstreetmap.org. This open-source solution provides free reverse-geocoding capabilities without requiring proprietary API keys.
How does the Geocoder handle coordinates that cannot be resolved?
When Nominatim returns {"error":"Unable to geocode"}, the into_address/1 function generates a placeholder "unknown" address structure. For other network or parsing failures, it returns {:error, {:geocoding_failed, reason}}, allowing the application to handle missing data gracefully.
What is the purpose of the details/2 function in the Geocoder module?
The details/2 function performs batch lookups for existing addresses by querying the /lookup endpoint with a comma-separated list of OSM identifiers. This reduces API traffic when refreshing metadata for multiple stored locations simultaneously.
Which HTTP client adapter does the Geocoder module employ?
The module configures Tesla to use Tesla.Adapter.Finch as its HTTP client adapter. This provides efficient HTTP/2 support and connection pooling for requests to the Nominatim servers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →