Location Database — Gazetteer

See also: location-dbarchitectureschema

A named-point reference table in the same owntracks database as locations, for matching GPS fixes against known places (stations, GWML electrification neutral sections, etc). Added 2026-07-13 to replace the missing /home/john/tmp/uk_stations.tsv that location/speed-plot's plot cell used to depend on (that cell now derives stops from speed data directly instead; this table exists for other/future station-matching use).

Schema

CREATE TABLE gazetteer (
    id          BIGSERIAL PRIMARY KEY,
    name        TEXT NOT NULL,
    lat         DOUBLE PRECISION NOT NULL,
    lon         DOUBLE PRECISION NOT NULL,
    geom        GEOMETRY(Point, 4326) GENERATED ALWAYS AS
                    (ST_SetSRID(ST_MakePoint(lon, lat), 4326)) STORED,
    category    TEXT,        -- 'station', 'neutral_section', GeoNames feature class, NaPTAN StopType ...
    source      TEXT NOT NULL,
    notes       TEXT,
    admin1      TEXT,        -- wider location: region/state/constituent country (GeoNames admin1), e.g. 'Wales', 'Alabama'
    admin2      TEXT,        -- county / unitary authority (GeoNames admin2), e.g. 'Lincolnshire', 'Telford and Wrekin'
    country     TEXT,        -- country name, e.g. 'United Kingdom'
    population  BIGINT,      -- GeoNames population (NULL if unknown); rank same-named places by this
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX gazetteer_geom_idx ON gazetteer USING GIST (geom);
CREATE INDEX gazetteer_source_idx ON gazetteer (source);
CREATE INDEX gazetteer_category_idx ON gazetteer (category);
-- admin1/admin2/country/population added 2026-08-03 (nullable, in-place).

geom is a generated column (like a computed field) so loads only need to provide lat/lon — COPY/INSERT should list columns explicitly and omit geom.

Wider-location columns admin1/admin2/country/population (added 2026-08-03) disambiguate same-named places the way humans do — "Newport, Wales" vs "Newport, Telford and Wrekin, England" vs "Newport, Rhode Island, United States". Values are kept exactly as the source provides them (e.g. GeoNames' modern unitary-authority admin2 names, not historic counties). Populated for the geonames-* sources from each row's GeoNames id (in notes as gid=) via GeoNames admin1CodesASCII.txt/admin2Codes.txt/countryInfo.txt. For the GB-only sources, country is set to United Kingdom (naptan, gwml-neutral-sections, uk-railway-stations) since their scope fixes it; uk-railway-stations additionally has admin1 (England/Scotland/Wales) lifted from its own source field. admin2 and population remain geonames-only. Order by population to pick the principal place of a given name.

Source values

Distinct values of the source column — i.e. the distinct origins of data in this table. Row counts confirmed live via SELECT source, count(*) FROM gazetteer GROUP BY source on 2026-08-02; re-run that query rather than trusting these numbers if precision matters, since new loads will change them.

SourceRowsCategory valuesGood for
gwml-neutral-sections5neutral_sectionHand-curated in an earlier session from ~/tmp/gwml-neutral-sections.kml/.gpx. Only source for GWML electrification phase-break locations — used by hibernate-on-approach; nothing else provides this.
uk-railway-stations2,606stationgithub.com/davwheat/uk-railway-stations (stations.csv: name, lat, long, CRS code, IATA code, country). One row per station (clean, deduplicated), with notes holding "CRS=<code>, country=<n>". Best source for "which railway station is this" / station-to-station matching — use this over naptan's RSE/RLY/RPL rows (below) when you just need the station itself, not its individual entrances/platforms.
naptan397,89634 StopType codes — see breakdown belowDepartment for Transport National Public Transport Access Node dataset — every GB bus stop, rail/tram/metro/underground access point, ferry terminal and taxi rank, including request stops with no scheduled timetable. https://beta-naptan.dft.gov.uk/. Best source for "nearest bus/tram stop" (category='BCT', see breakdown) — far more complete for on-street stops than general-purpose places-search tools, which tend to miss untimetabled ones.
geonames-GB109,177P, T, S, A, H, L, R, V, UGeoNames.org geographical database, GB subset. category holds the GeoNames feature class (P=populated place, T=terrain/hill, S=spot/building/farm, A=administrative, H=hydrographic, L=park/area, R=road/railroad, V=vegetation, U=undersea). https://www.geonames.org/. Best for general place-name lookup (towns, hills, farms, administrative areas) — not transport-specific.
geonames-cities500069,562P (populated places)GeoNames.org global 'cities' extract (populated places with population >= 5,000), all countries. https://download.geonames.org/export/dump/cities5000.zip. Best source for well-known towns/cities worldwide (adds the global coverage the GB-only sets lack). Overlaps geonames-GB for GB places (same GeoNames id under both sources) - filter to one source, or DISTINCT ON the gid in notes, for one row per real place.
jPhone0 (reserved)Reserved for data John supplies directly (e.g. dictated from his phone). None loaded yet as of 2026-08-02. Do not duplicate entries already in the notes-store gazetteer here until the sync is actually implemented — see using-gps-data ("There are two gazetteers").

naptan StopType families (2026-08-02 snapshot)

The single naptan row above covers 27 distinct StopType codes; grouped into families (per DfT NaPTAN schema — confirmed groupings, not every individual code's exact wording) they break down as:

FamilyCodesRowsGood for
On-street bus/coach/tram stopsBCT380,022The dominant category by far. Actual kerbside stop locations — the right family for "nearest bus stop" / walking-directions-to-a-stop questions. Includes untimetabled request stops (e.g. Parkside Avenue, Winterbourne).
Rail station access pointsRSE, RLY, RPL6,677Entrances and platform-access points at railway stations — finer-grained than uk-railway-stations (multiple rows per station). Use uk-railway-stations for "which station", this family for "which entrance/platform".
Metro/tram/undergroundTMU, MET, PLT4,136Entrance and platform-access points for tram, metro and underground systems (e.g. London Underground, DLR, Tyne & Wear Metro).
Bus/coach station (off-street)BCS, BCE, BCQ, BST4,877Bays, entrances and stands within bus/coach stations (interchanges) — distinct from the on-street BCT stops above.
FerryFER, FBT, FTD1,134Ferry terminal, dock and berth access points.
Taxi rankTXR, STR902Taxi rank and shared-taxi-rank head points.
AirGAT, AIR148Airport entrance and airside access points.

Grants

Same pattern as locations: table created/owned by postgres (superuser), then GRANT INSERT, SELECT ON gazetteer TO owntracks and GRANT SELECT ON gazetteer TO owntracks_ro. Note owntracks itself has no schema-level CREATE privilege (PG15 default), so new tables need the superuser step — confirmed via has_database_privilege(current_user, 'owntracks', 'CREATE') returning false for it.

Loading data

Loaded directly from pomelo over the [postgres] stunnel tunnel (see architecture for the tunnel itself) using the write-capable owntracks role and psycopg2's copy_expert with a local CSV — no scp/ssh file transfer needed, since trust auth on the owntracks database doesn't care which host the tunnel-forwarded connection originates from, only the requested db+role.

Example query

-- Nearest gazetteer entries to a point (any source/category)
SELECT name, category, source, notes,
       ST_Distance(geom::geography, ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)::geography) AS dist_m
FROM gazetteer
ORDER BY geom <-> ST_SetSRID(ST_MakePoint(:lon, :lat), 4326)
LIMIT 5;
created 2026-07-13  ·  tags location, gazetteer, postgis  ·  updated 2026-08-03  ·  version 6