1What you get
This package replaces the page UberSDR serves on its WebSDR port (8901) with the classic Twente WebSDR interface, restyled by RW3PS and adapted to UberSDR's Opus sound engine.
- Waterfall with colours and automatic brightness and contrast.
- Spectrum in the PhantomSDR style, over the waterfall or above it ("spectrum + waterfall", the default for first-time visitors).
- Click-to-tune on the waterfall and spectrum, rounded to 0.5 kHz.
- Signal readouts on the radio display, as in PhantomSDR-Plus: dBm, dBµV, SNR and NF (noise floor) in a row over the S-meter.
- Digit tuning on the frequency display: mouse wheel over a digit, left click up, right click down.
- Frequency keypad: click anywhere else in the black frequency / S-meter frame (desktop page) for a number pad with a decimal point; type the frequency in kHz and press Enter (details).
- Band buttons that zoom to the band and follow the frequency; All shows the whole receiver range and stays lit while the waterfall is fully zoomed out.
- RADE V1 (FreeDV digital voice) with the RADEL and RADEU mode buttons, decoded by UberSDR's own FreeDV extension.
- The desktop page fits the browser window: it is scaled to the window's width, from 1024 px screens to 4K (add
?nofitto the address to switch this off). - A dark theme for the whole page (the Light GUI / Dark GUI switch next to Auto brightness; the original light look is the default, each visitor's choice is kept).
- A CW decoder window that opens under the Mode buttons while the mode is CW, using PhantomSDR-Plus's CW decoder in the listener's browser.
- Digital-mode decoders from PhantomSDR-Plus (FT8, FT4, FT2, JS8, WSPR, SSTV, HF FAX, NAVTEX, and an FLDIGI window with RTTY, PSK31, Olivia, MFSK, DominoEX, THOR, THROB, Hellschreiber, MT63, Packet and APRS), with a Decoder button row under the Mode buttons.
- Audio tools in the listener's browser: Weak-signal AGC, noise reduction, two autonotch filters, squelch, soft limiter, Hi-Boost, L/R output, WAV recording.
- Users list with each listener's country and city; clicking a listener tunes to their frequency and mode.
- Works with DJ0MY's CATSync (Windows): your own transceiver and the WebSDR follow each other's frequency and mode, both ways.
- Mobile page: phones are sent there automatically, with the same audio tools and an S-meter.
- Station labels on the frequency scale, from a plain text file.
- Chatbox working with UberSDR's WebSDR chat. The server keeps the last 20 messages in memory until it restarts.
UberSDR itself is not modified. The files are mounted into its container, UberSDR updates leave them alone, and uninstalling brings back UberSDR's own page.
2Requirements
- A working UberSDR made with its standard installer (Docker Compose). The package expects the usual folder
~/ubersdr, withdocker-compose.yml, a service calledubersdrand a container calledka9q_ubersdr. Other folders and names work too. - UberSDR's WebSDR server switched on, in the admin page or in
config.yaml:Check thatserver: enable_websdr: true websdr_tcp_port: 8901http://<your-address>:8901/shows UberSDR's own WebSDR page before you install. python3anddockeron the host. Both are already there on a normal UberSDR machine.- For the RADE buttons (optional): UberSDR's FreeDV extension (standard in current UberSDR) and
server.enable_cors: truein itsconfig.yaml. See section 7.
3Quick install
The package is on GitHub: github.com/sv1btl/WebSDR-emulation-for-UberSDR.
- Get the package on the UberSDR machine, for example in your home folder. With git:
git clone https://github.com/sv1btl/WebSDR-emulation-for-UberSDR.git cd WebSDR-emulation-for-UberSDROr without git, as a ZIP file:
wget https://github.com/sv1btl/WebSDR-emulation-for-UberSDR/archive/refs/heads/main.zip unzip main.zip cd WebSDR-emulation-for-UberSDR-mainOr download
websdr_sv1btl_package.zipand its.sha256file from the Releases page, check it withsha256sum -c websdr_sv1btl_package.zip.sha256, then unpack it withunzip websdr_sv1btl_package.zip && cd websdr_sv1btl_package. - Run the installer.
bash install.sh # UberSDR in ~/ubersdr bash install.sh /path/to/ubersdr # UberSDR somewhere elseIt deletes nothing. It:
- copies
websdr_sv1btl/next todocker-compose.yml; - adds 6 mount lines to the
ubersdrservice, after saving a backup asdocker-compose.yml.bak.<date>; - copies
websdr_waterfall_calibrationfrom UberSDR's config intostation.js; - asks before recreating the container. This happens once, the first time, and stops listeners' audio for about 15 seconds. Answer N to do it later with
cd ~/ubersdr && docker compose up -d ubersdr; - runs a check, where every line should say OK.
- copies
- Edit your station settings in
~/ubersdr/websdr_sv1btl/sv1btl/station.js(section 4). No restart is needed. - Open
http://<your-address>:8901/and press Ctrl+F5. Try the mobile page at/m.htmltoo.
4Your station settings
Everything that belongs to your station is in one file, websdr_sv1btl/sv1btl/station.js. Change the values, keeping the quotes and the comma at the end of each line.
| Setting | Example | What it does |
|---|---|---|
callsign | 'SV1ABC' | "It is operated by …" in the header |
location | 'Athens, GR' | "This is a WebSDR receiver, located in …" |
locator | 'KM17vx' | Maidenhead locator, linked to a map |
email | 'sv1abc@example.com' | contact address in the header |
mobileTitle | 'SV1ABC WebSDR Mobile version' | browser-tab title of the mobile page |
startKHz | 7120 | where a first-time visitor starts; returning visitors start where they left off |
startMode | 'LSB' | 'LSB', 'USB', 'AM', 'CW' or 'FM' |
waterfallCalibration | 12 | must equal websdr_waterfall_calibration in UberSDR's config (the installer copies it); sets the spectrum's dB scale |
mainServer | 'https://sv1abc.tunnel.ubersdr.org' | where visitors' browsers reach UberSDR's main web server, for RADE; the installer fills in UberSDR's public address; '' means this host on port 8080 |
mwStepKHz | 9 | medium-wave channel step of the >>> / <<< buttons in AM: 9 kHz in Europe, Africa and Asia, 10 in the Americas |
showListenerCity | true | true gives "GR,Athens" in the users list, false the country only |
otherWebSDRs | [ 'Twente', 'http://…' ], | "Switch to another WebSDR" buttons, 6 per row, as many rows as needed |
hamBands | commented out | your own band-button table; leave it out for the built-in IARU Region 1 table |
The band table
Each line is [ 'button text', lowest kHz, highest kHz, kHz the button tunes to, 'mode' ],. For example, [ '40m', 7000, 7300, 7200, 'LSB' ], suits Region 2. The range also decides which band button lights up as a listener tunes around.
The desktop page title
The browser-tab title of the desktop page comes from UberSDR itself (instance name and location in its admin page), not from station.js.
5Station labels
The labels on the frequency scale come from websdr_sv1btl/sv1btl/stationinfo.txt, one per line, as <kHz><mode> <text>:
7074usb FT8
10136usb FT8
729am ERT Athens
14100cw NCDXF beaconsThe mode is am, fm, usb, lsb or cw; clicking the label tunes there in that mode. A label whose text names a digital mode (FT8, FT4, FT2, JS8, WSPR, SSTV, FAX, NAVTEX, RTTY, PSK31, Olivia, MFSK16/32/64, DominoEX, THOR, THROB, Hell, MT63, Packet, APRS) also starts that decoder, with its own sideband and filter (desktop page); within 2 kHz of the mode's usual frequency it tunes to that frequency, "FT8<br>JT65" starts FT8, and clicking a label without a digital mode stops a running decoder. Lines starting with # are comments, and <br> in the text starts a second line. The file in the package is SV1BTL's list (time signals, European broadcasters, some Athens stations), so adapt it to your area. The page reads it again on each band or zoom change, so after editing just reload.
The labels appear only from a quarter of the way in on the zoom range (25–100 %); further out they would crowd the scale. To change that, edit e.zoom * 4 < e.maxzoom in sv1btl/ubersdr-compat.js (* 2 = from half zoom, or delete that line to show them at every zoom).
6Other things you may want to change
| What | Where |
|---|---|
| receiverbook.de registration | websdr-head.html, line 1: paste the <meta name="receiverbook-confirmation" …> line receiverbook gives you |
"Equipment" box (hidden by default) and sv1btl/setup_bw.gif | websdr-controls.html, search for equip_info |
| Background images | sv1btl/bg6.jpg (desktop), sv1btl/aluminium.jpg (mobile); replace them with files of the same name |
| Colours of the text under the waterfall: the "Chatbox" heading, the Statistics line and the UberSDR credit line (light green, links cyan, the Statistics numbers yellow) | websdr-head.html, the rules for #chatcaption, #statsbox and #ubersdr-credit |
| Favicon | sv1btl/favicon.ico, sv1btl/favicon.png |
| Browser-autoplay guide linked in the header | sv1btl/guide/guide.html |
Please keep the credit line "a layout based on RW3PS's template … modified by SV1BTL".
7How it works
UberSDR builds its WebSDR page from files in the container's /app/websdr/ folder. The package mounts five of them, plus one folder of its own, from ~/ubersdr/websdr_sv1btl/:
websdr-head.html page <head>: styles, scripts
websdr-controls.html desktop page body (RW3PS layout)
websdr-base.js page logic (Twente WebSDR, with RW3PS changes)
m.html mobile page
mobile-controls.html mobile page body
sv1btl/ everything else, served as /sv1btl/…
station.js your settings
stationinfo.txt your labels
ubersdr-compat.js glue to UberSDR and all the extras
websdr-nr.js noise-reduction engine
images, fonts, less.js, jQuery, guide/UberSDR's own websdr-sound.js (Opus audio) and websdr-waterfall.js are not replaced. ubersdr-compat.js hooks into them, which is why the check script verifies them after each UberSDR update.
Editing files safely
- Saving into the same file (nano, most GUI editors,
cat > file) makes the change live at once, with no restart. - Replacing the file (
sed -i, copying a new file over it, some vim settings) is not seen untildocker restart ka9q_ubersdr. A restart stops listeners' audio for about 15 seconds. - Files inside
sv1btl/,station.jsincluded, are always seen at once.
Browsers cache scripts, so press Ctrl+F5 after editing a .js file. To make every visitor's browser fetch a changed ubersdr-compat.js, raise the ?v=… number after it in both websdr-head.html and mobile-controls.html.
RADE (FreeDV digital voice)
The RADEL and RADEU buttons in the Mode row decode RADE V1 on the lower or upper sideband, with a 700–2200 Hz passband (1500 Hz, the width of a RADE signal; the 1.50 kHz filter button, first in the LSB and USB filter presets, lights up). Pressing the lit button again, or any other mode button, switches it off.
UberSDR decodes RADE on the server, with its FreeDV extension (freedv-ka9q). That extension only works on a session of UberSDR's own interface, not on a WebSDR (port 8901) one. So when a listener presses RADEL or RADEU, their browser:
- registers a session with UberSDR's main web server (
mainServerinstation.js); - opens an audio session there on the same frequency in LSB or USB, muted, so no audio is sent back for it;
- asks UberSDR to start the FreeDV decoder on it, and plays the decoded voice through the page's volume, Hi-Boost, notch and NR, while the normal audio is silenced.
Tuning on the page is followed. A status line under the Mode row shows "waiting for a RADE signal…" or "decoding", and the lit button turns green while voice is decoded.
Below it, a small FreeDV Reporter window lists the stations reported to FreeDV Reporter on the band you are on, as in UberSDR's own FreeDV panel: callsign, country, distance, frequency (a green dot when you are on it), message, TX and last RX. Stations transmitting now come first (red TX badge), then those that transmitted most recently; the TX column shows how long ago ("3m", "2h"). Clicking a station tunes to it. The window shows four rows at a time and scrolls for more.
On the mobile page, RADEL and RADEU are at the end of the mode list, with the same status line under the buttons (the reporter window is on the desktop page only).
- Your visitors must be able to reach
mainServer. The installer fills in the public address from UberSDR's instance settings (for example a…tunnel.ubersdr.orgaddress). Without one, the page uses port 8080 of the same host; forward that port too in that case. server.enable_cors: truemust be set in UberSDR'sconfig.yaml, because the page contacts another address. The installer warns if it is off.- Each RADE listener uses one more UberSDR session and one FreeDV decoder (
freedv_extension.max_users, 15 by default). - The decoder reads the sideband when it starts, so switching between RADEL and RADEU restarts it. UberSDR allows one restart every 2 seconds; the page waits and retries.
CW decoder
While the mode is CW (the CW button, CW narrow or wide, a keyboard key or CAT software), a window opens under the Mode buttons with the decoded text. The decoder is the one from PhantomSDR-Plus (sv1btl/cw-decoder.js): it locks on the strongest steady tone in the audio, finds the speed by itself and decodes even weak or fading signals. It shows the pitch and the speed in WPM; a line break marks a pause or a new frequency. Clear empties the window. Choosing another mode closes it.
It runs in the listener's browser, on the audio the page receives (before squelch, NR and the notch filters, so muting does not stop it). Nothing extra is asked of UberSDR: no extra session, no mainServer, no enable_cors.
- It decodes what passes the page's filter, so tune the signal into the passband (the yellow band). With several signals in a wide filter it takes the strongest; narrow the filter (CW narrow) to pick one.
- It needs a few seconds of a signal to lock on to its speed.
- Desktop page only.
Digital-mode decoders
A Decoder row under the Mode buttons starts one of PhantomSDR-Plus's decoders, in the listener's browser: FT8, FT4, FT2, JS8, WSPR, SSTV, FAX, NAVTEX, FLDIGI. The FLDIGI window's list picks RTTY, PSK31, Olivia, MFSK16·32·64, DominoEX, THOR, THROB, Hellschreiber, MT63, Packet, APRS or DWD weather RTTY (PhantomSDR-Plus 5.1.0). Its window opens above "Waterfall Settings". Pressing the lit button again, or choosing AM, FM, CW or RADE, stops it; the page then returns to the band's usual mode (LSB on 40 m, CW on 30 m…; outside the amateur bands the sideband stays) with that mode's usual filter (or the preset the listener chose for it). Tuning into another band while a decoder runs keeps the decoder's own mode and filter. Only one runs at a time. Like the CW decoder they take the received audio before squelch, NR and the notch filters, and nothing extra is asked of UberSDR.
While a decoder runs, the Mode Filters' presets on the left are replaced by Decoder Filters' presets: one button per decoder with its filter width (FT8, FT4, FT2 and JS8 2.90 kHz, WSPR 400 Hz, SSTV 1.50 kHz, FAX 1.60 kHz, NAVTEX 500 Hz; FLDIGI follows its list: RTTY 300 Hz, DWD weather 593 Hz, PSK31 200 Hz, the other modes their bandwidth plus a margin). A button sets that decoder's sideband and filter; the one in use is lit. The Mode presets come back when the decoder stops.
| Decoder | What the button does | Window |
|---|---|---|
| FT8, FT4, FT2 | USB, filter 0.1–3.0 kHz; FT8/FT4 move to the band's usual frequency if the dial is not on one | UTC, dB, DT, Hz, message, locator and distance from your locator; 15 / 7.5 / 3.75 s slots |
| JS8 | USB 0.1–3.0 kHz, the band's JS8 frequency | messages put together from JS8 frames; speed Normal/Fast/Turbo/Slow/Ultra |
| WSPR | USB 1.3–1.7 kHz, the band's WSPR frequency | spots every 2 minutes (even UTC minutes): call, locator, dBm, kHz, SNR, distance |
| SSTV | LSB below 10 MHz, USB above; 1.0–2.5 kHz | the picture (VIS auto-detect or a fixed mode), Save as PNG, a list of SSTV frequencies |
| FAX | USB 1.1–2.7 kHz | the weather chart, LPM/IOC, Invert, Save; the station list tunes 1.9 kHz below the published frequency |
| NAVTEX | USB 0.25–0.75 kHz | the messages (ZCZC … NNNN); list of NAVTEX stations |
| FLDIGI | USB, around the mode's audio centre | the window's list: Ham RTTY, PSK31, Olivia, MFSK16·32·64, DominoEX, THOR, THROB / THROBX, Hellschreiber, MT63, Packet (AX.25), APRS, DWD weather RTTY (the FLDIGI button reopens the last one). RTTY: text; ham 45.45 Bd / 170 Hz or DWD weather 50 Bd / 450 Hz, with frequency lists; Squelch slider in dB SNR (Off … +10, ham −5, weather −8) keeps noise from printing |
| PSK31 (FLDIGI list) | USB 0.9–1.1 kHz, the signal at 1000 Hz | text; calling frequencies; Auto-tune finds the strongest carrier within 0.3–2.7 kHz and moves it to 1000 Hz. A click on a PSK31 trace on the waterfall puts it in the filter. Its squelch is built in (it prints only once locked on a carrier), as in PhantomSDR-Plus |
| Olivia (FLDIGI list) | USB around 1000 Hz, the signal bandwidth + 150 Hz each side | text; mode 8/250, 16/500, 32/1000 or 16/1000 (must match the signal); Squelch slider (FEC S/N 3–15, default 4); calling frequencies (they set the mode too). A click on a trace puts it in the filter |
| MFSK16·32·64, DominoEX, THOR, THROB / THROBX, MT63 (FLDIGI list) | USB around 1500 Hz (MT63: its lowest carrier at 500 Hz), the signal bandwidth plus a margin | text; a Mode list (speed or bandwidth, must match the signal: MFSK16/32/64, DominoEX Micro–88, THOR Micro–100, THROB/THROBX 1/2/4, MT63 500/1000/2000 short or long) and its own Squelch scale as in PhantomSDR-Plus (MFSK 0–60, default 22; DominoEX and THOR 0–80, default 25; THROB 0–20 dB, default 4; MT63 0–15, default 4; far left = off); Auto-tune finds the strongest signal within 0.3–2.7 kHz and moves the dial onto it — THROB must be within ±3 Hz. A click on a trace puts it in the filter. MFSK and MT63 text comes a few seconds behind the signal |
| Hellschreiber (FLDIGI list) | USB around 1500 Hz | a picture of the received text, as on paper (no squelch, as fldigi); Feld Hell, Slow Hell, Hell X5/X9, FSK Hell 245/105, Hell 80; Reverse for FSK Hell sent the other way round; Save as PNG; Auto-tune |
| Packet (AX.25), APRS (FLDIGI list) | USB 1.3–2.1 kHz, tones 1600/1800 Hz | 300 Bd HF packet: every frame like a TNC monitor, or APRS decoded into plain text (positions, weather, messages…). Only frames with a correct checksum are printed. 1200 Bd VHF packet needs FM above 30 MHz, which this receiver does not cover; there is no APRS map |
- JS8 and WSPR show a bar under the window title: it fills over the current slot (teal while capturing, grey while waiting for the first slot) with the time to the next decode.
- FT8, FT4, FT2 and JS8 start each capture a little after the UTC slot boundary, to allow for the time the audio takes to arrive. The page learns this "time shift" from the decoded DT values (shown in the window) and keeps it in the listener's browser. The listener's PC clock must be right (within about a second).
- While a decoder runs, the frequency display shows the dial frequency (WSPR 14095.6, NAVTEX 517.5 for the 518 kHz station), also with the narrow WSPR, NAVTEX and RTTY filters. Otherwise the page shows the middle of a filter narrower than 1.4 kHz, as in CW.
- The distance column needs the station locator in
station.js(locator). - The decoder files are in
sv1btl/psdr/(PhantomSDR-Plus's own files) andsv1btl/decoders.js(the buttons and windows). The JS8 dictionary (1.9 MB) is only downloaded when JS8 is used. - Desktop page only.
SNR, dBm, dBµV and NF readouts
- The readouts sit in a row over the S-meter, in PhantomSDR-Plus's order, each in its own fixed cell and colour: dBm cyan, dBµV green, SNR yellow, NF red; the numbers themselves are a very light grey. The MUTED, SQL, ANF1, ANF2, NR and AGC lights are in a row under the S-meter scale (lit: MUTED red, SQL orange, the others green), with a fixed place at its right end that shows the digital mode in use in bold yellow (FT8, JS8, WSPR, SSTV, FAX, NAVTEX, the FLDIGI mode such as RTTY or PSK31, or RADE) and stays empty otherwise.
- SNR is measured on the waterfall, the way PhantomSDR-Plus does it: the noise is the quietest 3 kHz stretch of the visible span (the median of each stretch, the passband left out), rescanned every second; the signal is the strongest point in the passband; SNR is the difference in dB, never below 0, smoothed a little. A steady carrier (AM) no longer reads 0 dB, and pauses in speech are not needed. After a band change or zoom it takes a second or two to settle.
- dBm is the current S-meter reading, with the per-band S-meter offsets of
websdr-base.jsapplied. - dBµV is dBm + 107 (into 50 Ω).
- NF is the noise floor in dBm: dBm minus SNR, so it always agrees with the SNR figure.
- A readout shows
--while there is nothing to show (no signal reading yet; NF also until the first SNR measurement). Unlike PhantomSDR-Plus, there is no extra +5 dB display offset: the figures follow this receiver's S-meter calibration. - The grey noise marker on the S-meter bar still works the original way (the lowest reading over a few seconds), so it can differ from NF.
- The SNR measurement is in
sv1btl/ubersdr-compat.js(snrUpdate); the readouts are filled in bywebsdr-base.js. Desktop page only.
Frequency keypad
A click anywhere in the black frame with the frequency display, the magic eye and the S-meter opens a number pad over the page, so a frequency can be entered with the mouse or a finger as well as the keyboard.
- The pad has the keys 0–9, a decimal point ., ⌫ (delete the last digit), Clear, Cancel and Enter. The number is shown in the display at its top.
- Type the frequency in kHz, as in the frequency field:
7074,14074.5,198. Only digits and one decimal point are accepted (up to 9 digits); a number starting with the point gets a0in front. - Enter tunes there and closes the pad; the mode follows the band plan, as when the frequency is typed in the frequency field (LSB on 40 m, USB on 20 m…). An empty entry or 0 is ignored. Cancel, a click outside the pad or Esc closes it without tuning.
- The computer keyboard works while the pad is open: digits (also the numeric keypad),
.or,, Backspace, Delete (clear), Enter and Esc. The page's one-key shortcuts (M for mute, arrows for tuning…) are off until it closes. On a phone or tablet the pad does not bring up the on-screen keyboard. - Digit tuning stays as it was: the mouse wheel over a digit, a left click on a digit (up) and a right click (down) step that digit and do not open the pad. A click beside the digits opens the pad (it used to put a typing cursor in the frequency field). The
Gkey still empties the frequency field for typing. - The pad is at the end of
websdr-controls.html(#freqpad, functionssv1btl_freqpopup_openandsv1btl_freqpad_key); the frame that opens it is#radiodisplay. It is dark in both themes, with the dark theme's blue on Enter. Desktop page only.
Page size, look and dark theme
- Fits the window. The desktop page is scaled to the width of the browser window (0.5× to 3×), so it fills a 1024 px laptop screen as well as a Full HD, 2K or 4K monitor, and follows when the window is resized. Clicks, drags, the mouse wheel and the frequency digits stay exact. Add
?nofitto the address for the old fixed size. - Dark theme. The Light GUI / Dark GUI switch next to Auto brightness turns dark: the page header, the WebSDR Information panel, the Waterfall / Keyboard Control / Background image boxes, the control panel (buttons, lists, switches, sliders), the RADE, CW and decoder windows, the signal strength plot, the users bar and the chat box. The radio display with the S-meter and the waterfall stay as they are. Off (the original light look) is the default; each visitor's choice is kept in their browser.
- Colours. Light theme: the original teal for selected buttons, switches, radio buttons and sliders. Dark theme: blue (
#3a6db5) for all of them. Without the background image the page background is very dark blue (#0a1a3a). Links are blue (#0645ad) in the light theme and keep their light blue in the dark theme; in both they turn red under the mouse (the cyan links at the bottom of the page keep their colour). - Sliders and on/off switches have the same small 3D knob, in both themes (in the dark theme with a deeper shadow and a light edge so it stands out); slider tracks and switch grooves look slightly sunken. In the dark theme the "Switch to" buttons for other WebSDRs are raised grey buttons too, like the other dark buttons.
- Desktop page only; the mobile page keeps its own look.
What listeners' browsers contact
Your UberSDR for the page, audio and waterfall, and its main web server (mainServer) only while RADE is on. Also get.geojs.io (with ipwho.is as a fallback) once a day per visitor, to find the visitor's own country and city for the users list. Section 13 shows how to switch that off.
8After an UberSDR update
UberSDR's updater only adds missing services to docker-compose.yml and never changes the ubersdr service, so the mount lines stay. After each update, run:
bash ~/ubersdr/websdr_sv1btl/check-after-update.shIf every line says OK, everything is in place. A FAIL line says what is wrong. The usual case is missing mount lines; compose-mounts.txt in the package has them. The other is "websdr-sound.js changed shape", meaning a new UberSDR renamed something the audio extras use. The page still plays; please report it on GitHub Issues.
With another folder or container name:
UBERSDR_DIR=/path/to/ubersdr CONTAINER=my_container URL=http://localhost:8901 \
bash /path/to/ubersdr/websdr_sv1btl/check-after-update.sh9Upgrading to a newer package
Get the new version and run its install.sh again:
cd WebSDR-emulation-for-UberSDR # the folder you cloned
git pull
bash install.shWithout git, download and unpack the new ZIP or release archive and run its install.sh. The installer saves the current folder as websdr_sv1btl.bak.<date>, writes the new files in place (live at once, no restart), and keeps your station.js and stationinfo.txt. Settings that are new in the version are added to your station.js with their default value; your own values are not changed, and the installer lists what it added.
10Uninstalling
bash uninstall.sh # or: bash uninstall.sh /path/to/ubersdrThis removes the 6 mount lines (keeping docker-compose.yml.bak.<date>) and, after asking, recreates the container, so UberSDR's own WebSDR page is back. The websdr_sv1btl folder stays; delete it by hand if you want.
11Manual installation
- Copy the
websdr_sv1btlfolder next todocker-compose.yml. - Under
services:→ubersdr:→volumes:, add these lines, indented like the ones already there:- ./websdr_sv1btl/websdr-head.html:/app/websdr/websdr-head.html - ./websdr_sv1btl/websdr-controls.html:/app/websdr/websdr-controls.html - ./websdr_sv1btl/websdr-base.js:/app/websdr/websdr-base.js - ./websdr_sv1btl/m.html:/app/websdr/m.html - ./websdr_sv1btl/mobile-controls.html:/app/websdr/mobile-controls.html - ./websdr_sv1btl/sv1btl:/app/websdr/sv1btl - Set
waterfallCalibrationinsv1btl/station.jsto the value this prints:docker exec ka9q_ubersdr grep websdr_waterfall_calibration /app/config/config.yaml - Apply it with
cd ~/ubersdr && docker compose up -d ubersdr, then check it withbash ~/ubersdr/websdr_sv1btl/check-after-update.sh.
12Troubleshooting
| Problem | Cause and fix |
|---|---|
| Port 8901 shows UberSDR's own page | The mounts aren't active. Run docker compose up -d ubersdr in the UberSDR folder, then the check script. |
The check says "http://localhost:… does not answer" (older versions: many FAIL lines with HTTP 000) | UberSDR was still starting, the WebSDR server is off, or the port is published under another number. Wait a minute and run the check again; see docker port ka9q_ubersdr; for another port run URL=http://localhost:<port> bash ~/ubersdr/websdr_sv1btl/check-after-update.sh. The installation itself is fine if sections 1 and 2 say OK. |
| Port 8901 doesn't answer | enable_websdr is off, or the port isn't published or forwarded. Check config.yaml and the ports: of the ubersdr service (8901:8901). |
| Red "Station settings not loaded" line | A typo in station.js (section 4). |
| Header still says "N0CALL / Your City" | station.js wasn't edited, or the browser cached the old one. Press Ctrl+F5. |
| An HTML edit doesn't show | The file was replaced instead of saved in place. Run docker restart ka9q_ubersdr. |
| Spectrum dB numbers look wrong | waterfallCalibration doesn't match websdr_waterfall_calibration. |
| No sound until clicking | Browsers need one click before playing audio; the page shows a "start audio" button. |
| With the Dark Reader browser extension, the passband shade over the waterfall or the S-meter looks dark and solid | Dark Reader recolours their colour gradients. The pages carry <meta name="darkreader-lock"> in websdr-head.html and m.html, which makes Dark Reader leave them alone. If you still see it, the listener should reload the page; check that the line wasn't lost after editing those files. |
| A phone doesn't get the mobile page | Open /m.html?mobile once; that clears a saved "desktop version" choice. |
| "RADE unavailable: cannot reach …" | mainServer in station.js is wrong or not reachable from outside, or server.enable_cors is off (section 7). |
| RADE stays on "waiting for a RADE signal…" | Nobody is transmitting RADE there right now. Common RADE frequencies: 7177 kHz LSB, 14236 kHz USB. |
| Anything else | Open http://…:8901/?ubersdr_debug. Script errors then show in a red panel at the bottom; please include them in a report on GitHub Issues. |
13Settings for advanced users
These constants are in sv1btl/ubersdr-compat.js. After editing, raise its ?v= number (section 7).
| Constant | Default | Meaning |
|---|---|---|
WAGC_TARGET_DB, WAGC_MAX_DB, WAGC_NOISE_MAX_DB | −9, 20, 3 | Weak-signal AGC: target peak level (dBFS), most boost with a signal, most boost on an empty channel |
WAGC_PROFILE | SSB 0.4 / 0.75, AM 1 / 1 | Weak-signal AGC hang (s, only after a sudden jump) and release time constant (s), as the PhantomSDR-Plus Auto AGC; attack is immediate, level = peak of the last 100 ms |
NR_MULT, NR_FLOOR | per level | noise-reduction strength, and how far noise is turned down: −9/−14/−18/−23 dB for Low/Medium/High/Strong |
SQL_OPEN_DB, SQL_CLOSE_DB, SQL_HANG_S | 8, 4, 0.6 | squelch opens this many dB above the noise |
LIM_CEIL, LIM_KNEE | 0.7, 0.8 | soft limiter |
WF_NOISE_T, WF_SIG_T, WF_GRAIN_MAX | 0.10, 0.70, 0.17 | auto brightness: where the noise floor and strong signals sit in the colour scale (full 0–30 MHz view: noise 0.10, speckle limit 0.28; with WF_SIG_W 1.25 = how hard it pushes signals brighter, WF_C_MAX 3.5 = most contrast; the low end of the colour table is darkened so the background is near black) |
WFTYPE_DEFAULT | '2' | first-visit waterfall type: 0 spectrum, 1 waterfall, 2 spectrum + waterfall |
GEO_SERVICES | geojs.io, ipwho.is | location lookup; [] switches the location in the users list off |
SPEC_RANGE_DB | 70 | spectrum height in dB |
14Credits and licences
- WebSDR client pages and scripts, © 2007–2014 Pieter-Tjerk de Boer, PA3FWM (websdr.org).
- RW3PS's WebSDR template: layout, styles and the waterfall colour map.
- UberSDR by madpsy (github.com/madpsy/ka9q_ubersdr).
- websdr-nr.js noise reduction © 2026 joshuah.rainstar@gmail.com. MIT terms, with a caveat about commercial use in its header; read it before using the package on a paid service. SV1BTL added a residual floor.
- jQuery 3.1.1 (MIT), Less.js 3.12 (Apache 2.0), Roboto Condensed (Apache 2.0).
- DS-Digital font (frequency display) © Dusit Supasawat, "All Rights Reserved", usually free for personal use only. Replace
sv1btl/DS-DIGII.TTFwith another digital-style font of the same name if that matters for your station. - The spectrum is drawn after the style of PhantomSDR-Plus.
sv1btl/cw-decoder.js, the CW decoder, comes from PhantomSDR-Plus (github.com/sv1btl/PhantomSDR-Plus) and is under its licence, the GNU GPL v3.- The digital-mode decoders in
sv1btl/psdr/come from PhantomSDR-Plus too, and withsv1btl/decoders.jsare under the GNU GPL v3. The FT8/FT4/FT2 engine (ft8_lib.wasm, from Karlis Goba's ft8_lib, MIT) and the JS8 engine and dictionary (js8.wasm, built on ft8_lib with tables from JS8Call, andjs8_dict.bin, from JS8Call, GPL v3) keep their own terms. - Adaptation to UberSDR, audio tools, spectrum, tuning features, installer and this guide: SV1BTL, 2026.
SV1BTL's own work in the package is released under the MIT licence (the LICENSE file). The third-party parts above keep their own terms.