Changelog
All notable changes to OpenHamClock will be documented in this file.
📅 Schedule Change: Starting with v15.5.10, OpenHamClock moves to a weekly release cycle. Updates will ship on Tuesday nights (EST) — one release per week for better testing and stability.
[15.6.5] - 2026-03-09
Security
- CORS lockdown: Replaced wildcard
origin: truewith explicit origin allowlist (localhost, openhamclock.com/app). Prevents malicious websites from accessing the API via the user's browser. Custom origins configurable viaCORS_ORIGINSenv var. - SSRF elimination: Custom DX cluster hosts are now DNS-resolved to IPv4, validated against private/reserved ranges, and the connection uses the validated IP (not hostname) to prevent DNS rebinding. IPv6 fallback removed to eliminate representation bypass attacks.
- Rotator & QRZ auth:
/api/rotator/turn,/api/rotator/stop,/api/qrz/configure,/api/qrz/removenow requireAPI_WRITE_KEYauthentication. - Trust proxy auto-detect:
trust proxyenabled only on Railway (auto-detected), disabled on Pi/local installs to prevent rate-limit bypass via spoofedX-Forwarded-Forheaders. Override withTRUST_PROXYenv var. - SSE connection limiter: Per-IP cap on concurrent SSE streams (default 10, configurable via
MAX_SSE_PER_IP) to prevent resource exhaustion. - Telnet command injection: Control characters stripped from DX cluster login callsigns.
- DOM XSS fixes:
sanitizeColor()for N3FJP logged QSO line colors;esc()helper for APRS Newsfeed userscript. - ReDoS fix: Replaced
/\d+$/regex withsubstring()for IP anonymization. - URL encoding:
encodeURIComponent()applied to callsign parameters in localhost fetch calls. - RBN callsign validation: Input sanitized and length-checked on
/api/rbn/location/:callsign. - Health endpoint: Session details (partial IPs, user agents) gated behind
API_WRITE_KEYauth. - Dockerfile: Application now runs as non-root user (
nodejs, UID 1001). - Startup warning: Server prints visible warning when
API_WRITE_KEYis not set. - Rig-bridge CORS: Restricted to explicit origin allowlist (was wildcard
*). - Rig-bridge localhost binding: HTTP server binds to
127.0.0.1by default (was0.0.0.0). - Rig-bridge serial port validation: Paths validated against OS-specific patterns (COM*, /dev/tty*, /dev/cu.*).
- Rig-bridge relay SSRF: Relay URL validated to reject private/reserved addresses.
Added
- LMSAL solar image fallback: Three-source failover for solar imagery: SDO direct → LMSAL Sun Today (Lockheed Martin) → Helioviewer API. Independent of NASA Goddard infrastructure.
- Lightning unit preferences: Proximity panel distances respect km/miles setting from allUnits.
- DXCC entity selector: Browse/search DXCC entities to set DX target in Modern and Dockable layouts.
- DX News text scale: Adjustable font size (0.7x–2.0x) with A-/A+ buttons. Persists in localStorage.
- Layout lock border panel: Lock/unlock toggle in dedicated FlexLayout border tab (Dockable layout).
- Rig-bridge multicast: WSJT-X relay supports UDP multicast for multi-app packet sharing.
- Rig-bridge simulated radio: Mock plugin for testing without hardware (
radio.type = "mock"). - DX cluster TCP keepalive: Persistent telnet sessions use OS-level keepalive and auto-reconnect after 5 min silence.
- DX cluster SSID: Callsign SSID (-56) appended automatically when not provided.
Fixed
- Rotator enabled by default:
.env.examplehadROTATOR_PROVIDER=pstrotator_udpuncommented, causing fresh installs to send UDP to a hardcoded IP. All rotator lines now commented out. - Pi setup (armhf): NodeSource dropped 32-bit ARM support for Node 20+. Setup script now downloads armv7l binaries directly from nodejs.org with retry support.
- Pi setup (electron):
npm install --ignore-scriptsprevents electron-winstaller postinstall failures on ARM.ELECTRON_SKIP_BINARY_DOWNLOAD=1skips useless Electron download.npm prune --omit=devfrees ~500MB after build.
[15.5.10] - 2026-02-20
Fixed
- Log flooding — 115K dropped messages in 30 minutes: Six hot-path loggers (RBN spot responses, callsign mismatch warnings, WSPR heatmap, PSK-MQTT SSE connect/disconnect) were writing directly to
console.logon every request instead of going through the log level system. All moved behindlogDebug/logInfo/logErrorOnce. Added global token-bucket rate limiter (burst 20, refill 10/sec) as a safety net — excess logs silently dropped with 60-second summary. - Moon Image retry storm: When NASA Dial-A-Moon API was down, every client request triggered a fresh fetch attempt. Added 5-minute negative cache — stale Moon images served during outages instead of returning errors.
- RBN callsign lookup storm: When QRZ/HamQTH was down, every uncached skimmer callsign triggered a failed lookup on every spot cycle. Failed lookups now cached for 10 minutes with automatic expiry.
- Header vertical centering: Text in header bar (callsign, clocks, solar stats, buttons) was misaligned after layout changes. Fixed with
alignItems: 'center'on stats and buttons rows,lineHeight: 1on large text spans,boxSizing: border-box, andautogrid row height. - TLE data failures: CelesTrak rate-limited/banned the cloud server IP from excessive TLE polling. See "TLE Multi-Source Failover" below.
Added
- TLE multi-source failover: Satellite TLE data now automatically fails over across three sources: CelesTrak → CelesTrak legacy (.com) → AMSAT. Rate limit responses (429/403) trigger immediate failover. Cache extended 6h → 12h. Stale TLEs served up to 48 hours. 30-minute negative cache prevents hammering.
TLE_SOURCESenv var for self-hosters to reorder sources. - Ultrawide monitor layout: Sidebars scale proportionally with viewport using
clamp()(left: 260–480px, right: 280–500px). On 2560px displays, sidebars grow to ~960px combined instead of being capped at 660px. Panel height caps removed — DXpeditions, POTA, Contests flex to fill space. - Mobile single-module scroll: Mobile layout (<768px) rebuilt with full-width cards, 60vh map, scroll-snap momentum, and proper vertical stacking order.
- Russian translation (Русский 🇷🇺) — 379 keys, 100% coverage
- Georgian translation (ქართული 🇬🇪) — 379 keys, 100% coverage
- 13 languages total: en, de, es, fr, it, ja, ko, ms, nl, pt, sl, ru, ka — all at 100%
- Global log rate limiter: Token bucket wraps
console.log/warn/errorto prevent Railway/cloud log pipeline floods regardless of source. Burst of 20, refill 10/sec, 60-second drop summary. - WhatsNew notice banner: Release announcements can now include a highlighted notice bar (used for the Tuesday schedule announcement).
[15.5.9] - 2026-02-20
Added
- APRS-IS live tracking: Full APRS integration via server-side APRS-IS connection (rotate.aprs2.net). Stations parsed in real-time with position, course, speed, altitude, and symbol. Watchlist groups for EmComm nets, ARES/RACES events, Field Day tracking.
- Wildfire map layer: Active wildfires worldwide via NASA EONET satellite detection. Markers with severity indicators under new Natural Hazards category.
- Floods & Storms map layer: Active floods and severe storms worldwide via NASA EONET. Grouped under Natural Hazards in Settings.
- PSKReporter TX/RX split view: Separate "Being Heard" and "Hearing" tabs with per-direction counts, replacing combined view.
- Map layers categorized & sorted: Settings groups layers by category (📡 Propagation, 📻 Amateur Radio, 🌤️ Weather, ☀️ Space Weather, ⚠️ Natural Hazards, 🪨 Geology, 🗺️ Overlays) with alphabetical sorting within each.
- 100% translation coverage — all 11 languages: Every string fully translated. Previously 45–61% coverage with 292 missing keys total.
Fixed
- Duplicate WSJT-X/PSK spots (#396): Content-based dedup IDs replace timestamp-based. QSO logging checks call+freq+mode within 60s. MQTT ingestion deduplicates before buffering.
- Windows update mechanism: Git operations use proper path resolution and restart handles Windows process semantics.
- DX Cluster time display: Spot timestamps now show relative time ("5m ago") with original UTC in parentheses.
[15.5.8] - 2026-02-19
Fixed
- Memory leaks — three unbounded caches: Propagation heatmap (200-entry cap, 10-min purge), custom DX sessions (15-min reap), DX path cache (100-key cap, 5-min cleanup).
- Merge conflict cleanup: Duplicate zoom buttons, triplicated switch/case blocks, duplicate variable declarations, broken cache check.
Added
- Live NASA Moon imagery: Dial-A-Moon 730×730 JPG with 1-hour server-side cache replaces static SVG.
- Map legend & band colors restored: Clickable band color legend, rotator bearing line, satellite tracks, My Spots markers.
[15.5.7] - 2026-02-19
Added
- Settings export filenames include time: e.g.
hamclock-current-2026-02-19-143022.json— multiple exports no longer overwrite.
[15.5.6] - 2026-02-19
Fixed
- Draggable panel disappear bug: Stale mousemove/mouseup listeners from layout switches teleported panels off-screen. Fixed with AbortController cleanup.
- Portable callsign location: PJ2/W9WI, DL/W1ABC now resolve to correct DXCC entity via new
extractOperatingPrefix(). - Rig control CW mode: Band plan JSON now labels CW segments correctly. Rewritten
mapModeToRig()for proper CW/SSB/DATA switching. - Rig Listener FT-DX10 & Windows serial: DTR assertion fix for CP210x adapters, npm path resolution on Windows.
- Emoji icons on Linux: Proper emoji font-family CSS stack, auto-installed
fonts-noto-color-emojiin Pi setup.
Added
- Satellite info minimize button: Collapse floating window to slim header during map viewing.
[15.5.5] - 2026-02-18
Fixed
- Leaflet load race condition: Map polls up to 5 seconds for vendor script with actionable error message if it fails.
Added
- Prettier code formatting pipeline with
.prettierrc, pre-commit hooks (Husky + lint-staged), and CI enforcement
[15.5.4] - 2026-02-18
Added
- Satellite tracker overhaul — Floating data window, blinking visibility indicators, pinned satellite tracking, GOES-18/19 weather satellites re-enabled
- SOTA summit details — Spots now include full summit info (name, altitude, coordinates, points) from the official SOTA summits database, refreshed daily
- POTA/WWFF click-to-tune — Park spots now properly trigger rig control when clicked
- Community tab — New tab in Settings with GitHub, Facebook, and Reddit links plus a contributor wall
- SEO & branding — Favicon, Open Graph social cards, JSON-LD structured data, canonical URL, robots.txt, sitemap.xml
- Contributors list — 23 contributors recognized in the Community tab
Fixed
- WSJT-X rig tuning — Click-to-tune now sends the dial frequency instead of the audio offset for FT8/FT4 decodes
- Frequency display — POTA, SOTA, and WWFF panels now consistently show frequencies in MHz
- SOTA QRT filtering — Operators who have signed off (QRT) are filtered out of the spots list
- Favicon not showing — SEO and favicon tags were only in the monolithic fallback, not the Vite-built index.html that production serves
Removed
- Nested duplicate
openhamclock-main/directory (3.7MB waste) - Backup/debug files:
.jsxbak,.backup,.bak,tle_backup.txt, test scripts, debug patches - Stale dev notes:
TODAYS_PLUGIN_UPDATES.md,PLUGIN_DOCUMENTATION_SUMMARY.md,RIG_CONTROL_COMPARISON.md - Deprecated
rig-bridge/andrig-control/directories (replaced byrig-listener/) - Duplicate
vite.config.js(keeping onlyvite.config.mjs) - Duplicate
build-rig-listener.ymlworkflow
Improved
- New
docs/ARCHITECTURE.md— full codebase map for contributors - Rewritten
CONTRIBUTING.md— proper dev setup, code patterns, testing checklist .editorconfigfor consistent formatting across editors.gitignoreupdated to prevent future cruft accumulation- Updated
CHANGELOG.mdwith all missing versions (15.4.1 through 15.5.3)
[15.5.2] - 2026-02-16
Fixed
- Railway OOM crashes — Memory leak investigation at 1800-2300 concurrent users:
callsignLocationCache(RBN skimmers) had no cap — added 2000-entry limit with oldest-first evictiongeoIPCachestored duplicate data in both a Map and a plain object — eliminated object, reconstruct only at save time- Stats save interval reduced from 60s to 5 minutes to reduce GC pressure
- Memory logging — Added periodic heap usage reporting for leak detection
- QRZ auth cooldown — Suppressed BadRequestError spam during rate limiting
- Heap limit increased to 2048MB for high-traffic deployments
[15.5.1] - 2026-02-15
Added
- cty.dat DXCC entity database — Callsign identification now uses the full AD1C cty.dat database (~400 entities, thousands of prefixes). Replaces the old 120-entry prefix table.
- Smarter DX cluster filtering — Spotter/spot continent/zone filtering uses cty.dat for accurate identification
Fixed
- MUF layer regression — The ionosonde-based MUF overlay was missing from Map Layers; restored
- VOACAP power levels — Changing TX power now produces dramatically different propagation maps as expected
[15.5.0] - 2026-02-15
Added
- Direct rig control — Click any DX spot, POTA activation, or WSJT-X decode to tune your radio. Supports Yaesu, Kenwood, Elecraft, and Icom via USB serial.
- One-click rig listener download — Download the Rig Listener for Windows, Mac, or Linux from Settings. Double-click to run — auto-installs everything.
- Interactive setup wizard — Detects USB serial ports, asks radio brand/model, saves config, connects in 30 seconds.
- Live frequency & mode display — Real-time frequency/mode shown on the dashboard, polling every 500ms.
- Night darkness slider — Adjust nighttime shading intensity on the map.
- Hosted user cleanup — Rotator panel and local-only features hidden for hosted users.
[15.4.1] - 2026-02-15
Added
- QRZ.com callsign lookups — 3-tier waterfall: QRZ → HamQTH → prefix estimation
- Antenna rotator panel — Real-time azimuth display and Shift+click map control
- Mouse wheel zoom sensitivity — Adjustable scroll-to-zoom speed
- Map lock — Prevent accidental panning/zooming
- Clickable QRZ callsigns — Callsigns link to QRZ.com profiles across all panels
- Contest calendar links — Contest names link to WA7BNM calendar
- World copy replication — All markers replicate across three world copies
- RBN firehose fix — No more lost spots from telnet buffer overflow
- VOACAP power reactivity — Heatmap updates immediately on power/mode change
- PSK Reporter direction fix — Map popups show correct remote station callsign
[15.2.12] - 2026-02-12
Fixed
- Critical memory leak (OOM at 4GB after ~24h) — Multiple unbounded data structures in the PSK-MQTT proxy caused heap exhaustion:
recentSpotshad no cap on insert — spots were.push()ed with no limit, only trimmed to 500 every 5 minutes. With 1000+ subscribed callsigns, hundreds of thousands of spots accumulated between cleanups. Now capped at 200 per callsign at insert time.recentSpotsandspotBufferentries were never cleaned up when callsigns unsubscribed — every callsign that disconnected left behind up to 500 spots for up to 1 hour. Over 24 hours with thousands of unique visitors, this accumulated hundreds of MB of orphaned spot data. Now deleted immediately on unsubscribe.spotBufferentries for unsubscribed callsigns were never cleaned in the 5-minute cleanup cycle (flush only iteratedsubscribers, notspotBuffer). Now cleaned.mySpotsCache(HamQTH spot lookups) grew forever with no eviction. Now cleaned every 2 minutes.- Removed dead
pskReporterSpotscache (tx/rx Maps with cleanup timer) that was never written to
- Added memory monitoring — Logs RSS, heap usage, and data structure sizes every 15 minutes for leak detection
- Set explicit Node.js heap limit (1GB) in Dockerfile to fail fast on leaks instead of slow-dying at 4GB
- Double SSE connection eliminated —
PSKReporterPanelwas callingusePSKReporter()internally whileApp.jsxalready had one open for the same callsign. Every user opened 2 SSE connections. Now the panel receives data as a prop from the single app-level hook, halving SSE traffic and server memory. - MQTT connack timeout crash —
removeAllListeners()during client teardown stripped the error handler; when the old client later emittedconnack timeout, Node.js crashed on the unhandled error event. Now re-attaches a no-op error handler after stripping listeners. Added globaluncaughtExceptionhandler as safety net. - SSE flush interval increased from 10s to 15s to reduce network egress
- Solar image disappearing after ~20 minutes —
onErrorhandler permanently hid the<img>element withdisplay: noneon any load failure, with no retry or recovery. A single transient network blip would make the image vanish until page refresh. Also, the cache-buster timestamp was computed once at render time and never updated, so the image URL went stale. Now uses React state with a 15-minute refresh interval, shows a "Retrying..." placeholder on error, and auto-retries after 30 seconds. - DX Lock / Settings buttons hidden or overlapping in Classic and Tablet layouts — Buttons were positioned at
top: 10pxwith hardcodedleftvalues that collided with WorldMap's built-in SAT and CALLS toggle buttons. Classic layout also lackedzIndex, causing Leaflet to render over them. Moved both buttons to bottom-left of map in a flex group (Classic) or standalone (Tablet), avoiding all conflicts with WorldMap's top-row controls. - Pi kiosk update fix —
update.shwithgit stash --include-untrackedwas swallowing Pi helper scripts (kiosk.sh,start.sh,stop.sh, etc.) that live in the repo root but aren't tracked by git. The stash was never popped, so the scripts vanished after update, breaking kiosk auto-start on reboot. Now preserves and restores these scripts across the update. Also added them to.gitignoreso git never treats them as untracked files.
[15.2.11] - 2026-02-11
Added
- ID Timer panel (Dockable layout) — 10-minute countdown timer that reminds operators to identify their station. Displays a large countdown with progress bar; in the final minute the display turns red and pulses. At expiration, plays three short beeps via Web Audio API and shows a full-screen overlay with your callsign in large blinking text. Clicking anywhere dismisses the alert and resets the timer. Start/Stop button lets operators pause the timer when not on the air. Available from the
+panel picker as 📢 ID Timer
Fixed
- PSK-MQTT reconnect fork bomb — When the MQTT broker connection dropped,
pskMqttConnect()called.end(true)on the old client, which fired itscloseevent, which calledscheduleMqttReconnect(), which calledpskMqttConnect()again — each cycle doubling the number of pending reconnect chains. Over hours of downtime this created hundreds of parallel reconnect loops, flooding logs withDisconnected from mqtt.pskreporter.infoand exhausting resources. Three fixes: (1) strip all event listeners from old client before.end(true)so itscloseevent can't schedule a reconnect; (2) stale-client guard onclose/error/offlinehandlers — only react if the firing client is still the current one; (3) single reconnect timer —clearTimeoutbefore scheduling a new reconnect, preventing multiple pending timers
[15.2.10] - 2026-02-11
Added
- SOTA (Summits on the Air) panel — New SOTA activator spots panel alongside POTA. In Classic and Modern layouts, the POTA slot now has POTA/SOTA tabs (like the Solar panel cycling) with independent Map ON/OFF toggles for each. In Dockable layout, SOTA is a fully separate panel in the panel picker (⛰️) so you can dock it independently, stack it with POTA, or place it anywhere
- SOTA map markers — Orange diamond markers for SOTA activators on the world map (distinct from POTA's green triangles). Callsign labels shown when DX labels are enabled. Popup shows summit reference, name, and points. Separate
showSOTAmap layer toggle. Legend shows◆ SOTAwhen active - SOTA data hook —
useSOTASpotsfetches from the existing/api/sota/spotsserver endpoint (SOTA API v2). Maps summit details including lat/lon, altitude, and activation points. 2-minute refresh cycle matching POTA
Fixed
- DX location lock not working — Clicking callsigns in DX Cluster or PSK Reporter panels moved the DX point even when locked. Lock check was only in the WorldMap click handler;
handleDXChangeinuseDXLocationnow gates all updates throughdxLockedRef - Map overlays disappear at dateline (#327) — Replaced antimeridian path splitting with world-copy duplication (same approach as the GrayLine plugin). Polylines and circle markers are now rendered at -360°, 0°, +360° longitude offsets so they appear on every visible map copy. Affects DX Cluster paths, PSK Reporter paths, WSJT-X paths, satellite tracks/footprints, great circle lines, and contest QSO lines. Users in Australia, New Zealand, and Pacific islands no longer lose spots when panning
[15.1.9] - 2026-02-10
Added
- Server-side settings sync (opt-in) — All UI preferences (layout, panel visibility, map layers, filters, theme, temp unit, solar panel mode, etc.) can now be persisted on the server in
data/settings.json. Enable withSETTINGS_SYNC=truein.env— designed for single-operator self-hosted/Pi deployments where you want every device (phone, tablet, desktop) to share the same configuration without setting up each browser individually. Disabled by default for multi-user hosted deployments like openhamclock.com where each user's settings live in their own browser localStorage. When enabled: server → browser on page load (server wins), browser → server on any change (2s debounce). First device to connect seeds the server; subsequent devices inherit settings
Fixed
- Stale SFI and SSN values — SFI was reading from
f107_cm_flux.jsonwhich stopped updating at 2025-12-31, showing a month-old value of 170. SSN was reading fromobserved-solar-cycle-indices.jsonwhich only has monthly averages. Now uses three-tier fallback: (1) SWPCsummary/10cm-flux.jsonfor current SFI (updates every few hours), (2) N0NBH/hamqsl.com feed for both SFI and daily SSN (same source as GridTracker, Log4OM, and hamqsl.com), (3) archive endpoints for history graphs only. Propagation predictions also updated to use current values. N0NBH cache pre-warmed on server startup - RBN only showing CW spots — The RBN telnet parser regex required a
WPMfield, which only CW spots have. FT8, FT4, RTTY, and PSK spots were silently dropped. Fixed regex to match all spot formats by terminating atdBand optionally extracting WPM/BPS speed afterward. RBN buffer increased from 500 → 2000 spots - "fatal: couldn't find remote ref" on update (#293) — Update script and server-side git functions didn't handle broken git state: missing/wrong remote URL, detached HEAD, stale remote refs, or missing upstream tracking. Now auto-fixes remote URL, fetches with
--prune, detects and recovers detached HEAD, sets upstream tracking, and falls back togit reset --hardifgit pullfails - K-Index forecast bars not rendering — Extra wrapper
<div>withflexDirection: columnbroke the parent'salignItems: flex-endheight calculation, collapsing bar heights to zero - PSK-MQTT "Batch subscribe error" log spam — When the MQTT broker connection was unstable, each reconnect cycle logged
Batch subscribe error: Connection closedfor every attempt. Now suppresses expected "Connection closed" errors in the batch subscribe callback (same fix as v15.1.6 for individual subscribes). Also: MQTTon('error')no longer double-logs "Connection closed" alongsideon('close'); disconnect messages uselogErrorOnceto dedup; reconnect messages throttled to 1st attempt and every 5th - WSPR Heatmap double-logging 503 errors — Each 503 response logged twice: once from the fetch handler with the backoff duration, and again from the catch block. Also, changing backoff values (
36s,72s, etc.) defeatedlogErrorOncededup. Fixed: single log line per failure, stable dedup key
[15.1.8] - 2026-02-10
Changed
- Weather → client-direct Open-Meteo — Removed entire server-side weather stack (NWS, Open-Meteo proxy, background worker, throttle queue, cache). All weather is now fetched directly by each user's browser from Open-Meteo. Rate limits are distributed across all user IPs instead of concentrated on our server — eliminates the 429 backoff death spirals that plagued 2,000+ user deployments. Optional Open-Meteo API key field in Settings for users who want higher limits. Removed ~400 lines of server code
- Solar indices panel — Each section (SFI, K-Index, SSN) now shows contextual detail: condition labels (e.g. "Excellent", "Quiet", "High"), chart descriptions ("10.7cm Solar Flux — 20-day trend"), value ranges, time axis labels on K-Index bars ("Now → +24h"), and fallback explanatory text when no history data is available
Fixed
- Blank screen —
filteredSatellites is not defined— DockableApp and ClassicLayout passed rawsatellites.datato WorldMap instead offilteredSatellites. The variable was never destructured from props, causing a ReferenceError that crashed the entire React tree with no error boundary to catch it. Fixed all three layouts to properly receive and passfilteredSatellites. Also means satellite filters in Settings now actually work in dockable and classic layouts - Blank screen after update — After server updates, browsers with cached old JS chunks would fail to load new modules, crashing the React app with a blank screen (users had to clear cookies/cache to fix). Three fixes: (1) global chunk-load error handler in
index.htmldetects stale module import failures and auto-reloads once; (2)update.shnow deletesdist/before rebuilding to prevent old hashed chunks from being served alongside new ones; (3) backward-compatible/api/weatherstub endpoint returns{ _direct: true }so old cached client code doesn't 404 - Global error boundary — Added
ErrorBoundarycomponent wrapping the entire app. Future render crashes show a recovery UI with "Reload Page" and "Clear Cache & Reload" buttons plus expandable error details, instead of a blank screen
[15.1.7] - 2026-02-09
Added
- Upstream Request Manager — New
UpstreamManagerclass prevents request stampedes on external APIs. Three-layer protection: (1) in-flight request deduplication — 50 concurrent users trigger 1 upstream fetch, not 50; (2) stale-while-revalidate — serve cached data instantly while refreshing in background; (3) exponential backoff with jitter per service. Applied to PSKReporter HTTP and WSPR Heatmap endpoints - PSKReporter Server-Side MQTT Proxy — Server now maintains a single MQTT connection to
mqtt.pskreporter.infoinstead of each browser opening its own. Spots are buffered per callsign and pushed to clients via Server-Sent Events (SSE) every 10 seconds. Dynamic subscription management: subscribes when first SSE client connects for a callsign, unsubscribes 30s after last client disconnects, disconnects from broker entirely when no clients are active. Exponential backoff on broker disconnects. Health dashboard shows MQTT proxy stats (connected/callsigns/spots/clients). ClientusePSKReporterhook rewritten to useEventSourceinstead ofmqttlibrary — no more direct browser-to-broker connections - GeoIP Country Statistics — Visitor IPs resolved to country codes via ip-api.com batch endpoint (free, no API key). Results cached persistently across restarts.
/api/healthJSON includesvisitors.today.countriesandvisitors.allTime.countries(sorted by count). HTML dashboard shows "🌍 Visitor Countries" section with flag emoji badges for today and horizontal bar chart with percentages for all-time data - Weather error/retry UI — WeatherPanel now shows loading skeleton, error messages with retry countdown, and stale-data badges instead of silently disappearing when weather API is rate-limited
- WSJT-X Decode Retention Control — New time filter dropdown (5m / 15m / 30m / 60m) in the WSJT-X panel header controls how long decoded messages are kept visible in the list and on the map. Default 30 minutes, persisted in localStorage
Fixed
- Weather 429 cascade — Multiple issues caused weather to disappear for all users: (1) each WeatherPanel called
useWeather()independently, doubling API calls; now fetched once at App level and passed asweatherDataprop; (2) no retry on 429 — client waited full 15-min poll; now retries at 15s→30s→60s→120s→300s; (3)WeatherPanelreturnednullon error with no feedback; now shows loading/error states - Weather overwhelmed at 2000+ users — Server was exhausting Open-Meteo's free tier (10K/day) by proxying weather for all users through a single IP. Moved weather to client-direct: each user's browser fetches from Open-Meteo directly, distributing rate limits across all user IPs. Optional API key in Settings for higher limits
- WSJT-X decodes not mapping correctly (#299) — Only 13 of 100 decodes showed map pins because: (1) only CQ messages were mapped — all QSO exchanges (signal reports, RR73, 73, grid exchanges) were filtered out even when a grid square was present; (2) grid regex
^grid$only matched if the exchange was nothing but a grid — messages likeEN82 a7(grid + signal report) failed; (3) no memory between decodes — once a station's CQ with grid scrolled off, subsequent exchanges from that callsign lost their location. Fix: map ALL decode types with resolved coordinates, extract grids from anywhere in exchange text, maintain a callsign→grid cache across decodes, and fall back to callsign prefix estimation as a last resort. Prefix-estimated locations shown at reduced opacity with (est) label in popup - PSKReporter SSE stream stuck at "Connecting" — Compression middleware was gzip-buffering SSE events; API cache middleware was setting
Cache-Controlon the stream endpoint. Fix: skip compression fortext/event-stream, skip cache headers for/stream/paths, add explicitres.flush()after every SSE write, setContent-Encoding: identityandno-transformheaders - "vite: not found" after update (#284) —
npm installskips devDependencies whenNODE_ENV=productionis set, leavingviteandvitestuninstalled. Three fixes: (1) all npm scripts now usenpx vite/npx vitestwhich auto-resolves fromnode_modules/.bin; (2)update.sh,setup-pi.sh, andsetup-linux.shnow usenpm install --include=devto force devDependency installation regardless of NODE_ENV; (3)prestartbuild step no longer runs tests —npm startjust builds and starts, tests are separate vianpm test - VOACAP heatmap blocks DX click — Heatmap grid rectangles had
interactive: truewith popup bindings, which consumed map clicks before they could reach the DX-setting handler. Set tointeractive: falseso clicks pass through. The color-coded grid with legend still communicates propagation reliability visually - README/docs cleanup — Corrected OpenWeatherMap description (only needed for cloud layer overlay, not weather data). Added "Can't find
.env?" guidance box with instructions for showing hidden files on Linux/Pi/Mac. Added FAQ entry about.envlocation. Weather data sources section updated to reflect client-direct Open-Meteo architecture - PSK-MQTT "Connection closed" subscribe spam — When the MQTT broker connection dropped, a race condition caused
pskMqtt.connectedto still betruewhile the socket was dead. Incoming SSE clients would callsubscribeCallsign(), which passed the connected check but got "Connection closed" callbacks — one error per callsign, flooding the log with 40+ lines. Fix: suppress expected "Connection closed" errors (reconnect handler re-subscribes all callsigns anyway), and batch all reconnect subscriptions into a single MQTT subscribe call instead of individual calls per callsign
Removed
- PSKReporter HTTP backfill — Removed the
/api/pskreporter/http/:callsignendpoint and all client-sidefetchHistorical()code. With 2,000+ concurrent users, every new SSE connection triggered 2 HTTP requests to PSKReporter's retrieve API (TX + RX), causing constant 503 errors and backoff. The backoff was shared with the WSPR heatmap endpoint, so PSK failures were taking WSPR down too. The SSE connected event already delivers up to 500 recent spots from the server's MQTT buffer — no HTTP backfill needed. Net effect: zero HTTP requests to PSKReporter for live spot data, cleaner upstream status on health dashboard - WSPR Heatmap had zero backoff — PSKReporter 503 responses were ignored; WSPR kept hammering on every 2-min poll. Now shares PSKReporter's exponential backoff via UpstreamManager
Changed
- WSJT-X decode limits — Server buffer: 200 → 500 decodes. Max age: 30 → 60 minutes. Client ring buffer: 200 → 500. These are the raw limits; the new retention dropdown (5m/15m/30m/60m) controls what the user actually sees
- WSPR client polling — 2 min → 5 min (server caches for 10 min anyway)
- PSKReporter backoff — Replaced fixed-duration backoff (15 min / 1 hr) with exponential backoff: 30s → 60s → 120s → ... capped at 30 min, with 0-15s random jitter to prevent synchronized retry storms
[15.1.1] - 2026-02-09
Added
- VOACAP Propagation Heatmap — New map layer plugin (
voacap-heatmap) overlays color-coded propagation predictions across the globe for a selected band. Draggable/minimizable control panel with band selector (160m–6m), grid resolution (5°–20°), and color legend. Server-side/api/propagation/heatmapendpoint computes reliability grid using ITU-R P.533-style model with live solar indices. 5-minute server cache, 3 world copies for dateline support, click popups with reliability %, distance, and grid coordinates - Propagation Mode & Power — VOACAP predictions now factor in operating mode and TX power. Eight modes supported (SSB, CW, FT8, FT4, WSPR, JS8, RTTY, PSK31) with physically-modeled decode advantages (+34dB for FT8, +41dB for WSPR vs SSB baseline). Power offset in dB relative to 100W. Signal margin widens/narrows effective MUF/LUF window — FT8 shows bands "open" that SSB shows "closed". Configurable in Settings → Station tab with preset power buttons (5W/25W/100W/1.5kW) + custom watt input. Live margin readout. Applied to both main propagation panel and VOACAP heatmap map layer
- Distance Units — Global metric/imperial toggle in Settings. Affects all distance displays: DE↔DX distance (LocationPanel), propagation path distance, ionosonde distance, satellite altitude & range, great circle path popup, WSPR spot distances & efficiency, VOACAP heatmap cell popups. Default: Imperial (mi)
- Custom Terminator — Replaced CDN-based
L.terminatorwith built-insrc/utils/terminator.jsimplementation that spans 3 world copies for seamless dateline crossing
Fixed
- Gray line disappearing past dateline — Replaced
splitAtDateLine()withunwrapAndCopyLine()/unwrapAndCopyPolygon()in gray line plugin. All 5 render paths fixed (main terminator, enhanced DX zone, civil/nautical/astronomical twilight) - Sun/moon marker updates — Now update every 60 seconds instead of only on initial render
- DX Cluster frequency format (Classic/Tablet/Compact) — Frequencies showed
14.1instead of14.070in non-Modern layouts. Fixed.toFixed(1)→.toFixed(3)and added kHz→MHz conversion for all 3 ClassicLayout DX cluster displays
[15.0.2] - 2026-02-08
Added
- Per-panel font sizing (Dockable Mode) — A−/A+ buttons in each panel's tabset header. 10 zoom steps from 70% to 200%, persisted per-panel in localStorage. Percentage badge shown when zoomed; click to reset. World Map excluded (has its own zoom)
- DX News Ticker toggle — New checkbox in Settings → Map Layers tab to show/hide the scrolling DX news ticker. Persisted in localStorage with other map layer settings
- Weather proxy — New
/api/weatherserver endpoint proxies Open-Meteo requests. Coordinates rounded to ~11km grid for cache sharing across users. 15-minute cache, 1-hour stale serving on rate limit/errors. Client debounced (2s) to prevent rapid-fire calls when clicking through DX spots
Changed
- ITU-R P.533 by default — All installs now use the public OpenHamClock ITURHFProp service (
proppy-production.up.railway.app) for propagation predictions out of the box. No.envconfiguration needed. Self-hosting still supported viaITURHFPROP_URLoverride
Fixed
- DX Cluster spot clicks — Clicking a DX cluster spot now updates the DX panel and map. Root cause:
DXClusterPanelhad noonClickhandler; paths data with coordinates wasn't being looked up. Fixed across Modern, Classic, and Dockable layouts - RBN layer showing N0CALL — RBN (and all plugin layers) showed "N0CALL" instead of the user's callsign. Root cause:
WorldMapwasn't passingcallsign,locator, orlowMemoryModetoPluginLayer. Also fixed 4 of 6WorldMapinstances across layouts that were missing thecallsignprop entirely - Update button fails with "Local changes detected" —
git status --porcelainblocked updates when file permissions changed (e.g.,chmod +x update.sh) or on cross-platform mode differences. Fix:git config core.fileMode falseset at server startup, in setup scripts, and inupdate.sh. Auto-update now stashes local changes before pulling instead of refusing - Update button missing in Dockable Mode —
DockableAppwasn't passingonUpdateClick,updateInProgress, orshowUpdateButtonto the Header component - PSKReporter missing spots — Only showed spots received after page load (MQTT-only, no history). Now fetches historical spots via
/api/pskreporter/http/:callsignon connect, then merges with real-time MQTT stream. Also: time window increased from 15 to 30 minutes, max spots increased from 100 to 500 (50 in low-memory mode), deduplication changed from freq-based (dropped legitimate spots) to callsign+band keyed (keeps most recent per station per band), server-side report cap raised from 100 to 500 - Update script "fatal: couldn't find remote ref master" — The
main||masterfallback pattern rangit pull origin mastereven aftergit pull origin mainsucceeded (non-zero exit from suppressed warnings). Script now detects the correct branch once at startup. Same fix applied to server-side auto-update - Stale browser cache after updates —
index.htmlwas cached for 1 day (maxAge: '1d'), causing browsers to load old JavaScript bundles after a local update. New features (like toggles) wouldn't appear until cache expired. Fix:index.htmlnow served withno-cache, no-store, must-revalidateheaders. Hashed JS/CSS assets still cached for 1 year (filenames change on rebuild) - WSJT-X relay agent ECONNRESET — Relay v1.1.0: added
Connection: closeheader, startup connectivity test, clear error diagnostics for ECONNRESET/ECONNREFUSED/DNS/timeout - Pi kiosk mode loses settings on reboot — Chromium
--incognitoflag wiped localStorage on every restart. Replaced with dedicated--user-data-dirprofile.update.shauto-patches existing kiosk installs - Open-Meteo 429 rate limiting — Client-side Open-Meteo calls replaced with server-side proxy (see Weather proxy above)
- Map jumping near dateline (Australia/NZ/Pacific) — Panning east or west past 180° longitude caused the map to snap violently. Root cause:
moveendhandler normalized center longitude to ±180°, fighting Leaflet'sworldCopyJump. Also: tile layerboundsrestricted to [-180, 180] prevented tiles from loading in world copies. Fix: center longitude no longer normalized (Leaflet manages wrap internally), tile bounds removed for all styles except MODIS (which only covers -180..180)
[15.0.0] - 2026-02-08
Added
- N0NBH Band Conditions — Real-time band condition data from N0NBH's NOAA-sourced feed replaces the old calculated estimates. Server-side
/api/n0nbhendpoint with 1-hour caching. Day/night conditions per band, VHF conditions (Aurora, E-skip by region), geomagnetic field status, signal noise level, and MUF. PropagationPanel shows mini day/night indicators when conditions differ between day and night - User Profiles — Save and load named configuration profiles from Settings → Profiles tab. Each profile snapshots all localStorage keys (config, layout, filters, map layers, preferences). Supports save, load, rename, delete, export to JSON file, and import from file. Useful for multi-operator shared stations or switching between personal views (contest mode, field day, everyday)
- Concurrent User Tracking — Health dashboard (
/api/health) now shows real-time concurrent users, peak concurrent count, session duration analytics (avg/median/p90/max), duration distribution buckets, and an active users table with anonymized IPs and session durations - Auto-Refresh on Update — New
useVersionCheckhook polls/api/versionevery 60 seconds. When a new version is detected after deployment, connected browsers show a toast notification and automatically reload after 3 seconds. Lightweight/api/versionendpoint with no-cache headers - Cloud Layer Restriction — OWM cloud overlay restricted to local installs only via
localOnlyflag in layer registry. Cloud layer invisible on openhamclock.com, visible on localhost/LAN - A-Index Display — A-index and geomagnetic field status added to Header and ClassicLayout solar stats bars, color-coded by severity
- Space Weather Extras — Header shows A-index (color-coded: green <10, amber 10-19, red ≥20) and geomagnetic field status from N0NBH data
Changed
- Band Conditions Rewrite —
useBandConditionshook completely rewritten. Removed 200+ lines of local SFI/K-index formula calculations. Now fetches from/api/n0nbhserver proxy and maps N0NBH grouped ranges (80m-40m, 30m-20m, etc.) to individual bands - Health Dashboard Auto-Refresh — HTML health dashboard now auto-refreshes every 30 seconds
- Stats Grid — Health dashboard shows 6 stat cards (added Online Now and Peak Concurrent)
- Donate Buttons — Hidden in fullscreen mode across Header, ModernLayout, and ClassicLayout
- CI Pipeline — Dropped Node 18 (replaced with 20.x/22.x), replaced
npm startwithnode server.jsto skip redundant prestart build, added retry loop for health check (up to 30 attempts), same retry pattern for Docker health check - Version — Bumped to 15.0.0
Fixed
- CI Health Check Failure —
npm startwas runningprestart(full rebuild) before starting the server, causing the 5-secondsleep+curlto fail every time. Now usesnode server.jsdirectly since the build step already ran
[3.12.0] - 2025-02-03
Added
- State persistence — All user preferences survive page refresh: PSK/WSJT-X panel mode, TX/RX tab, solar image wavelength, weather panel expanded state, temperature unit
- Collapsible weather — DE location weather section collapses to one-line summary, expands for full details
- Lunar phase display — 4th cycling mode in Solar panel shows current moon phase with SVG rendering, illumination %, and next full/new moon dates
- F°/C° toggle — Switch temperature units with localStorage persistence; header always shows both
- Satellite filtering — Complete satellite filter interface in Settings → Satellites tab. Select/deselect from 40+ satellites, real-time visibility status, persistent filters
- WSPR heatmap improvements — Increased brightness (opacity 0.75-1.0), 4-layer glow effect, tighter clustering (radius 50,000m → 6,000m), adjustable opacity slider
- DX Target enhancements — Distance calculation (Haversine), beam headings (SP/LP), color-coded display
- Lightning detection — WebSocket server fallback system, proximity alerts, RBN history management
- WSPR data quality — Spot limit increased from 2,000 to 10,000, detailed marker tooltips with power/SNR/distance/efficiency
Fixed
- PSKReporter MQTT — Field mapping used
sa/ra(ADIF country codes) instead ofsc/rc(callsigns), so no MQTT spots ever matched - PSKReporter RX topic — Subscription pattern had one extra wildcard
- PSKReporter HTTP fallback — If MQTT fails within 12 seconds, automatically falls back to HTTP API
- Map layer persistence — Map style/zoom save was overwriting plugin layer settings. Now merges correctly
- Version consistency — All version numbers now read from package.json as single source of truth
- PSKReporter 403 spam — Server backs off for 30 minutes on 403/429 responses
- WSPR heatmap infinite loop — Removed heatmapLayer from useEffect dependencies
- WSPR grid filter — Supports 2-6 character grids, prefix matching (FN → FN03, FN21)
- WSPR callsign filter — Proper suffix stripping (VE3TOS/M → VE3TOS), respects grid filter state
- Satellite initialization — Fixed ReferenceError when filteredSatellites referenced satellites.data before hook initialized
- VOACAP ionosonde label — Added "Iono:" prefix to clarify it's the data source, not the DX location
Changed
- WSPR update frequency — Polling interval from 5 minutes to 60 seconds
- WSPR band chart — Removed pulsing animation, added smooth CSS transition
Reverted
- WSPR MQTT — Real-time MQTT feed attempted and reverted due to mixed content policy (HTTPS pages cannot connect to insecure WebSocket)
[3.11.0] - 2025-02-02
Added
- PSKReporter Integration — New panel showing stations hearing you (TX) and stations you're hearing (RX). Supports FT8, FT4, JS8, and other digital modes. Configurable time window. Signal paths drawn on map
- Bandwidth Optimization — Reduced network egress by ~85%: GZIP compression, server-side caching, reduced polling intervals, HTTP Cache-Control headers
Fixed
- Empty ITURHFPROP_URL causing "Only absolute URLs supported" error
- Satellite TLE fetch timeout errors handled silently
- Reduced console log spam for network errors
[3.10.0] - 2025-02-02
Added
- Environment-based configuration —
.envfile auto-created from.env.exampleon first run. Supports CALLSIGN, LOCATOR, PORT, HOST, UNITS, TIME_FORMAT, THEME, LAYOUT - Auto-build on start —
npm startautomatically builds React frontend - Update script —
./scripts/update.shfor easy local/Pi updates - Network access configuration —
HOST=0.0.0.0for LAN access - Grid locator auto-conversion — Calculates lat/lon from LOCATOR
- Setup wizard — Settings panel auto-opens if callsign or locator missing
- Retro theme — 90s Windows style
- Classic layout — Original HamClock-style with black background and large colored numbers
Changed
- Configuration priority: localStorage > .env > defaults
- DX Spider connection uses dxspider.co.uk as primary
Fixed
- Header clock "shaking" when digits change
- Header layout wrapping on smaller screens
- Reduced log spam with rate-limited error logging
[3.9.0] - 2025-01-31
Added
- DX Filter modal with tabs for Zones, Bands, Modes, Watchlist, Exclude
- Spot retention time configurable (5-30 minutes) in Settings
- Satellite tracking with 40+ amateur radio satellites
- Satellite footprints and orbit path visualization
- Map legend showing all 10 HF bands plus DE/DX/Sun/Moon markers
Fixed
- DX Filter modal crash when opening
- K-Index display showing correct values
- Contest calendar attribution
[3.8.0] - 2025-01-28
Added
- Multiple DX cluster source fallbacks
- ITURHFProp hybrid propagation predictions
- Ionosonde real-time corrections
[3.7.0] - 2025-01-25
Added
- Modular React architecture with Vite
- 13 extracted components, 12 custom hooks, 3 utility modules
- Railway deployment support
- Docker support
Changed
- Complete rewrite from monolithic HTML to modular React
[3.0.0] - 2025-01-15
Added
- Initial modular extraction from monolithic codebase
- React + Vite build system
- Express backend for API proxying
- Three themes: Dark, Light, Legacy
Version History
- 15.x — N0NBH band conditions, user profiles, concurrent user tracking, auto-refresh, CI fixes
- 3.12.x — PSKReporter fixes, state persistence, satellite filtering, WSPR improvements, lunar phase
- 3.11.x — PSKReporter integration, bandwidth optimization
- 3.10.x — Environment configuration, themes, layouts
- 3.9.x — DX filtering, satellites, map improvements
- 3.8.x — Propagation predictions, reliability improvements
- 3.7.x — Modular React architecture
- 3.0.x — Initial modular version
- 2.x — Monolithic HTML version (archived)
- 1.x — Original HamClock fork
What's Changed
- Rename chromium-browser to chromium in setup script by @m1dst in #1
- Modular staging by @accius in #6
- error logging by @accius in #7
- Update package.json by @accius in #8
- Update ci.yml by @accius in #9
- update spider nodes by @accius in #10
- spider node by @accius in #11
- fixed spider issues by @accius in #12
- error logging silencing by @accius in #16
- Modular staging by @accius in #17
- Modular staging by @accius in #18
- Modular staging by @accius in #20
- less aggressive api polling by @accius in #25
- Modular staging by @accius in #37
- Modular staging by @accius in #38
- Add extensible plugin system for map layers by @trancen in #36
- Add React i18n for translate proposal. First, settings dialog translate by @SebFox2011 in #27
- Modular staging by @accius in #40
- Modular staging by @accius in #41
- fix url by @accius in #43
- maybe created a nightmare by @accius in #44
- Modular staging by @accius in #45
- Modular staging by @accius in #46
- quieting logs by @accius in #47
- Modular staging by @accius in #49
- Update Dockerfile by @accius in #50
- Update server.js by @accius in #51
- relay by @accius in #52
- wsjtx support enabled by @accius in #53
- Modular staging by @accius in #54
- header weather by @accius in #55
- persistance by @accius in #57
- psk updates and version by @accius in #58
- Modular staging by @accius in #59
- Add Dutch language JSON file by @theodeurne76 in #65
- nederlands by @accius in #73
- Modular staging by @accius in #78
- pota and logging issues by @accius in #79
- Update README.md by @accius in #81
- Modular staging by @accius in #87
- New Plugins and fixes by @trancen in #82
- Added the ability to resize the callsign. by @ThePangel in #86
- Korean localization for settings menu + locale entries for layer plugins by @infopcgood in #85
- renamed callsignSize to headerSize, which now also affects the clocks by @ThePangel in #95
- lots of updates by @accius in #96
- Modular staging by @accius in #98
- unify space weather by @accius in #102
- Issue #19 Improve DX Cluster Exclusion (partial) by @rfreedman in #105
- Fixed a few bugs by @trancen in #106
- Added small screen support by @accius in #108
- feat: add dockable panel layout with drag, resize, and tab support by @brianbruff in #110
- Reverse Beacon Network Plugin by @trancen in #121
- Translation Slovenian - S5 by @s53zo in #126
- Dx weather by @dmazan in #128
- Self expanding weather panels by @dmazan in #143
- Modify sunrise and sunset time calculations to use the NOAA standard approach by @dmazan in #151
- Dockable analog clock by @dmazan in #152
- Add Czech translation by @Holyszewski in #138
- Revert "Add Czech translation" by @accius in #161
- Language fixes and working Lightning Layer by @trancen in #133
- Add auto-update scheduler and manual UPDATE button by @s53zo in #125
- N1MM-QSO-UDP ingest by @s53zo in #124
- Revert "N1MM-QSO-UDP ingest" by @accius in #164
- Modular staging by @accius in #165
- Modular staging by @accius in #166
- Modular staging by @accius in #167
- health finished by @accius in #168
- Loads of fixes and changes See CHANGELOG_PR6.md by @trancen in #169
- Issue #19 Improve DX Cluster Exclusion (complete) by @rfreedman in #180
- Modular staging by @accius in #185
- Remove version from docker-compose.yml by @kmanwar89 in #184
- Add N3FJP logged QSO overlay and ingest API by @Delerius in #183
- Pr translate by @SebFox2011 in #123
- Modular staging by @accius in #189
- Updated Fro MODIS Satellite imagery and two addition TLE groups by @creinemann in #192
- Modular staging by @accius in #207
- 112 Add a Brisbane Timezone by @alanhargreaves in #205
- Translate: finishing translate keys by @SebFox2011 in #195
- loop in layers by @accius in #208
- bug by @accius in #209
- Modular staging by @accius in #211
- wspr cache server side by @accius in #213
- egress optimization by @accius in #215
- Add vitest unit testing and unit tests for utils/dxClusterFilters.js by @rfreedman in #229
- Issue #19 - Fix bug in filtering for excluding ITU zones by @rfreedman in #219
- Issue #220 - refactor callsign.js by @rfreedman in #226
- Added Global Clouds plugin provides a real-time satellite-derived cloud cover overlay for the entire world by @creinemann in #224
- add the 'data' directory to .gitignore by @rfreedman in #241
- fix ssn bug by @accius in #245
- updates by @accius in #246
- Refacto App component because is too big by @SebFox2011 in #218
- Modular staging by @accius in #247
- Small new plugin to add the sort and long path from DX to DX to the map by @dmazan in #227
- add DX news toggle by @JoshuaNewport in #250
- Update server.js by @accius in #252
- donate and version by @accius in #253
- TEST AND CHANGELOG by @accius in #255
- Modular staging by @accius in #256
- Modular staging by @accius in #259
- Add Ambient Weather panel and hook by @Delerius in #225
- feat: Add satellite search functionality to Settings panel by @trancen in #254
- Modular staging by @accius in #264
- Fix Satellite Crash in settings. by @trancen in #267
- Fixes and Feature requests by @trancen in #268
- Add HF Band Health panel based on DX Cluster activity by @Delerius in #265
- Modular staging by @accius in #271
- Modular staging by @accius in #272
- Update server.js by @accius in #273
- fixe weather by @accius in #274
- weather updates by @accius in #275
- psk getting pounded fix by @accius in #280
- weather getting pounded by @accius in #283
- Bunch of fixes and tweaks. by @trancen in #294
- weather and psk update by @accius in #300
- fix wjstx by @accius in #301
- Modular staging by @accius in #303
- Modular staging by @accius in #304
- Modular staging by @accius in #313
- Modular staging by @accius in #316
- error logging updates by @accius in #328
- Enhanced City Lights Layer with shading and Dynamic Intensity and CSS Clipping by @creinemann in #325
- Revert "Enhanced City Lights Layer with shading and Dynamic Intensity and CSS Clipping" by @accius in #329
- i18n: Localization parity and UI string refactoring by @yuryja in #315
- Modular staging by @accius in #331
- version bump by @accius in #332
- ID Timer by @accius in #333
- Modular staging by @accius in #344
- Update Dockerfile by @accius in #345
- memory leak causing hard crash by @accius in #368
- psk double sse connections eliminated by @accius in #369
- still working on crashes by @accius in #370
- bug fixes by @accius in #378
- Fix RBN plugin to use HAMQTH lat/lon instead of grid conversion by @trancen in #375
- PstRotatorAz UDP integration, Rotator panel, and map bearing overlay by @Delerius in #372
- Revert "PstRotatorAz UDP integration, Rotator panel, and map bearing overlay" by @accius in #379
- Revert "Fix RBN plugin to use HAMQTH lat/lon instead of grid conversion" by @accius in #380
- Update config.js by @accius in #381
- Revise SECURITY.md to reimagine vulnerability policy by @w8mej in #377
- sec updates by @accius in #382
- Update package.json by @accius in #383
- limits by @accius in #384
- muf map by @accius in #385
- HF Band Health V2: Improved accuracy of band health, Custom tooltips by @Delerius in #296
- Modular staging by @accius in #387
- hamqth lookups by @accius in #388
- Modular staging by @accius in #389
- version bump by @accius in #390
- Modular staging by @accius in #391
- Update package.json by @accius in #392
- Modular staging by @accius in #398
- Refactor City Lights into a modular plugin as a Map Layer Choice and remove vertical terminator line changed and updated satellite display. by @creinemann in #397
- Modular staging by @accius in #418
- Fix #317: Add hyperlink to DX NEWS label by @KentenRoth in #416
- Fix #341 Contest Panel: show all contests and localize time labels by @echo-gravitas in #414
- Modular staging by @accius in #419
- Modular staging by @accius in #420
- Modular staging by @accius in #421
- Re-apply Rotator Panel v1 (post-revert) – clean merge with current upstream by @Delerius in #405
- Add possibility to build app with electron by @SebFox2011 in #216
- [FEATURE] Add mouse scroll wheel scaling adjustment for map zoom by @denete in #367
- version bump and updates by @accius in #423
- rortator issue by @accius in #425
- disables rotator when unhosted by @accius in #426
- Update WorldMap.jsx by @accius in #427
- [FEATURE] Rig Control Integration by @ceotjoe in #436
- Modular staging by @accius in #442
- Modular staging by @accius in #444
- polling fixes by @accius in #447
- [FEATURE] Pause & Resume DX News Ticker by @ceotjoe in #440
- [FEATURE] WWFF Activators #173 by @alanhargreaves in #415
- Modular staging by @accius in #449
- Modular staging by @accius in #450
- fix oom leaks by @accius in #451
- bump version by @accius in #452
- mem leak fix by @accius in #467
- mem leak by @accius in #468
- seo by @accius in #478
- og image by @accius in #479
- icons? by @accius in #480
- favicon by @accius in #481
- settings social by @accius in #482
- fix: remove debug touch indicator from header by @ceotjoe in #457
- Enhanced satellite display. by @creinemann in #472
- Fix: several rigcontrol related fixes by @ceotjoe in #458
- Github Action to create docker images on github Container Registry by @thomas-schreck in #463
- Make SOTA Spots work by @alanhargreaves in #338
- Fix: POTA/SOTA UTC timestamp parsing bug by @ceotjoe in #487
- Fix Rotator usability + local-only safety (addresses setup confusion) by @Delerius in #446
- fix: correct moon phase SVG sweep direction so new moon appears dark by @ceotjoe in #498
- Drop Downs for footprints by @creinemann in #499
- fix: align clock updates to wall-clock second boundaries to prevent d… by @ceotjoe in #495
- feat: display local time and UTC offset in DX target panel by @ceotjoe in #494
- Docs: align dev server ports (Vite 3000, API 3001) by @Delerius in #491
- Add customizable band colors with local persistence and map legend editor; apply colors across map and DX views by @echo-gravitas in #441
- use references to environment variables in the docker-compose.yml by @ftl in #406
- Commas in summitslist.csv get lat/long incorrect by @alanhargreaves in #510
- Improve DX Cluster custom telnet flow, spot-time handling, and DX panel relative time by @echo-gravitas in #402
- Add the callsign toggle button to the SOTA Panel and widen the column for the site reference by @alanhargreaves in #505
- Removed dup prettier from package.json by @echo-gravitas in #517
- DX Weather (Local-Only): hover overlay, popup weather, and DX highlight integration by @Delerius in #520
- Use loopback IP address so docker compose healthcheck passes by @agocs in #523
- [BUG] POTAPanel should display spot.ref rather than spot.locationDesc #394 by @alanhargreaves in #524
- Display the park name along with the reference in the WWFF Panel by @alanhargreaves in #525
- Re-instate the pota-ref fix by @alanhargreaves in #526
- Added Malay language translation, .env file in docker-compose.yml and DXCC flags by @9M2PJU in #507
- DX Weather (Local-Only) – Clean Rebase + Structural Preservation by @Delerius in #528
- Revert "DX Weather (Local-Only) – Clean Rebase + Structural Preservation" by @accius in #534
- Aggregate the common code from POTAPanel, SOTAPanel and WWFFPanel by @alanhargreaves in #532
- Expose port 12060 for N1MM/DXLog by @s53zo in #533
- Add global map band filter across all map layers by @s53zo in #538
- Only display most recent SOTA spot for "callsign summit" by @alanhargreaves in #540
- Auto-follow DX target from newest contest QSO by @s53zo in #371
- Feature/publish image on release by @agocs in #557
- feat: Add Simplified Chinese (zh) translation by @Oukagen in #561
- Add DX beam/distance info to Dockable DX Target panel (match Modern layout) by @echo-gravitas in #546
- feat: add screen wake lock to prevent display sleep on tablets/kiosks by @ceotjoe in #545
- Merge main to staging? by @accius in #565
- DX Weather (local-only): hover overlay + popup injection by @Delerius in #542
- Revert "DX Weather (local-only): hover overlay + popup injection" by @accius in #570
- Add WWBOTA spots by @kwirk in #550
- Weather Panel & Units (Fix #562) by @echo-gravitas in #569
- Updating PRS by @accius in #571
- Staging by @accius in #572
- skip workflows on forks to reduce notification noise by @frankenstein91 in #573
- "did i break it" - yes you did, so i brought it back. :-) by @echo-gravitas in #574
- introduce AddOns ecosystem with APRS and Antenna tools (Userscripts) by @frankenstein91 in #575
- Add PSKReporter style filters to POTA, SOTA, WWFF and WWBOTA by @alanhargreaves in #584
- fix: Allow multiple, optional env files by @KidVizious in #588
- [Feature 342 user theme colors] Add a custom theme for the user to update colors by @denete in #589
- Translation ca by @caballe in #581
- Implemented a new compact map control dock for WorldMap and added a global UI visibility toggle. by @echo-gravitas in #590
- Fix SSN display inconsistencies when value is 0 (Solar Panel vs Header) #586 by @echo-gravitas in #591
- Rotator: Add live connection LED and auto-reconnect support by @Delerius in #582
- feat(rig-control): support port=0 as “no port” and clarify setting labels by @echo-gravitas in #592
- Expire WWBOTA spots older than 1 hour by @kwirk in #595
- Reinstate the SOTA spot duplication checking by @alanhargreaves in #599
- Implemented parity with Dockable DX Target time behavior in Modern layout by @echo-gravitas in #603
- Staging by @accius in #605
- fix assign close bots by @accius in #616
- [FEATURE 608] Add the mode FM to the filters by @alanhargreaves in #613
- [feature/standardize-panels-for-display] added class name panel to components by @denete in #619
- Feature: rig bridge introducing plugin architecture by @ceotjoe in #620
- [AddOns] position of the menu system by @frankenstein91 in #611
- Add onHoverSpot functionality to the Modern Layout and potaSota by @alanhargreaves in #610
- Feature/rig bridge plugin architecture by @ceotjoe in #621
- Bring back feature #233 from PR #590 by @echo-gravitas in #623
- [Enhancemant 585] Split out Distance, Temperature and Pressure in to three individually configurable settings by @alanhargreaves in #624
- Fix config merge order so .env callsign/locator load on first run #615 by @echo-gravitas in #627
- [BUG 614] Some WSJT-X positions are plotted incorrectly by @alanhargreaves in #628
- feat: add manual Maidenhead locator input to DX panel by @ceotjoe in #629
- Make the spot reference column a little wider by @alanhargreaves in #637
- [Bug 607] Incorrect dependency on filtered spots by @alanhargreaves in #638
- simplify portainer deployment from GitHub by @ftl in #639
- Add AM to the list of filters in PSKReporter and ActivatePanel filters by @alanhargreaves in #643
- fix(dx-grid-input): validate Maidenhead ranges and tighten length check by @ceotjoe in #645
- [bug] bug-set-default-theme-active by @denete in #647
- Unify map overlay widget drag-and-toggle behavior by @echo-gravitas in #648
- Fix/setup pi bookworm trixie by @ceotjoe in #651
- Feature Request #553: add separate toggle for DE/DX markers in Map Layers by @echo-gravitas in #653
- Staging by @accius in #654
- Add a hot key (/) to toggle the DE and DX labels by @alanhargreaves in #658
- docs: clarify contributor setup and staging PR workflow, Fixes #663 by @echo-gravitas in #664
- Add TCI/SDR plugin to rig-bridge + bump to v1.2.0 by @ceotjoe in #668
- feat: add inline text size controls to DX News ticker by @ceotjoe in #669
- Staging by @phether in #671
- [BUG 660] POTA & SOTA panels truncate information by @alanhargreaves in #672
- Add DXCC target selector for DX Target panel by @echo-gravitas in #667
- Update to reduce SOTA API load by @vk3arr in #670
- Merge main to Staging by @accius in #676
- Feature 634 - Map Widgets Alignment by @denete in #655
- Fix lightning map layer timestamps by @DigitalFeonix in #657
- [BUG 673] PSKReporter Always Uses FN31 as Grid Square by @alanhargreaves in #681
- Improve TCI plugin diagnostics and Thetis compatibility by @ceotjoe in #684
- [BUG 685] Add full multicast support for WSJT-X, so that multiple apps can listen by @alanhargreaves in #686
- Fix/setup pi electron winstaller arm by @ceotjoe in #690
- Feature/tci rig bridge plugin wsjtx multicast by @ceotjoe in #700
- [FEATURE] Relocate Layout Lock Button so it's not consuming vertical screen space by @denete in #687
- Add optional fixed DX cluster spotter coordinates via env vars by @on6zq in #688
- [BUG 695] Lightning layer is not using settable distance units by @alanhargreaves in #697
- Staging by @accius in #706
- reapplying alans commit by @accius in #711
- [enhancement-703] rebranded the lock layout panel to just layout, by @denete in #704
- [refactor / bugfix] language - sort JSON keys, find missing keys by @MichaelWheeley in #709
- Staging by @accius in #714
- Staging by @accius in #715
New Contributors
- @m1dst made their first contribution in #1
- @trancen made their first contribution in #36
- @SebFox2011 made their first contribution in #27
- @theodeurne76 made their first contribution in #65
- @ThePangel made their first contribution in #86
- @infopcgood made their first contribution in #85
- @rfreedman made their first contribution in #105
- @brianbruff made their first contribution in #110
- @s53zo made their first contribution in #126
- @dmazan made their first contribution in #128
- @Holyszewski made their first contribution in #138
- @kmanwar89 made their first contribution in #184
- @Delerius made their first contribution in #183
- @creinemann made their first contribution in #192
- @JoshuaNewport made their first contribution in #250
- @yuryja made their first contribution in #315
- @w8mej made their first contribution in #377
- @KentenRoth made their first contribution in #416
- @echo-gravitas made their first contribution in #414
- @denete made their first contribution in #367
- @thomas-schreck made their first contribution in #463
- @ftl made their first contribution in #406
- @agocs made their first contribution in #523
- @Oukagen made their first contribution in #561
- @kwirk made their first contribution in #550
- @frankenstein91 made their first contribution in #573
- @KidVizious made their first contribution in #588
- @caballe made their first contribution in #581
- @phether made their first contribution in #671
- @vk3arr made their first contribution in #670
- @DigitalFeonix made their first contribution in #657
- @on6zq made their first contribution in #688
Full Changelog: https://github.com/accius/openhamclock/commits/v15.6.5
Docker image: ghcr.io/accius/openhamclock:15.6.5
docker pull ghcr.io/accius/openhamclock:15.6.5