ShinySDR Manual: Configuration and devices

  1. Configuration directories
  2. config.py and the config object
  3. Available receiving devices
  4. Available special-purpose devices

Configuration directories

Starting the ShinySDR server requires specifying on the command line a directory containing configuration information. Such a directory can be created with example contents using the command shinysdr --create config-dir-name. The contents of a configuration directory look like this:

config.py specifies the radio hardware to use and the address of the server, among other things. It is written in Python so that unusual configurations can be accommodated, including definitions of custom drivers for special hardware.

dbs-read-only/ may contain frequency database .csv files; for information on the format of these files, see the page Frequency Databases.

config.py and the config object

As an example, here is the default config.py, without the comments:

from shinysdr.devices import AudioDevice
from shinysdr.plugins.osmosdr import OsmoSDRDevice
from shinysdr.plugins.simulate import SimulatedDevice

config.devices.add(u'osmo', OsmoSDRDevice(''))
config.devices.add(u'audio', AudioDevice(rx_device=''))
config.devices.add(u'sim', SimulatedDevice())

config.serve_web(
    http_endpoint='tcp:8100',
    ws_endpoint='tcp:8101',
    root_cap='3QLxPaLD22xaAzykSVH2eg',
    title='ShinySDR')

The only required parts are at least one device and config.serve_web(...). In addition to the usual Python builtins, there is one additional global, config, which contains all of the ShinySDR configuration methods.

Note: The config object cannot be used to modify the configuration after startup has finished.

The remainder of this section describes the methods of the config object.

Devices; config.devices

A device object corresponds to a hardware device (or multiple devices working together) providing antenna, tuner (VFO/LO), ADC, antenna rotator, etc.

Device objects are created via various plugins which implement drivers for the particular hardware; in the above example, shinysdr.plugins.osmosdr provides ShinySDR devices for gr-osmosdr. See the section Available receiving devices below for information on those drivers which are bundled with ShinySDR.

Several device objects can be merged, creating a single device object containing all of the functionality of both. This is appropriate when the corresponding hardware is in fact interconnected, but has independent interfaces; for example, a receiver with an external downconverter or upconverter, or a device which uses a separate sound card for ADC.

config.devices.add(key, device, ...)

Add a device object, making it available for use from the UI.

key is a (Unicode) string used to identify the particular device (for example, in order to save its state when the server is restarted). It can be anything.

You can specify more than one device, in which case they will be merged, as described above.

Web server and other network interfaces

config.serve_web(http_endpoint='...', ws_endpoint='...', root_cap=u'...', title=u'...')

Enable and configure the web server.

http_endpoint specifies the port (and address) to use for HTTP access. It should be a string in Twisted endpoint syntax; for a quick example, "tcp:8000" specifies port 8000, and "tcp:8000:interface=127.0.0.1" does the same while also prohibiting access from other machines.

ws_endpoint specifies the port to use for the WebSocket service used to stream data to the client. It should be identical to the http_endpoint except for using a port number exactly one greater (this restriction will be removed in the future).

root_cap is a secret string value used for restricting access to the server, or None to disable it. If set, the URL of the web interface will include this secret, so that no one can use this ShinySDR instance without having been given that particular URL.

title is a name for identifying this particular ShinySDR instance — it will be used in the titles of web pages. If not specified, the default is “ShinySDR”.

SSL configuration

If you're using ShinySDR over the Internet, I highly recommend that you use HTTPS to prevent snooping on your connection and hence unauthorized access to your ShinySDR instance.

If you already have a certificate for your domain name (lucky you!), the configuration looks like this:

config.serve_web(
    http_endpoint='ssl:8100:privateKey=key.pem:certKey=cert.pem',
    ws_endpoint='ssl:8101:privateKey=key.pem:certKey=cert.pem',
    ...)

If you don't have a certificate, you can generate a “self-signed” certificate using OpenSSL. This will not be accepted as legitimate by web browsers unless you install it on your client machine (the details of this process vary widely, and may not be possible at all), but even without that you gain protections against some attacks that plain HTTP does not have.

This advice has not been reviewed by crypto experts! It is being provided only because it is slightly better than nothing! Make your own evaluation of the risks and get a second opinion!

  1. Install the openssl command-line tool.

  2. Create a file with the following contents, and call it, say, req.conf.

    [ req ]
    default_bits = 2048
    distinguished_name = req_distinguished_name
    x509_extensions = x509_extensions
    prompt = no
    [ req_distinguished_name ]
    CN=your domain name goes here
    [ x509_extensions ]
    basicConstraints=critical,CA:FALSE
    extendedKeyUsage=critical,serverAuth

    (Note: The lines in the x509_extensions section restrict the generated certificate so that a client which has it installed does not trust it for any other purposes than authenticating the server; this limits the harm if your private key is stolen.)

  3. Run the command: openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem -config req.conf

    This will generate two new files, cert.pem and key.pem, which should be named in the endpoint specification of the ShinySDR config as described earlier. key.pem contains your server private key — keep it private! cert.pem contains the certificate; this is the file you install on the client to make it accepted as valid.

    The number after -days specifies the length of time (in days) for which the certificate is valid. When it expires, if you wish to generate a new certificate using the same key, replace the -keyout option with -key to read the key file instead of writing a new one.

Frequency databases; config.databases

A frequency database is a file containing listings of frequencies and bands of interest. For information on the file format, and using them within ShinySDR, see the page Frequency Databases.

Some frequency databases are included with ShinySDR. Your own databases may be placed in config-dir-name/dbs-read-only/, or the methods below may be used to specify additional locations.

config.databases.add_directory(pathname)

Given the pathname of a directory, add all files located in that directory with names ending in “.csv” as frequency databases.

Warning: The provided pathname, if relative, is currently relative to the working directory of the server. It is planned that this will be changed to be relative to the location of the config file. If this makes a difference, use an absolute path for now.

config.databases.add_writable_database(pathname)

Use the given pathname for a single frequency database file whose contents may be edited from the UI.

Warning: The provided pathname, if relative, is currently relative to the working directory of the server. It is planned that this will be changed to be relative to the location of the config file. If this makes a difference, use an absolute path for now.

Other features of the config object

config.persist_to_file(pathname)

Deprecated: In the future, server state will not be stored in a single file and this method will not be available. A replacement will specify a directory instead.

Use the specified pathname as the name of a file storing the state of the server (current tuning, receivers, gain, etc.) to preserve it across restarts. If config.persist_to_file is not called, the state will be saved in config-dir-name/state.json.

Additional names made by appending suffixes to pathname will be used for temporary copies and backups.

Warning: The provided pathname, if relative, is currently relative to the working directory of the server. It is planned that this will be changed to be relative to the location of the config file. If this makes a difference, use an absolute path for now.

config.set_server_audio_allowed(True[, device_name=..., sample_rate=...])

Enable sending the demodulated audio output from to an audio device on the server, rather than the client.

This is disabled by default since it may be undesirable for remote or multiuser operation.

device_name is optional, and may be used to specify the audio device to use instead of the default. It takes the same names as the GNU Radio audio sink block. [TODO: Explain or link to explanation of where to find device names.] sample_rate is optional, defaults to 44100, must be an integer, and specifies the sample rate to request.

config.features.enable('...')
config.features.disable('...')

Enable or disable the optional feature with the specified name.

Certain features of ShinySDR are notably incomplete, in which case they are disabled by default but can be enabled, or costly, in which case they are enabled by default but one might wish to disable them.

Attempting to enable or disable an unrecognized feature name is an error. Attempting to disable a feature which in a previous version of ShinySDR was disabled-by-default but is now always enabled will have no effect.

The currently defined optional features' names are:

'stereo'

Stereo audio output. Enabled by default and may be disabled (producing mono audio instead) to reduce CPU usage and network data rate.

'reboot'

Allows restarting or stopping the server by request from the client. Disabled by default.

This feature is useful if you have flaky or sometimes-unplugged RF devices. It is incomplete in that the commands do not yet live in a sensible location in the user interface, and they may not work if you have an unusual configuration (it is implemented as essentially exec python -m shinysdr.main ...).

config.reactor

ShinySDR uses the Twisted framework. config.reactor is a convenient alias for the reactor object from Twisted, which may be useful in some advanced configuration scenarios or when a plugin requires it.

config.wait_for(deferred)

Used to delay startup until some asynchronous operation has completed. deferred should be a Twisted Deferred object.

Available receiving devices

These are the device types which are available in ShinySDR or the bundled plugins.

shinysdr.devices.AudioDevice(rx_device='...', tx_device='...', name='...', sample_rate=44100, channel_mapping='IQ', usable_bandwidth=(low, high))

An system audio input (“sound card”) device.

There are two basic use cases for this device, depending on what the sound card is connected to:

rx_device is optional, and may be used to specify the audio input device to use instead of the default. (Specifying the device name is recommended, so that you can change the OS input settings without affecting ShinySDR.) It takes the same names as the GNU Radio audio sink block. [TODO: Explain or link to explanation of where to find device names.]

tx_device will be used to specify the output device when ShinySDR finally gets transmit support. Right now, it's useless.

name is optional, setting a name for the device which will be shown in the UI. It defaults to being named after rx_device.

sample_rate is optional, defaults to 44100, must be an integer, and specifies the sample rate to request.

channel_mapping is optional and defaults to 'IQ'. It specifies how the audio input device's channels should be interpreted. The value may be:

usable_bandwidth is optional and defaults to (0, sample_rate / 2). It specifies the frequency range in Hz which contains usable signal, as a tuple of lower frequency and upper frequency (both nonnegative; they will be mirrored for IQ input).

shinysdr.plugins.simulate.SimulatedDevice(name='Simulated RF')

A simulated RF spectrum, useful for testing demodulators.

Currently all of its configuration for the signals and noise level is only through the UI, not in this configuration. That may change.

name is optional, setting a name for the device which will be shown in the UI.

Example:

from shinysdr.plugins.simulate import SimulatedDevice
config.devices.add(u'sim', SimulatedDevice())
shinysdr.plugins.osmosdr.OsmoSDRDevice('...', name=u'...', profile=..., sample_rate=..., correction_ppm=0.0)

Any device supported by the gr-osmosdr library (includes RTL-SDR, HackRF, bladeRF, UHD (USRP), and files of recorded data).

The first parameter is a gr-osmosdr device string; see that page for complete information. Common uses:

name is optional, setting a name for the device which will be shown in the UI.

profile is optional, and can be used to provide more information about the characteristics of the hardware. [TODO: Values not yet documented; see shinysdr.plugins.osmosdr.OsmoSDRProfile in the ShinySDR source code for now.]

sample_rate is optional, and defaults to the nearest value to 2.4 MHz that is supported by the particular hardware.

correction_ppm is optional, and specifies a correction for the hardware oscillator frequency in parts-per-million. (This value can be changed at runtime via the UI, which is useful for calibrating against a known-frequency signal. After the first run, the value set in this configuration is ignored.)

Example:

from shinysdr.plugins.osmosdr import OsmoSDRDevice
config.devices.add(u'rtl', OsmoSDRDevice('rtl=0', correction_ppm=-52))

Available special-purpose devices

shinysdr.devices.FrequencyShift(shift)

This device is useless by itself. When merged with another device, it represents an external device performing frequency shifting (upconversion, downconversion) in the antenna line.

shift should be set to the needed change in the displayed frequency. For example, if using a 125 MHz upconverter for receiving HF using an RTL-SDR device, one should specify a shift of -125e6:

from shinysdr.plugins.osmosdr import OsmoSDRDevice
from shinysdr.devices import FrequencyShift
config.devices.add(u'rtl',
    OsmoSDRDevice('rtl=0'),
    FrequencyShift(-125e6))
shinysdr.devices.PositionedDevice(latitude, longitude)

This device is useless by itself. When merged with another device, it stores the physical location of the receiving antenna, allowing it to be displayed on the map view.

In future versions, this information may be used for such purposes as calculating antenna rotation for satellite communications.

latitude and longitude are in degrees North and East, in the WGS 84 coordinate system.

Example:

from shinysdr.plugins.osmosdr import OsmoSDRDevice
from shinysdr.devices import PositionedDevice
config.devices.add(u'rtl',
    OsmoSDRDevice('rtl=0'),
    PositionedDevice(27.988056, 86.925278))
shinysdr.plugins.hamlib.connect_to_rig(config.reactor, options=[...], port=4532)

Hamlib is a library for controlling amateur radio transceivers and antenna rotators. When Hamlib is installed, connect_to_rig from the Hamlib plugin for ShinySDR can be used to control the VFO frequency of a transceiver which is also sending upper-sideband audio to an audio device.

options should be an array of strings which are command-line options to Hamlib's rigctld (usually to specify the transceiver model and serial port to communicate on) such as ['-m', '123', '-r', '/dev/ttyUSB0']. Do not specify host or port in these options.

port is an unused TCP port number which rigctld will use. (Unfortunately, rigctld does not support automatically choosing a free port number.)

Because this involves an external process and a TCP connection, connect_to_rig completes asynchronously, returning a Twisted Deferred value instead of a Device object. Therefore, configs using connect_to_rig must delay startup and retrieve the Device from the Deferred, as shown in this example:

import shinysdr.plugins.hamlib as hamlib
d = hamlib.connect_to_rig(config.reactor,
    options=['-m', '123', '-r', '/dev/cu.SLAB_USBtoUART', '-p', '/dev/cu.SLAB_USBtoUART1', '-P', 'RTS'])
d.addCallback(lambda rig: config.devices.add('rig',
    rig,
    shinysdr.devices.AudioDevice(
        'USB Audio CODEC ', sample_rate=8000, channel_mapping=1)))
config.wait_for(d)

This configuration example also demonstrates merging in an audio device, so that ShinySDR can match the input audio signal with the the VFO frequency, allowing display of an appropriate frequency scale and use of the frequency database. SSB, baseband, or IF outputs can be used in this way (a FrequencyShift may be needed).

[TODO: Make this nicer by adding Deferred support to config.devices.add, perhaps.]

shinysdr.plugins.hamlib.connect_to_rigctld(config.reactor, host='localhost', port=4532)

Identical to connect_to_rig except that it connects to an existing rigctld server rather than starting one of its own.

shinysdr.plugins.hamlib.connect_to_rotator(config.reactor, options=[...], port=4533)
shinysdr.plugins.hamlib.connect_to_rotctld(config.reactor, host='localhost', port=4533)

For controlling an antenna rotator. Usage is identical to connect_to_rig and connect_to_rigctld, but uses Hamlib rotctld instead of rigctld.

This device can be used either merged with another device (to bundle the rotator controls with it) or as a separate non-receiving device; it works the same either way.