Catalog · How the catalog works
WeatherInfo
A Delphi FireMonkey weather widget — GPS/IP geolocation, OpenWeatherMap integration, and a clean App.Controller separation of concerns demo.
- ★ 5 on GitHub
Anyone may press Interesting, signed in or not. It helps others find this project.
README
WeatherInfo
A FireMonkey weather widget that displays current weather data for the user's location. Supports Windows, macOS, iOS, and Android.
This project is a demo application built as part of a Delphi course. It covers real-world topics — HTTP clients, GPS and IP-based geolocation, background threads, INI persistence, and separation of concerns — while producing a fully functional, good-looking widget.
How It Works
Startup Sequence
- The app starts with a hardcoded default location (Berlin).
- It reads
WeatherInfo.inifrom the user's Documents folder. If the file exists, the stored location and API key are loaded. The stored location overwrites the default; the API key is used for all API calls. - If no API key is available (first run or missing from INI), an input dialog prompts the user to enter their OpenWeatherMap API key. The key is persisted immediately.
- Weather data is fetched right away using whichever location is currently active (default or INI). The widget displays data within seconds of launch.
- GPS and IP geolocation services start in parallel in the background. When either resolves, the location is upgraded and a new weather fetch is triggered automatically.
Location Priority
The app maintains four location layers. CurrentLocation always returns the highest-priority layer that has valid data:
| Priority | Source | When it becomes active |
|---|---|---|
| 1 (lowest) | Default | Immediately on startup (Berlin, hardcoded) |
| 2 | INI | On startup, if WeatherInfo.ini contains a previous location |
| 3 | IP Geolocation | When the background IP lookup completes (ip-api.com) |
| 4 (highest) | GPS | When the platform GPS sensor delivers a fix |
Whenever a higher-priority location becomes available, the INI file is updated and a fresh weather fetch is triggered. The 60-second update timer always reads from CurrentLocation, so the displayed weather automatically reflects the best available location — no explicit state machine required.
INI File Format
~/Documents/WeatherInfo.ini — standard INI format, read and written by Delphi's TIniFile:
[Location]
City=Berlin
Latitude=52.52
Longitude=13.405
[API]
Key=your_api_key_hereWeather Icons
Two icon modes are supported:
- API Icons (default): Fetched from OpenWeatherMap (
img/wn/). Includes day/night variants and covers all weather states. Falls back to custom icons if the download fails. - Custom SVG Icons: Vector paths rendered directly in a
TCircle+TPath. Fully offline, with glow effects for sun, thunderstorm, and snow.
The widget switches to custom icons automatically when API icon loading fails (e.g., no network).
Update Cycle
- Clock timer (1 s): Updates the date/time label.
- Update timer (60 s): Calls
FetchCurrentWeather, which readsCurrentLocationand fetches new weather data from the API.
Architecture
| Unit | Responsibility |
|---|---|
Main.Form |
Pure UI — renders weather data and icons, delegates all logic to the controller |
App.Controller |
Location orchestration, INI persistence, API key management, weather fetch |
Weather.Client |
HTTP client for OpenWeatherMap One Call API 3.0 |
Weather.Model |
TWeatherData transfer object and TWeatherCondition enum |
Location.Service |
GPS via TLocationSensor (platform sensor framework) |
Location.Geocoding |
Reverse geocoding (coordinates → city name) via OpenWeatherMap Geo API |
Location.IPGeolocation |
IP-based geolocation fallback via ip-api.com |
Design Patterns in Play
- Separation of Concerns —
Main.Formis pure UI. All business logic lives inApp.Controller, which communicates back via typed events (OnWeatherDataReceived,OnWeatherError,OnStatusUpdate). - Do/On event dispatch — Controller exposes public
On…properties for event assignment; the actual dispatch logic lives inprotected virtual Do…methods, following the standard Delphi convention and leaving the door open for subclassing. - Priority-based resolution — Four location layers are written independently by different sources. A single
CurrentLocationfunction resolves the best available value at read time — no state machine, no explicit fallback chain. - Thread safety —
TIPLookupThreadperforms a blocking HTTP call on a background thread and marshalls the result back to the UI thread viaTThread.Synchronizebefore any controller state is touched.
Project Layout
WeatherInfo/
????????? Build/
??? ????????? DelphiBuildDPROJ.ps1 # MSBuild wrapper (from omonien/DelphiStandards)
????????? Source/
??? ????????? App.Controller.pas # Business logic, location layers, INI, weather fetch
??? ????????? Location.Geocoding.pas # Reverse geocoding (coords ??? city name)
??? ????????? Location.IPGeolocation.pas # IP-based geolocation via ip-api.com
??? ????????? Location.Service.pas # GPS via TLocationSensor
??? ????????? Main.Form.fmx # FireMonkey form layout
??? ????????? Main.Form.pas # Pure UI layer
??? ????????? Weather.Client.pas # HTTP client for OpenWeatherMap
??? ????????? Weather.Model.pas # TWeatherData / TWeatherCondition
??? ????????? WeatherInfo.dpr # Program entry point
??? ????????? WeatherInfo.dproj # IDE / MSBuild project file
??? ????????? WeatherInfo.rc # Windows resource (version info, manifest)
????????? bin/ # Build output ??? gitignored
??? ????????? <Platform>/<Config>/
????????? .gitignore # Curated Delphi gitignore (from omonien/DelphiStandards)
????????? README.md
????????? WeatherInfo.code-workspaceSetup
1. Get an OpenWeatherMap API Key
- Visit openweathermap.org/api
- Create a free account
- Generate an API key (free tier: up to 60 requests/minute)
Note: Newly created API keys can take up to 2 hours to activate. If you receive HTTP 401 errors immediately after key creation, wait and retry.
2. First Run
On first launch (no WeatherInfo.ini exists), the app shows an input dialog asking for your API key. Enter it and press OK. The key is saved to the INI file and reused on subsequent runs — no code changes needed.
3. Build
Open Source\WeatherInfo.dproj in Delphi and run. Alternatively, use the included build script:
.\Build\DelphiBuildDPROJ.ps1 -ProjectFile Source\WeatherInfo.dproj -Config Debug -Platform Win32Output binaries go to bin\<platform>\<config>\ and DCU files to bin\<platform>\<config>\dcu\.
API Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| HTTP 401 | Key not yet active | Wait up to 2 hours after key creation |
| HTTP 401 | Wrong key | Delete WeatherInfo.ini from Documents; the app will prompt for a new key on next start |
| HTTP 429 | Rate limit exceeded | Free tier allows 60 req/min; the 60 s update interval stays within this limit |
| Network error | No internet | The widget shows the last successfully fetched data until the next successful update |
Platform Notes
- GPS on Windows: The
TLocationSensorreturns (0, 0) in most desktop environments (no GPS hardware). The app detects this, stops the sensor, and falls back to IP geolocation. - GPS on Android/iOS: Requires location permissions. The app requests them via the platform sensor framework. If denied, IP geolocation is used instead.
- ip-api.com: The free tier only supports HTTP (not HTTPS). This is a known limitation of that service.
Requirements
- Delphi 10.3 or later (tested on Delphi 13)
- Internet connection for weather data and initial location detection
- OpenWeatherMap API key (free tier is sufficient) — uses the One Call API 3.0
License
MIT — see LICENSE for details.

