v1.2.0 — Real data
port-tidewatch v1.2.0
Release date: 2026-06-15
Real data (M7). v1.1 made the pipeline demonstrable with a scripted surge; v1.2
feeds it from the live PEGELONLINE Elbe gauges alongside that simulator,
behind a source-selection switch — without touching the Reading contract or
the consumer path.
Highlights
- Live PEGELONLINE Elbe feed — a source adapter polls the public WSV REST-API
for four Hamburg gauges (St. Pauli, Bunthaus, Over, Zollenspieker) and emits the
sameReadingrecords the simulator does. Centimetres-above-gauge-zero are
converted to metres NHN in an explicit mapping layer (W/100 + PNP offset);
conditional GET (If-None-Match) means a304emits no duplicate reading, and
transient API failures are logged and retried without crashing the host. - Source-selection switch — a single
ReadingSourceconfig value
(Simulator | Pegelonline) chooses the active source at startup, so the same
build serves the scripted demo or the real feed without recompiling. A bad or
empty value fails fast at startup, consistent with the threshold-options
validation. - Producer renamed to
Tidewatch.Source— the simulator project became a
Generic Host that hosts interchangeable reading sources behindIReadingSource;
the simulator is now one source among others, so the name and the deployed
workload (reading-source) are source-neutral.
What's seen on the dashboard
Live dashboard on real WSV/PEGELONLINE data — the public Hamburg Elbe gauges (St. Pauli, Zollenspieker, Over, Bunthaus), all normal.
The scripted-surge demo (video and screenshots) from
v1.1
still tells the alerting story best — real Elbe levels normally sit well below the
4.50 m NHN warning boundary, so the live feed reads calm normal. The live feed's
value is the real-data integration: cm → PNP → NHN mapping and conditional polling
against the public WSV API.
What's changed
Reading-source host (was Tidewatch.Simulator)
- Moved to a Generic Host (
Microsoft.NET.Sdk.Worker): DI, Options, graceful
shutdown. The publish path is theIReadingPublisherseam; sources depend on
intent, not transport. SimulatorSourceholds the scripted surge (behaviour unchanged — sameReading,
exchange, routing key;SURGE_PEAK_M/SURGE_PERIOD_S/RABBITMQ_HOSTstill
honoured).PegelonlineSource+PegelonlineClient+PegelMapper: latest value, window
backfill on start, livegaugeZerolookup, and the cm → m / PNP → NHN mapping.
Stations are configured by UUID. HPA tidal gauges expose nogaugeZero, so their
PNP is set explicitly (Hamburg PNP = NHN −5.00 m); the live lookup remains for
other WSV stations.ReadingSourceOptions+ validator select the active source at startup
(ValidateOnStart); only the chosen source and its dependencies are registered.
Deploy
- The deployed producer runs the live feed:
ReadingSource=Pegelonlineis set via
env var on the k8sreading-sourceDeployment and the Container Apps app; the
local appsettings default staysSimulatorfor the documented demo. - The producer workload was renamed
simulator→reading-sourceacross the k8s
manifests, kustomization,azure.yaml, and the bicep (resource, name,
azd-service-name), plus the runbook.
Tests
PegelMappercm → m / PNP → NHN pinned end to end against a known St. Pauli
value;ReadingSourcevalidator (known / missing / unknown / numeric).
Known limitations (by design)
- Live feed reads calm — real Elbe levels stay below the storm-surge
thresholds, so the live source showsnormal; the simulator remains the
dramatic demo. The two are not run side by side (single source per run). - Dashboard remains read-only and polling-based.
- No notification delivery — alert events are published but acting on them is
still out of scope.
What's next (v1.3)
Observability made visible — see M8 in
docs/ISSUES.md:
surface the existing OpenTelemetry path in the dashboard (a pipeline latency pulse,
a Jaeger deep-link, and an optional self-rendered trace waterfall).
