Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

WeatherInfo

A Delphi FireMonkey weather widget — GPS/IP geolocation, OpenWeatherMap integration, and a clean App.Controller separation of concerns demo.

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate 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

  1. The app starts with a hardcoded default location (Berlin).
  2. It reads WeatherInfo.ini from 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.
  3. 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.
  4. Weather data is fetched right away using whichever location is currently active (default or INI). The widget displays data within seconds of launch.
  5. 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:

ini
[Location]
City=Berlin
Latitude=52.52
Longitude=13.405

[API]
Key=your_api_key_here

Weather 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 reads CurrentLocation and 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.Form is pure UI. All business logic lives in App.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 in protected 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 CurrentLocation function resolves the best available value at read time — no state machine, no explicit fallback chain.
  • Thread safety — TIPLookupThread performs a blocking HTTP call on a background thread and marshalls the result back to the UI thread via TThread.Synchronize before any controller state is touched.

Project Layout

pascal
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-workspace

Setup

1. Get an OpenWeatherMap API Key

  1. Visit openweathermap.org/api
  2. Create a free account
  3. 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:

powershell
.\Build\DelphiBuildDPROJ.ps1 -ProjectFile Source\WeatherInfo.dproj -Config Debug -Platform Win32

Output 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 TLocationSensor returns (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.