TeplotaReky
Current water temperature of Czech rivers from CHMI data, with history charts, search and favourites.
TeplotaReky - river water temperature
![]()
Current water temperature of about 250 Czech river gauges, with the history behind it: search by river or station, filter by region, sort by warmest or coldest, keep favourites, and open a chart for the last 24 hours, 7 days, 30 days or a year. Works on a phone, follows the system light/dark setting.
Data source: Český hydrometeorologický ústav (ČHMÚ / CHMI), open data at https://opendata.chmi.cz/hydrology/now/ and the public HPPS pages https://hydro.chmi.cz/hpps/. The values are shown as CHMI published them, without warranty, and are not meant for safety decisions.
The map at /mapa also draws the rivers (a switchable layer; tap one to see its whole course and stations). The lines are a
simplified extract of DIBAVOD A02 (VÚV T. G. Masaryka, https://www.dibavod.cz), built offline by
tools/TeplotaReky.Rivers into wwwroot/data/rivers.geo.json (ADR 0006).
Since 1.14.0 stations below the ČHMÚ drought limit show a Sucho badge; level and discharge charts draw the published drought limits (ADR 0009).
Since 1.13.0 a visitor can opt in, per station, to a notification when the flood stage rises (Web Push, no accounts; ADR 0008).
Since 1.12.0 the station page also charts the water level and discharge with the flood-stage (SPA 1-3) lines CHMI publishes
for a station (ADR 0007).
The interface is in Czech.
How it works
A background service fetches the CHMI data every 30 minutes (politely: throttled, identified, conditional requests), stores the readings in SQLite, and the Blazor Server UI reads from that database. Details, data flow and decisions: docs/ARCHITECTURE.md.
Run it
Requires the .NET 10 SDK.
dotnet run --project src/TeplotaReky.Web
The first start downloads the station list and about 250 station files (a few minutes; the site shows data as they
arrive) and backfills the last 7 days. Data, keys and logs go to data/ (git-ignored).
dotnet test
Configuration
Any setting can be given as an environment variable with __ as the separator (Scrape__Enabled=false).
| Key | Default | Meaning |
|---|---|---|
DataDir |
data |
Folder with the SQLite file, data-protection keys and logs. A volume in production. |
Logging:Directory |
{DataDir}/logs |
Where the daily log files go. |
Serilog:MinimumLevel:* |
Information | Levels and per-namespace overrides. |
Scrape:Enabled |
true |
Turns the background scraper off. |
Scrape:ReadingsInterval |
00:30:00 |
How often the live readings are fetched. |
Scrape:InitialBackfillDays |
7 |
Days of history fetched on the first run (about 250 requests per day). |
Scrape:BackfillDays |
2 |
Days re-fetched by the daily backfill after UTC midnight. |
Chmi:MinRequestInterval |
00:00:00.400 |
Minimum pause between any two requests to CHMI. |
Admin:User / Admin:Password |
admin / none |
Administrator of the Logs page. Without a password the sign-in is disabled. |
Analytics:MeasurementId |
empty | GA4 id; empty means no banner and no tag. Set by the pipeline. |
Push:VapidPublicKey / Push:VapidPrivateKey |
empty | VAPID key pair for the opt-in flood-stage notifications (Web Push). Without both the feature is hidden. Generate with tools/New-VapidKeys.ps1; the private key is a pipeline secret (ADR 0008). |
Endpoints
GET /health-{ "status": "Healthy", "version": "1.0.0", "name": "teplotareky", "entries": { ... } }(Degradedwhen no readings cycle succeeded for about 1.5 hours).GET /api/stations- public JSON list of all stations with a thermometer;GET /api/stations/{slug}- one station (404 when unknown). Anonymous,Cache-Control: public, max-age=300. Fields (camelCase):slug,name,river,region,latitude,longitude,temperature(deg C),measuredUtc(ISO-8601 UTC),levelCm,flowM3s,url. The data are CHMI open data; anyone reusing the API must credit Český hydrometeorologický ústav (ČHMÚ)./logs,GET /api/logs/{file}- administrator only.
Android widget
A home-screen widget with the current water temperature of chosen stations (2x1 and 4x2, several widgets, each with its
own station; light/dark follows the system; goes grey with a note when the data are stale or the phone is offline).
It reads the public API above. The app is src/TeplotaReky.Android (package cz.tomlabs.teplotareky, release notes in
android/CHANGELOG.md); the logic lives in src/TeplotaReky.Widget.Core and is tested on the
host (dotnet test). The Android project is not in the solution: the host has no Android workload on purpose, the APK
is built in Docker.
docker build -t teplotareky-android docker/android # once (~5 GB, shared layers with lepsitv-android)
docker run --rm -v "${PWD}:/src" teplotareky-android # -> artifacts/android/TeplotaReky-<version>-android-arm64.apk
docker run --rm -e ARCH=x64 -v "${PWD}:/src" teplotareky-android # emulator build (android-x64)
docker rmi teplotareky-android # when the toolchain is no longer wanted
The APK is debug-signed (set ANDROID_KEYSTORE, ANDROID_KEY_ALIAS, ANDROID_KEY_PASS, ANDROID_STORE_PASS for a
release key). Sideload it: adb install -r artifacts/android/TeplotaReky-1.0.0-android-arm64.apk, or copy the file to
the phone and open it from a file manager (allow "install unknown apps" for that file manager). Then long-press the home
screen, Widgets, "Teplota řeky", and pick a station.
Deployment
Docker on the TomLabs VPS behind nginx; see Dockerfile, deploy/ and azure-pipelines.yml. The catalogue entry
in the TomLabs app store is described by appstore.json.
Release notes: CHANGELOG.md.
Changelog
Changelog
1.14.0 — 2026-10-20
- Added: drought indicators from ČHMÚ station limits. Stations below the limit show a Sucho badge on the list and detail, with a matching legend entry.
- Added: level and discharge charts draw a brown/amber dashed drought limit, including stations without flood stages.
- Fixed: the first scrape cycle refreshes metadata when no station has drought limits yet; daily sync keeps them current.
1.13.0 — 2026-10-20
- Added: optional flood-stage notifications. On a station that has stage limits you can switch on an upozornění for this device from a chosen stage (SPA 1, 2 or 3). You get one notification when the stage rises to it, and another if it falls and rises again. Off with one tap. No account is needed; the privacy page says what is stored.
- Added: every notification names ČHMÚ as the source, says that the values are informative and unverified, and links to the official ČHMÚ page of the station.
- Note: the notifications appear only where the operator has set them up, and on iPhone only once the app is added to the Home Screen.
- Changed: the privacy page describes the notification data.
1.12.1 — 2026-10-20
- Fixed: flood activity stages (SPA) were never shown, because the station sync did not store the limits published by ČHMÚ. The first scrape cycle after the upgrade now refreshes the station list right away, so the stages appear within minutes of the deploy.
1.12.0 — 2026-10-20
- Added: the station page now shows the water level and discharge. A switch above the chart toggles Teplota / Hladina / Průtok
(address
?velicina=hladinaor?velicina=prutok). - Added: where ČHMÚ publishes them, the level and discharge charts draw the flood activity stages SPA 1 (bdělost), 2 (pohotovost) and 3 (ohrožení) as coloured dashed lines with labels, and list all limits below the chart together with how far the water is from the next one. The lines appear when the water gets near them.
- Added: a station in a flood stage shows a badge with the stage on its page and in the station list.
- Added: the public API has an extra
floodStagefield (0-3, or null when unknown). - Changed: the chart scale for level and discharge starts at zero.
1.11.0 — 2026-10-20
- Added: the map now draws the rivers. A "Řeky" switch above the map turns the lines on or off (on by default, remembered).
- Added: tap a river to highlight its whole course and see the list of stations on it, each a link to its page; tap the map or the close button to clear it. A station's popup has a "Zobrazit celý tok" button too.
- Added: river lines come from DIBAVOD (VÚV T. G. Masaryka); credited on the map and on the About page. The lines are simplified and only show rivers that have a station.
1.10.0 — 2026-10-20
- Fixed: on a phone with a dark theme the page looked faded for the first few seconds (dark text on a dark background) until it finished loading; it now has the right colours from the first moment.
- Fixed: the page no longer flickers when it finishes loading.
- Changed: "Stanice na webu ČHMÚ", "Zobrazit na mapě", "Soukromí", "Cookies" and the map attribution links are now at least 40 px high, easy to tap.
- Changed: the cookie banner is a compact bottom sheet on a phone (under a fifth of the screen) with "Odmítnout" and "Přijmout" side by side and of the same size; the page leaves room for it so the footer stays reachable.
- Fixed: no black frame around the page heading after opening a page.
1.9.0 — 2026-10-20
- Added: "Mapa" shows every station on a map (OpenStreetMap), each marker coloured by the current water temperature. Tapping a marker shows the river, temperature, time of the measurement and a link to the station. The "Zobrazit na mapě" link on a station page now opens this map at that station.
- Added: "Stanice v okolí" on the map and on the station list finds the stations nearest to you and shows the distance. Your position is asked for only when you tap the button, is used just for sorting and is never stored or logged.
- Changed: the privacy page explains that map tiles come from OpenStreetMap servers and how the position is used.
1.8.0 — 2026-10-20
- Added: "Letos vs. průměr" inside "Porovnání": this year's daily water temperature against the daily average of all
earlier years of the station, with a shaded band from the lowest to the highest earlier value of each day and a
sentence such as "Letos je o 1,2 °C tepleji než průměr let 2022–2025." (over the days present in both). The average
only uses the years that have a measurement on that day. A switch above the chart toggles it with "Roky přes sebe";
the view has its own address (
/station?porovnani=2) and appears only when the station has this year and at least one earlier year with data.
1.7.0 — 2026-10-19
- Added: "Porovnání" on a station page draws every stored year of the station over each other (January to December on
one axis, one line per year). The current year is highlighted, older years are muted, and each year can be shown or
hidden with the buttons under the chart. The view has its own address (
/station?porovnani=1) that can be shared. Days without measurements stay empty in each line; implausible sensor values are left out as everywhere else.
1.6.0 — 2026-10-19
- Added: TeplotaReky can be pinned to a phone home screen as an app (web app manifest, icon and theme colour).
- Changed:
/api/stationsand/api/stations/{slug}send anETagand answer304 Not Modifiedto a matchingIf-None-Match; the JSON responses are compressed (gzip/Brotli; pages stay uncompressed). The JSON fields are unchanged. - Changed: an automated check opens the main pages at 375 px and fails if any of them scrolls sideways.
1.5.0 — 2026-10-19
- Fixed: implausible sensor values no longer appear anywhere. Water temperature outside -1 to 40 °C, negative level or flow, and placeholder numbers such as -999 are left out of the current values, the charts and the minimum, maximum and average, so for example the -8.9 °C winter minimum of Velvary 2022 is gone.
- Changed: such values are also skipped when measurements are collected (and logged as a warning), and values already stored are only hidden, not deleted.
1.4.0 — 2026-10-19
- Added: the whole stored history can now be browsed year by year. On a station page, "Po letech" shows one
calendar year with previous/next buttons and a year picker; the year is in the address (
/velvary?rok=2023), so it can be shared. History reaches back to October 2021. - Added: days without a measurement stay empty and break the line instead of being bridged, and the page says how many days of the year have a measurement. Daily means follow Prague days, and the year view leaves out "Změna" (first to last reading means little across a whole year).
- Fixed: the note under the chart no longer claims that history is only stored since the app started; it states when this station's measurements begin.
- Changed: the About page describes the history correctly.
1.3.0 — 2026-10-01
- Added: a public JSON API,
GET /api/stations(every station with a thermometer) andGET /api/stations/{slug}(one station), cached for 5 minutes. It feeds the new Android home-screen widget; the data are CHMI open data.
1.2.0 — 2026-09-30
- Changed: pages are now rendered on the server before the browser takes over, so a station page opens with its content straight away and search engines and link previews see it (title, description, address).
- Added: every station page has its own title, description, canonical address and social preview tags.
- Added:
sitemap.xmllisting the home page and all stations, androbots.txtpointing to it and keeping the administrator pages out of search results.
1.1.0 — 2026-09-30
- Added: every station has a short address of its own, for example
teplotareky.cz/stenovice. Stations that share a name are told apart by their river (/teplice-becva,/teplice-ohre). An address is assigned once and never changes. - Changed: the old address
/station/<id>redirects to the short one, so links shared earlier keep working. - Changed: an address that belongs to no station answers with a real 404.
- Fixed: the page no longer hangs on "loading" after a deploy; the Blazor script is now part of the published static assets.
1.0.0 — 2026-09-29
Complete rewrite of the application (the earlier Blazor/PostgreSQL version and the Static Web App prototype are retired; they remain in git history).
- Added: current water temperature for about 250 Czech river gauges, read from the official CHMI open data (10-minute values, also water level and discharge where measured).
- Added: a background scraper that stores the readings in a database, so every station has a temperature history. History accumulates from the day the app starts.
- Added: station detail with a temperature chart for 24 hours, 7 days, 30 days and a year, plus minimum, maximum, average and change over the period.
- Added: search by river or station name (diacritics are ignored), filter by region, and sorting by river, warmest, coldest and latest measurement.
- Added: favourite stations, kept in the browser only.
- Added: System / Light / Dark theme switch; System follows the operating system live.
- Added: layout that works on a phone.
- Added:
GET /healthwith status, version and name, and the scraper's state. - Added: application log with daily rolling files and a Logs page for the administrator (live events, file list, tail view, download).
- Added: the CHMI is credited as the data source on every page.
- Changed: the interface is Czech only.
- Removed: the OpenWeather integration and the committed API key. The key was published in git history and must be treated as compromised.