The Scanner Plugin is a comprehensive add-on for the FM-DX-Webserver that transforms a passive FM receiver into an intelligent, automated FM DX logging station. It provides automatic frequency scanning across the FM band (or a configurable sub-range), real-time RDS-based station identification, sophisticated signal filtering, and automated logging to multiple output formats including HTML, URDS CSV, and FMLIST.
The plugin runs as two cooperating scripts:
Key capabilities at a glance:
plugins/ folder inside the ZIP into:…/fm-dx-webserver-main/plugins/npm run webserver in a Node.js console and check the console output for errors.npm run webserver and verify the console output — the scanner should now initialise and print its configuration summary.…/fm-dx-webserver-main/plugins_configs/scanner.jsonscanner.json is created automatically with sensible defaults. You do not need to create it manually. All subsequent changes to the JSON are picked up on-the-fly without a server restart (see §6.9).
BEEP_CONTROL: true), the speaker npm module will be installed automatically on first start. With newer Node.js versions this may fail — downgrade Node.js if acoustic signalling is required.
The recommended way to create or modify the scanner configuration is the Scanner Wizard, an interactive web tool that generates a ready-to-use scanner.json file with all options described inline:
plugins_configs/scanner.json and restart the server.
Alternatively you can edit the JSON file directly. The sections below describe every parameter group.
| Parameter | Default | Description |
|---|---|---|
Scanmode | 1 | 1 = Online mode (uses fmdx.org TX data for station identification). 0 = Offline mode (no network lookups, station fields left empty). |
Autoscan_PE5PVB_Mode | false | Set to true to use the built-in firmware scan function of PE5PVB / TEF6686 ESP32 receivers. Also recommended for FMDX Scanner Mode. |
Search_PE5PVB_Mode | false | Set to true to use the PE5PVB firmware search function for the ◀◀ / ▶▶ buttons. |
StartAutoScan | "off" | "off" – manual start only. "on" – scan starts automatically with the webserver. "auto" – scan starts 10 s after the last user disconnects and stops when a user reconnects. |
AntennaSwitch | "off" | "on" enables automatic antenna cycling at the upper band limit. Requires at least 2 antennas configured in the webserver. |
OnlyScanHoldTime | "off" | "on" forces the scanner to always wait the full ScanHoldTime before moving on, regardless of RDS data. Useful for FM-DX monitor mode. |
| Parameter | Default | Description |
|---|---|---|
defaultSensitivityValue | 30 | Signal threshold in dBf / dBµV / dBm (unit set by SignalStrengthUnit). Valid values depend on the unit — see table below. If SensitivityCalibrationFrequenz is set, this becomes the threshold above the noise floor (1–10 recommended). |
SensitivityCalibrationFrequenz | "" | A frequency in MHz (e.g. "87.3") on which the scanner measures the current noise floor before each scan pass and adds defaultSensitivityValue to derive the actual threshold dynamically. Leave empty to disable. |
defaultScanHoldTime | 5 | Time in seconds the scanner pauses on a detected frequency before moving on. Valid: 1, 2, 3, 4, 5, 7, 10, 15, 20, 30. Not used in PE5PVB mode. |
scanIntervalTime | 500 | Milliseconds between frequency steps during scanning (max 1000). A higher value increases detection reliability at the cost of scan speed. |
scanBandwith | 0 | IF bandwidth in Hz during scanning. 0 = auto. Supported values: 56000, 64000, 72000, 84000, 97000, 114000, 133000, 151000, 184000, 200000, 217000, 236000, 254000, 287000, 311000. |
tuningLowerLimit | "" | Lower scan band limit in MHz (e.g. "87.5"). Overrides the webserver setting. Leave empty to use the webserver value. |
tuningUpperLimit | "" | Upper scan band limit in MHz (e.g. "108.0"). Maximum is 108.0. Leave empty to use the webserver value. |
SignalStrengthUnit | "dBf" | Unit for all signal strength display and thresholds. Accepted values: "dBf", "dBµV", "dBm". Must match the webserver's configured display unit. |
| Unit | Typical range | Notes |
|---|---|---|
dBf | 1 – 80 | Native hardware unit; no conversion applied |
dBµV | 1 – 80 | Internally offset by +10.875 before sending to tuner |
dBm | −115 – −40 | Internally offset by +119.75 before sending to tuner |
The defaultScannerMode parameter (default: "normal") sets the active scan mode at startup. The user can change it live via the scanner controls dropdown. Available modes:
| Mode | Requires | Description |
|---|---|---|
normal | — | Steps through all frequencies in the configured band at 0.1 MHz increments (0.01 MHz below 74 MHz), stops when signal + RDS detected. |
blacklist | EnableBlacklist: true | Same as normal but skips frequencies listed in blacklist.txt. |
whitelist | EnableWhitelist: true | Scans only the frequencies listed in whitelist.txt at 0.01 MHz increments. |
spectrum | Spectrum Graph plugin + EnableSpectrumScan: true | Uses the spectrum array to select only frequencies above the sensitivity threshold and below the limiter value. Much faster than normal scan. |
spectrumBL | spectrum + EnableBlacklist: true | Spectrum scan with blacklist filtering applied. |
difference | Spectrum Graph plugin + EnableDifferenceScan: true | Scans only frequencies whose signal has changed by more than SpectrumChangeValue dBf/dBµV compared to the previous scan pass. Ideal for detecting tropospheric events. |
differenceBL | difference + EnableBlacklist: true | Difference scan with blacklist filtering applied. |
The spectrum and difference scan modes require the Spectrum Graph plugin to be installed and active. In addition, the variable rescanDelay in the SpectrumGraph.json must be set to 0 so that a fresh spectrum is captured automatically after each full band sweep.
| Parameter | Default | Description |
|---|---|---|
EnableSpectrumScan | false | Enables the spectrum and spectrumBL modes. |
EnableDifferenceScan | false | Enables the difference and differenceBL modes. |
SpectrumLimiterValue | 50 | Upper signal strength limit in dBf/dBµV. Frequencies above this value (strong local stations) are excluded from spectrum/difference scan. Also used as the X-axis limiter displayed in the scanner UI. |
SpectrumPlusMinusValue | 60 | Signal threshold in dBf/dBµV at which the adjacent channels (±0.1 MHz) of a strong local station are also filtered out. |
SpectrumChangeValue | 3 | Minimum signal change in dBf/dBµV between scan passes required for a frequency to be included in difference scan. Set to 0 to disable the difference filter. |
sigArray). The scanner filters this array to find frequencies where the signal is above Sensitivity but below SpectrumLimiterValue, excluding the ±0.1 MHz neighbours of any station above SpectrumPlusMinusValue. Only those surviving frequencies are tuned and checked for RDS.
| Parameter | Default | Description |
|---|---|---|
HTMLlogOnlyID | true | When true, only stations with a known fmdx.org station ID are written to the filtered HTML log. |
HTMLlogRAW | false | When true, a raw (unfiltered) HTML log entry is also written for every received PI code, regardless of identification status. |
HTMLOnlyFirstLog | false | When true, each station is logged only once per session (first-seen mode). Duplicates are suppressed. |
CSVcreate | true | Enables creation of the URDS CSV log file in /web/logs/ and activates the Map Viewer and Validator buttons in the UI. |
CSVcompletePS | true | When true, waits for a complete (error-free) PS name before writing the CSV entry. When false, writes immediately and updates the last entry if the PS improves. |
UTCtime | true | When true, all timestamps in HTML and CSV logs are in UTC. When false, local system time is used. |
Log_Blacklist | false | Enables the log blacklist (blacklist_log.txt). Frequencies and/or PI codes listed there are excluded from HTML and CSV log entries, including manual search results. |
The scanner can automatically submit DX log entries to FMLIST when a station exceeds the configured distance thresholds. A valid OM ID and a webserver UUID token are required.
| Parameter | Default | Description |
|---|---|---|
FMLIST_OM_ID | "" | Your FMLIST OM ID (e.g. "1234"). If empty, the value from the webserver's FMLIST INTEGRATION settings is used. |
FMLIST_Autolog | "off" | "off" – disabled. "on" – log all identified DX stations (hides manual log button). "auto" – log only during autoscan mode. |
FMLIST_MinDistance | 200 | Minimum station distance in km for an autolog entry. Minimum enforced value: 200 km. |
FMLIST_MaxDistance | 2000 | Maximum station distance in km. Stations beyond this are not logged. |
FMLIST_LogInterval | 60 | Minimum interval in minutes before the same station ID can be logged again. Minimum: 60 minutes. |
FMLIST_CanLogServer | "" | Address of a central CanLogServer (e.g. "127.0.0.1:2000") that manages log repetition across multiple webserver instances. When set, the local FMLIST_LogInterval is ignored. |
FMLIST_ShortServerName | "" | Short server identifier (max 10 characters) prepended to FMLIST log messages (e.g. "DXserver01"). |
FMLIST_Blacklist | false | Enables the FMLIST blacklist (blacklist_fmlist.txt). Frequencies and/or PI codes listed there are excluded from FMLIST submissions. |
config.identification.token) must be set and non-null. Without it, FMLIST submissions are blocked and an error is logged. Stations beyond 900 km are automatically tagged as Sporadic E type on FMLIST.
Since version 4.2, the scanner supports multiple named configuration profiles. Additional profiles are stored as extra JSON files in the plugins_configs/ folder following the naming pattern:
plugins_configs/ ├── scanner.json ← default profile ├── scanner_Dave.json ← profile "Dave" ├── scanner_SpE.json ← profile "SpE" └── scanner_Tropo.json ← profile "Tropo"
When more than one scanner config file exists, a drop-down selector appears in the webserver settings panel (admin login required). Selecting a profile instantly loads and applies all its settings — including scan mode, sensitivity, FMLIST options, and logging preferences — without restarting the server. The active profile is persisted across server restarts in plugins/Scanner/scanner_state.json.
plugins_configs/. Changes to any config file on disk are picked up immediately via the file watcher (§6.9).
The Auto Scan button is injected into the FM-DX-Webserver's main tuning panel. Its behaviour depends on press duration:
| Interaction | Effect | Requirement |
|---|---|---|
| Short press | Starts / stops the automatic scanning process | Admin or Tune authentication |
| Long press (≥ 1 s) | Opens or closes the scanner control panel (Sensitivity / Mode / Hold Time dropdowns) | Admin authentication |
While autoscan is active:
When the scanner control panel is open (long-press on Auto Scan button), three dropdown controls appear:
| Control | Title attribute | Description |
|---|---|---|
| Sensitivity | Scanner Sensitivity | Sets the minimum signal threshold. Available values depend on the active SignalStrengthUnit. In PE5PVB mode, shows values 1–30 without a unit suffix. |
| Scanner Mode | Scanner Mode | Selects the active scan mode. Only modes enabled in the configuration (blacklist, whitelist, spectrum, etc.) appear in the list. |
| Scanhold Time | Scanhold Time | Sets the hold time in seconds: 1, 2, 3, 4, 5, 7, 10, 15, 20, 30. |
Changes to any dropdown are sent immediately to the server via WebSocket. The server responds with an updated broadcast that refreshes all connected clients. The control panel visibility is persisted in a browser cookie (scannerControlsStatus) for 7 days.
The scanner client also watches the webserver's signal-unit selector (#signal-selector-input) every 250 ms. When the unit changes (dBf → dBµV → dBm), the sensitivity dropdown is rebuilt with the correct value list and labels, and the currently displayed sensitivity value is recalculated accordingly.
Two search buttons (◀◀ and ▶▶) are inserted next to the standard frequency step buttons:
C1; otherwise calls startSearch('down') on the server.C2; otherwise calls startSearch('up') on the server.Search buttons are hidden during active autoscan. They are always available without admin login (unrestricted command), but a warning is shown if the tuner is locked to admin.
If CSVcreate: true is set and a CSV log file exists, two additional icon buttons are injected into the plugin panel (desktop only — hidden on touch devices):
| Button | Icon | Action |
|---|---|---|
| Mapviewer | 🌐 globe | Opens the current URDS CSV log in the URDS Map Viewer (via CORS proxy at cors-proxy.de:13128). If no CSV file is available, a warning toast is shown. |
| Validator | ✅ file-circle-check | Opens the current CSV log in the URDS Log Validator (via CORS proxy). Validates the URDS format and reports any issues. |
The scan engine runs as a setInterval loop on the server with a configurable tick rate (scanIntervalTime, default 500 ms). Each tick calls updateFrequency(), which:
currentFrequency by the appropriate step (0.01 MHz below 74 MHz, 0.1 MHz above — or 0.01 MHz in whitelist mode)sendDataToClient(currentFrequency) to retune the receivercheckStereo() or PE5PVBlog()When currentFrequency exceeds tuningUpperLimit during autoscan, the handleBandEnd() routine is called. It:
isCalibrating = truetuningLowerLimit and waits for a fresh spectrum scan (up to 15 s)SensitivityValueCalibration() again if configuredstartScan('up')In normal / blacklist / whitelist modes the scanner remembers the last tuned frequency across band-end restarts and continues from where it left off rather than returning to the lower limit, avoiding repeated scanning of already-checked frequencies within the same autoscan session.
When SensitivityCalibrationFrequenz is set, the scanner performs an automatic noise-floor measurement before every full band sweep instead of using a fixed threshold.
async function SensitivityValueCalibration() { isCalibrating = true; try { clearInterval(scanInterval); // --- Path 1: spectrum array available --- if (sigArray.length > 0) { const entry = sigArray.find( i => parseFloat(i.freq).toFixed(2) === targetFreqStr); if (entry) { Sensitivity = Math.round(parseFloat(entry.sig)) + Math.round(defaultSensitivityValue); } } // --- Path 2: physical tune + 2 s wait --- else { sendDataToClient(calibFreq); // wait until tuner reports calibration frequency while (Math.abs(parseFloat(freq) - calibFreq) >= 0.05) { await sleep(100); } await sleep(2000); // stabilise Sensitivity = Math.round(strength) + Math.round(defaultSensitivityValue); } // broadcast updated Sensitivity to all clients DataPluginsSocket.send(JSON.stringify( createMessage('broadcast', '255.255.255.255', Scan, '', Sensitivity, ScannerMode, ScanHoldTime, FMLIST_Autolog))); } finally { isCalibrating = false; } }
isCalibrating flag blocks checkStereo() from interrupting the measurement with a false detection.
Both spectrum-based modes rely on the sigArray provided by the Spectrum Graph plugin via the data_plugins WebSocket. The scanner listens for type: 'sigArray' messages and processes them in handleDataPluginsMessage():
// Find all entries above SpectrumLimiterValue const primaryFreqs = sigArray.filter(e => e.sig > SpectrumLimiterValue && Math.round(e.freq * 100) % 10 === 0 // primary 0.1 MHz grid only ); // Extend mask to ±0.1 MHz neighbours above SpectrumPlusMinusValue primaryFreqs.forEach(p => { if (p.sig >= SpectrumPlusMinusValue) { sigArray.filter(e => e.freq >= p.freq - 0.1 && e.freq <= p.freq + 0.1 ).forEach(e => extendedMask.add(e.freq)); } }); // sigArraySpectrum = everything NOT masked sigArraySpectrum = sigArray.filter(e => !extendedMask.has(e.freq) && !primaryFreqs.some(p => p.freq === e.freq) );
// freqMap2 = previous scan pass signals for current antenna sigArrayDifference = sigArraySpectrum.filter(item => { const sig = parseFloat(item.sig); if (sig < Sensitivity) return false; // below threshold if (!freqMap2.has(item.freq)) return true; // new frequency return Math.abs(sig - freqMap2.get(item.freq)) // changed by > SpectrumChangeValue; // SpectrumChangeValue });
Four baseline arrays (sigArraySave0 – sigArraySave3) store the previous spectrum pass for each of up to four antennas independently. This prevents false difference detections when the antenna is switched.
All real-time communication between server and clients uses the FM-DX-Webserver's /data_plugins WebSocket endpoint. Messages follow this envelope:
{
"type": "Scanner",
"value": {
"status": "request" | "response" | "broadcast" | "command",
"Scan": "on" | "off",
"Sensitivity": number, // internal dBf value
"ScannerMode": "normal" | ...,
"ScanHoldTime": number, // seconds
"ScanPE5PVB": boolean,
"SearchPE5PVB": boolean,
"SpectrumLimiterValue":number,
"StatusFMLIST": "off" | "on" | "auto",
"InfoFMLIST": "...", // optional status string
"AvailableConfigs": ["default", ...],
"ActiveConfig": "default" | "..."
},
"source": "clientIP",
"target": "serverIP | 255.255.255.255"
}
The plugin distinguishes between two client types based on the message.source field:
| Client type | Identified by | Auth required? |
|---|---|---|
| Legacy Scanner (browser) | Source does not contain "tef" | No — full access always granted |
| TEF Logger / Connector | Source contains "tef" (case-insensitive) | Yes — if adminPass is set in config |
All scan and config commands from TEF Logger clients are silently ignored until authentication succeeds. Search commands (Search: "up"/"down") are exempt from authentication and are always executed immediately for any client type.
On the browser side, authentication is handled by checking the webserver's page text:
isTuneAuthenticated = true, admin dropdown createdisTuneAuthenticated = trueisTunerLocked = true, tuning blocked unless adminThe HTML log is created from FilteredTemplate.html (located in the scanner plugin folder) as a header template and appended with one <tr> row per detected station. The row includes: date, time, frequency, PI code, PS name (spaces replaced with underscores), station name, city, ITU country, antenna name, polarisation, ERP, signal strength (converted to the configured unit), distance, azimuth, station ID, scan mode (A=auto / M=manual), and three action links (Stream, Map, FMLIST).
A new CSV file is created at the start of each autoscan session (format: YYYYMMDDTHHMMSS_fm_rds.csv). Each entry is one line with 40+ comma-separated fields compatible with the URDS (Universal RDS) format, including nanosecond-resolution timestamps, GPS coordinates, signal levels in dBµV, RDS fields (PI, PS, TP, TA, PTY, ECC, AF, RT), and transmitter metadata fetched live from the maps.fmdx.org API.
// CSV line structure (abbreviated)
30,{UNIXTIME},freq,{Hz},rdson,{SNRMIN},{SNRMAX},
{dateTimeNs},{GPS_LAT},{GPS_LON},{GPS_MODE},{GPS_ALT},{GPS_TIME},
{PI},1,{PS},1,{TA},{TP},{MUSIC},{PTY},{GRP},{STEREO},{DYNPTY},
{OTHERPI},,{ALLPSTEXT},{OTHERPS},,{ECC},{STATIONID},{AF},{RT},,,,,
{TX_NAME},{TX_CITY},{TX_ITU},{TX_ERP},{TX_POL},{TX_DIST},{TX_AZ},{TX_LAT},{TX_LON}
TX latitude/longitude are fetched live from maps.fmdx.org/api/?id={stationid} for each log entry. If the station ID is missing or the API call fails, the TX coordinate fields are left empty.
When FMLIST_Autolog is set to "on" or "auto", the function writeLogFMLIST() is called for each identified DX station that passes the distance and blacklist filters. The submission is a JSON POST to api.fmlist.org/fmdx.org/slog.php and includes the webserver's UUID token, OM ID, coordinates, and a log message string. A successful "OK!" response triggers a green toast notification in all connected browsers.
Three separate text files control frequency/PI filtering. All files are located in plugins/Scanner/ and are reloaded automatically when changed on disk (via fs.watchFile):
| File | Controlled by | Format | Effect |
|---|---|---|---|
blacklist.txt | EnableBlacklist | One frequency per line (e.g. 89.000) | Frequencies skipped during blacklist/spectrumBL/differenceBL scan modes |
whitelist.txt | EnableWhitelist | One frequency per line | Only these frequencies are scanned in whitelist mode |
blacklist_log.txt | Log_Blacklist | One entry per line: freq;PI, freq, or PI | Matching stations excluded from HTML and CSV log entries |
blacklist_fmlist.txt | FMLIST_Blacklist | One entry per line: freq;PI, freq, or PI | Matching stations excluded from FMLIST submissions |
Frequency matching uses a tolerance of ±0.05 MHz (floating-point safe). Whitelist matching uses exact two-decimal rounding. The combined blacklist+PI format allows suppressing a specific station on a shared frequency (e.g. 89.000;D3C3) without affecting other stations on 89.0 MHz.
When AntennaSwitch: "on" is configured and the FM-DX-Webserver has two or more antennas enabled, the scanner cycles through them at the end of every full band sweep via sendNextAntennaCommand():
function sendNextAntennaCommand() { if (enabledAntennas.length < 2) return; const ant = enabledAntennas[currentAntennaIndex]; sendCommandToClient(`Z${ant.number - 1}`); // Z0–Z3 currentAntennaIndex = (currentAntennaIndex + 1) % enabledAntennas.length; }
In auto mode (StartAutoScan: "auto"), the antenna is also restored to its pre-scan state when a user connects and autoscan stops. The current antenna at scan start is saved in saveAutoscanAntenna and restored via sendCommandToClient(`Z${saveAutoscanAntenna}`).
The four spectrum baseline arrays (sigArraySave0–3) are maintained per antenna index so that the difference scan can compare against the correct previous pass for each antenna independently.
The scanner uses fs.watchFile() (poll-based, 1-second interval) rather than fs.watch() (inotify-based) for config file monitoring. This is intentional — fs.watchFile is more reliable for config files across different filesystems and prevents rapid duplicate triggers during atomic saves by text editors.
The plugins_configs/ directory itself is also watched via fs.watch() with a 500 ms debounce. When a new scanner_X.json file appears or is deleted, availableScannerConfigs is updated and the admin dropdown in the browser is refreshed automatically. If the currently active profile file is deleted, the scanner falls back to scanner.json.
The function updateSettings() rewrites specific constant declarations directly inside scanner.js (the browser-side client file) using regex replacements, so that the browser always receives the correct feature flags (EnableBlacklist, EnableSpectrumScan, SignalStrengthUnit, AvailableScannerConfigs, ActiveScannerConfig, etc.) on the next page load. A byte-for-byte comparison prevents unnecessary disk writes.
Complete reference for plugins_configs/scanner.json. All parameters are optional — missing keys are filled with the defaults shown.
| Parameter | Default | Description |
|---|---|---|
| General | ||
Scanmode | 1 | 0 = offline, 1 = online (fmdx.org station lookup) |
Autoscan_PE5PVB_Mode | false | Use PE5PVB firmware scan engine instead of software scan |
Search_PE5PVB_Mode | false | Use PE5PVB firmware search for ◀◀ / ▶▶ buttons |
StartAutoScan | "off" | "off" / "on" / "auto" |
AntennaSwitch | "off" | "off" / "on" – cycle antennas at upper band limit |
OnlyScanHoldTime | "off" | "off" / "on" – always wait full hold time regardless of RDS |
| Sensitivity & Timing | ||
defaultSensitivityValue | 30 | Signal threshold in configured unit; or dBf/dBµV/dBm offset above noise if calibration is active |
SensitivityCalibrationFrequenz | "" | Reference frequency in MHz for dynamic noise-floor calibration (e.g. "87.3"). Empty = disabled. |
defaultScanHoldTime | 5 | Hold time in seconds: 1, 2, 3, 4, 5, 7, 10, 15, 20, 30 |
defaultScannerMode | "normal" | Startup scan mode: normal / blacklist / whitelist / spectrum / spectrumBL / difference / differenceBL |
scanIntervalTime | 500 | Milliseconds between frequency steps (max 1000) |
scanBandwith | 0 | IF bandwidth in Hz during scan (0 = auto) |
tuningLowerLimit | "" | Lower band limit in MHz; empty = use webserver value |
tuningUpperLimit | "" | Upper band limit in MHz (max 108.0); empty = use webserver value |
SignalStrengthUnit | "dBf" | "dBf" / "dBµV" / "dBm" |
| Filtering | ||
EnableBlacklist | false | Enable blacklist.txt frequency filter |
EnableWhitelist | false | Enable whitelist.txt frequency filter |
| Spectrum & Difference Scan | ||
EnableSpectrumScan | false | Enable spectrum / spectrumBL modes |
EnableDifferenceScan | false | Enable difference / differenceBL modes |
SpectrumChangeValue | 3 | Minimum signal change in dBf/dBµV for difference mode |
SpectrumLimiterValue | 50 | Upper signal limit in dBf/dBµV — strong locals excluded above this |
SpectrumPlusMinusValue | 60 | Signal level at which ±0.1 MHz neighbours of locals are also masked |
| Logging | ||
HTMLlogOnlyID | true | HTML log: only stations with known fmdx.org ID |
HTMLlogRAW | false | Also write raw (unfiltered) HTML log for every PI received |
HTMLOnlyFirstLog | false | Log each station only once per session |
CSVcreate | true | Create URDS CSV log file and enable Map Viewer / Validator buttons |
CSVcompletePS | true | Wait for complete error-free PS before writing CSV entry |
UTCtime | true | Use UTC timestamps in all log files |
Log_Blacklist | false | Exclude blacklist_log.txt entries from HTML and CSV logs |
| FMLIST Integration | ||
FMLIST_OM_ID | "" | Your FMLIST OM ID; falls back to webserver config if empty |
FMLIST_Autolog | "off" | "off" / "on" / "auto" |
FMLIST_MinDistance | 200 | Minimum station distance in km (enforced minimum: 200) |
FMLIST_MaxDistance | 2000 | Maximum station distance in km |
FMLIST_LogInterval | 60 | Re-log interval in minutes (enforced minimum: 60) |
FMLIST_CanLogServer | "" | CanLogServer address (e.g. "127.0.0.1:2000"); overrides local interval |
FMLIST_ShortServerName | "" | Short server name for log messages (max 10 chars) |
FMLIST_Blacklist | false | Exclude blacklist_fmlist.txt entries from FMLIST submissions |
| Miscellaneous | ||
BEEP_CONTROL | false | Acoustic beep signals for scan events (requires speaker npm module) |
The Spectrum Graph plugin must have rescanDelay set to 0 in its own config file (plugins_configs/SpectrumGraph.json). Without this, the spectrum array will not be refreshed after each band sweep and the scanner will repeatedly tune the same frequencies.
In spectrum and difference modes, Sensitivity must always be strictly less than SpectrumLimiterValue. If this condition is violated (e.g. after a manual sensitivity change), the server logs the error "Sensitivity must be smaller than SpectrumLimiter!" and the browser displays a red toast warning. The scan continues but will find no valid frequencies until the values are corrected.
I{value} command.ScanHoldTime is sent as K{value} to the firmware.The webserver must have a UUID token configured (config.identification.token not null). Without it, all FMLIST POST requests are blocked server-side. The UUID is set during the FM-DX-Webserver initial setup or via the settings page.
For every CSV log entry, the scanner fetches the transmitter's geographic coordinates from maps.fmdx.org/api/?id={stationid}. This is an HTTPS request with a 5-second timeout. On slow or offline connections the TX lat/lon fields will be empty but the log entry is still written. Consider setting Scanmode: 0 (offline mode) if internet connectivity is not available.
The speaker npm module requires native compilation (node-gyp). On Node.js versions above 18, compilation may fail. If acoustic control is not required, leave BEEP_CONTROL: false (default).
The browser-side script fetches the client's public IP from https://icanhazip.com at startup to populate the WebSocket message source field. If this service is unavailable, the initial WebSocket request will fail and the scanner will show an error toast. The page must be reloaded to retry.
On screens narrower than 769 px, the scanner button is placed inside a popup panel ("Bandwidth & Antennas" or "Filters") rather than the main tuning row. The Map Viewer and Validator buttons are suppressed on all touch devices (pointer: coarse media query).
| Version | Date | Key Changes |
|---|---|---|
| 4.2c | March 2026 | URDS Log Validator button; improved signal unit watcher; stabilised spectrum cooldown; TEF Logger session-based auth; dynamic config dropdown in settings panel; scanner_state.json persistence; CanLogServer integration improvements; TX coordinate lookup via maps.fmdx.org; per-antenna difference baseline arrays. |
| 4.2b | February 2026 | Multiple named config file support (scanner_X.json); live hot-reload via fs.watchFile; LoadScannerConfig WebSocket command; active config persisted across restarts. |
| 4.2a | January 2026 | plugins_api privileged command support (Admin Lock compatible); GPS WebSocket listener for dynamic QTH; OnlyScanHoldTime parameter; improved band-end wrap with calibration re-run. |
| 4.1x | Late 2025 | Difference scan mode (differenceBL); per-antenna spectrum baselines; SpectrumPlusMinusValue filter; FMLIST blacklist; log blacklist (blacklist_log.txt); CSVcompletePS option; FMLIST short server name. |
| 4.0x | Mid 2025 | Spectrum scan modes (spectrum, spectrumBL); Spectrum Graph plugin integration; dynamic ellipse gate; SensitivityCalibrationFrequenz; acoustic beep control; URDS CSV log format; Map Viewer button; HTML first-log mode. |
| 3.x | 2024–2025 | Whitelist mode; antenna switching; PE5PVB search mode; configurable band limits; dBµV / dBm unit support; mobile UI improvements; FMLIST autolog (on/auto/off); CanLogServer. |
| 2.x | 2024 | Blacklist mode; PE5PVB autoscan mode; admin-only controls; scanner controls panel (long-press); cookie persistence; blinking autoscan overlay. |
| 1.x | 2023–2024 | Initial release: basic FM band scan, RDS-based detection, HTML log, WebSocket architecture, configurable sensitivity and hold time. |
Scanner Plugin · Documentation v4.2c · Author: Highpoint · powered by PE5PVB · March 2026
github.com/Highpoint2000/webserver-scanner ·
Scanner Wizard