substation 0.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. substation-0.5.1/.github/workflows/publish.yml +48 -0
  2. substation-0.5.1/.gitignore +13 -0
  3. substation-0.5.1/INSTALL.md +269 -0
  4. substation-0.5.1/LICENSE +661 -0
  5. substation-0.5.1/PKG-INFO +913 -0
  6. substation-0.5.1/README.md +881 -0
  7. substation-0.5.1/examples/scan_demo.py +107 -0
  8. substation-0.5.1/examples/scan_osc.py +101 -0
  9. substation-0.5.1/pyproject.toml +133 -0
  10. substation-0.5.1/setup.cfg +4 -0
  11. substation-0.5.1/substation/__init__.py +46 -0
  12. substation-0.5.1/substation/__main__.py +15 -0
  13. substation-0.5.1/substation/antenna.py +371 -0
  14. substation-0.5.1/substation/cli.py +408 -0
  15. substation-0.5.1/substation/config.py +913 -0
  16. substation-0.5.1/substation/config.yaml.default +635 -0
  17. substation-0.5.1/substation/constants.py +225 -0
  18. substation-0.5.1/substation/devices/__init__.py +113 -0
  19. substation-0.5.1/substation/devices/base.py +168 -0
  20. substation-0.5.1/substation/devices/file.py +272 -0
  21. substation-0.5.1/substation/devices/hackrf.py +374 -0
  22. substation-0.5.1/substation/devices/rtlsdr.py +167 -0
  23. substation-0.5.1/substation/devices/soapysdr.py +758 -0
  24. substation-0.5.1/substation/dsp/__init__.py +3 -0
  25. substation-0.5.1/substation/dsp/demodulation.py +853 -0
  26. substation-0.5.1/substation/dsp/filters.py +348 -0
  27. substation-0.5.1/substation/dsp/noise_reduction.py +485 -0
  28. substation-0.5.1/substation/osc_sender.py +220 -0
  29. substation-0.5.1/substation/recording.py +1011 -0
  30. substation-0.5.1/substation/scanner.py +2033 -0
  31. substation-0.5.1/substation.egg-info/PKG-INFO +913 -0
  32. substation-0.5.1/substation.egg-info/SOURCES.txt +55 -0
  33. substation-0.5.1/substation.egg-info/dependency_links.txt +1 -0
  34. substation-0.5.1/substation.egg-info/entry_points.txt +3 -0
  35. substation-0.5.1/substation.egg-info/requires.txt +17 -0
  36. substation-0.5.1/substation.egg-info/scm_file_list.json +51 -0
  37. substation-0.5.1/substation.egg-info/scm_version.json +8 -0
  38. substation-0.5.1/substation.egg-info/top_level.txt +1 -0
  39. substation-0.5.1/tests/__init__.py +0 -0
  40. substation-0.5.1/tests/conftest.py +71 -0
  41. substation-0.5.1/tests/iq_generators.py +67 -0
  42. substation-0.5.1/tests/test_antenna.py +127 -0
  43. substation-0.5.1/tests/test_cli.py +90 -0
  44. substation-0.5.1/tests/test_config.py +438 -0
  45. substation-0.5.1/tests/test_config_supervisor.py +28 -0
  46. substation-0.5.1/tests/test_constants.py +36 -0
  47. substation-0.5.1/tests/test_demodulation.py +819 -0
  48. substation-0.5.1/tests/test_devices.py +193 -0
  49. substation-0.5.1/tests/test_events.py +179 -0
  50. substation-0.5.1/tests/test_filters.py +215 -0
  51. substation-0.5.1/tests/test_noise_reduction.py +339 -0
  52. substation-0.5.1/tests/test_osc_sender.py +297 -0
  53. substation-0.5.1/tests/test_recording.py +507 -0
  54. substation-0.5.1/tests/test_scanner_channels.py +189 -0
  55. substation-0.5.1/tests/test_scanner_detection.py +371 -0
  56. substation-0.5.1/tests/test_scanner_transitions.py +131 -0
  57. substation-0.5.1/tests/test_soapysdr.py +449 -0
@@ -0,0 +1,48 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes a release whenever a version tag is pushed. Versioning is driven by
4
+ # git tags via setuptools-scm, so `git tag v0.6.0 && git push --tags` is the
5
+ # whole release flow. Uses PyPI Trusted Publishing (OIDC) — no API token is
6
+ # stored. The build runs in isolation and only needs the build backend
7
+ # (setuptools + setuptools-scm), so it never installs the RTL-SDR / HackRF /
8
+ # SoapySDR runtime dependencies. Action versions matter: older majors run on a
9
+ # retired Node runtime and GitHub fails the job (same pattern as Subsequence).
10
+
11
+ on:
12
+ push:
13
+ tags:
14
+ - "v*"
15
+
16
+ jobs:
17
+ build:
18
+ name: Build distributions
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v7
22
+ with:
23
+ fetch-depth: 0 # full history + tags so setuptools-scm can derive the version
24
+ - uses: actions/setup-python@v6
25
+ with:
26
+ python-version: "3.12"
27
+ - name: Build sdist and wheel
28
+ run: pipx run build
29
+ - name: Check metadata
30
+ run: pipx run twine check dist/*
31
+ - uses: actions/upload-artifact@v7
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+
36
+ publish:
37
+ name: Publish to PyPI
38
+ needs: build
39
+ runs-on: ubuntu-latest
40
+ environment: pypi
41
+ permissions:
42
+ id-token: write # required for Trusted Publishing
43
+ steps:
44
+ - uses: actions/download-artifact@v8
45
+ with:
46
+ name: dist
47
+ path: dist/
48
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ .vscode/
3
+ .pytest_cache/audio/
4
+ .mypy_cache/
5
+ config.yaml
6
+ *.egg-info/
7
+ audio/
8
+ examples/audio/
9
+ .claude/
10
+ .vs-code/
11
+ CLAUDE.local.md
12
+ AGENT-INSTRUCTIONS.md
13
+ README-AGENTS.md
@@ -0,0 +1,269 @@
1
+ # Substation Installation Guide
2
+
3
+ Platform-specific setup for SDR drivers, system dependencies, and the Python environment. See [README.md](README.md) for usage, configuration, and features.
4
+
5
+ Tested on:
6
+ - Debian 12 / Ubuntu 24.04 / Raspberry Pi OS (Bookworm)
7
+ - Fedora 43 Server (x86_64)
8
+
9
+ ---
10
+
11
+ ## 1. RTL-SDR Blog V4 Driver
12
+
13
+ The RTL-SDR Blog V4 requires the rtlsdrblog fork — the standard osmocom drivers are missing required symbols (e.g. `rtlsdr_set_dithering`).
14
+
15
+ ### Debian / Ubuntu / Raspberry Pi OS
16
+
17
+ ```bash
18
+ # Remove any existing RTL-SDR packages to avoid conflicts
19
+ sudo apt purge ^librtlsdr
20
+ sudo rm -rvf /usr/lib/librtlsdr* /usr/include/rtl-sdr* \
21
+ /usr/local/lib/librtlsdr* /usr/local/include/rtl-sdr* \
22
+ /usr/local/include/rtl_* /usr/local/bin/rtl_*
23
+
24
+ # Install build tools
25
+ sudo apt update
26
+ sudo apt install -y libusb-1.0-0-dev git cmake pkg-config build-essential
27
+
28
+ # Clone and build the RTL-SDR Blog fork
29
+ git clone https://github.com/rtlsdrblog/rtl-sdr-blog.git rtl-sdr
30
+ cd rtl-sdr
31
+ mkdir build && cd build
32
+ cmake ../ -DINSTALL_UDEV_RULES=ON
33
+ make
34
+ sudo make install
35
+ sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
36
+ sudo ldconfig
37
+
38
+ # Blacklist the default DVB-T driver so it doesn't claim the SDR as a TV tuner
39
+ echo 'blacklist dvb_usb_rtl28xxu' | sudo tee --append /etc/modprobe.d/blacklist-dvb_usb_rtl28xxu.conf
40
+
41
+ cd ../..
42
+ ```
43
+
44
+ ### Fedora
45
+
46
+ ```bash
47
+ # Remove any existing RTL-SDR packages
48
+ sudo dnf remove 'rtl-sdr*' 'librtlsdr*'
49
+ sudo rm -rvf /usr/lib/librtlsdr* /usr/lib64/librtlsdr* \
50
+ /usr/include/rtl-sdr* /usr/local/lib/librtlsdr* \
51
+ /usr/local/lib64/librtlsdr* /usr/local/include/rtl-sdr* \
52
+ /usr/local/include/rtl_* /usr/local/bin/rtl_*
53
+
54
+ # Install build tools
55
+ sudo dnf group install -y development-tools
56
+ sudo dnf install -y gcc gcc-c++ libusb1-devel git cmake pkgconf
57
+
58
+ # Clone and build the RTL-SDR Blog fork
59
+ git clone https://github.com/rtlsdrblog/rtl-sdr-blog.git rtl-sdr
60
+ cd rtl-sdr
61
+ mkdir build && cd build
62
+ cmake ../ -DINSTALL_UDEV_RULES=ON
63
+ make
64
+ sudo make install
65
+ sudo cp ../rtl-sdr.rules /etc/udev/rules.d/
66
+ sudo ldconfig
67
+
68
+ # Blacklist the default DVB-T driver
69
+ echo 'blacklist dvb_usb_rtl28xxu' | sudo tee --append /etc/modprobe.d/blacklist-dvb_usb_rtl28xxu.conf
70
+
71
+ cd ../..
72
+ ```
73
+
74
+ ---
75
+
76
+ ## 2. System Optimisation (USB Buffering)
77
+
78
+ High sample rates (e.g. HackRF at 20 MHz) require more USB buffer memory than the kernel default.
79
+
80
+ ### Debian / Ubuntu / Raspberry Pi OS
81
+
82
+ ```bash
83
+ # Edit the kernel command line
84
+ sudo nano /boot/firmware/cmdline.txt
85
+
86
+ # Add the following to the end of the existing (single) line:
87
+ usbcore.usbfs_memory_mb=1000
88
+
89
+ # Reboot for the change to take effect
90
+ sudo reboot
91
+ ```
92
+
93
+ ### Fedora
94
+
95
+ ```bash
96
+ # Add the kernel parameter via grubby (Fedora's preferred method)
97
+ sudo grubby --update-kernel=ALL --args="usbcore.usbfs_memory_mb=1000"
98
+
99
+ # Reboot for the change to take effect
100
+ sudo reboot
101
+
102
+ # After reboot, verify the parameter is active
103
+ cat /proc/cmdline | grep usbfs_memory_mb
104
+ ```
105
+
106
+ ---
107
+
108
+ ## 3. OS Dependencies
109
+
110
+ ### Debian / Ubuntu / Raspberry Pi OS
111
+
112
+ ```bash
113
+ # Audio and maths libraries
114
+ sudo apt install -y libsndfile1 libsndfile1-dev python3-setuptools python3-dev
115
+
116
+ # HackRF drivers and utilities
117
+ sudo apt install -y libhackrf-dev hackrf
118
+ ```
119
+
120
+ ### Fedora
121
+
122
+ ```bash
123
+ # Audio and maths libraries
124
+ sudo dnf install -y libsndfile libsndfile-devel python3-setuptools python3-devel
125
+
126
+ # HackRF drivers and utilities
127
+ sudo dnf install -y hackrf hackrf-devel
128
+ ```
129
+
130
+ ---
131
+
132
+ ## 4. SoapySDR + AirSpy Support
133
+
134
+ Required only if using AirSpy R2, AirSpy HF+ Discovery, or other SoapySDR-compatible devices.
135
+
136
+ ### Debian / Ubuntu / Raspberry Pi OS
137
+
138
+ ```bash
139
+ # Install SoapySDR core and Python bindings
140
+ sudo apt install -y soapysdr-tools python3-soapysdr
141
+
142
+ # Install device-specific SoapySDR modules (install only what you need)
143
+ sudo apt install -y soapysdr-module-airspy # AirSpy R2
144
+ sudo apt install -y soapysdr-module-airspyhf # AirSpy HF+ Discovery
145
+
146
+ # If soapysdr-module-airspyhf is not available in your distro's repos
147
+ # (e.g., Raspberry Pi OS), build from source instead:
148
+ sudo apt install -y libairspyhf-dev libsoapysdr-dev cmake
149
+ git clone https://github.com/pothosware/SoapyAirspyHF.git
150
+ cd SoapyAirspyHF
151
+ mkdir build && cd build
152
+ cmake ..
153
+ make
154
+ sudo make install
155
+ cd ../..
156
+
157
+ # Verify SoapySDR can see connected devices
158
+ SoapySDRUtil --find
159
+ ```
160
+
161
+ ### Fedora
162
+
163
+ ```bash
164
+ # Install SoapySDR core and Python bindings
165
+ sudo dnf install -y SoapySDR SoapySDR-devel python3-SoapySDR
166
+
167
+ # Install device modules from the Fedora repos
168
+ sudo dnf install -y soapy-rtlsdr # RTL-SDR via SoapySDR
169
+ sudo dnf install -y soapy-airspyhf # AirSpy HF+ Discovery
170
+
171
+ # AirSpy R2 module is not in the Fedora repos — build from source:
172
+ sudo dnf install -y airspyone_host-devel SoapySDR-devel cmake
173
+ git clone https://github.com/pothosware/SoapyAirspy.git
174
+ cd SoapyAirspy
175
+ mkdir build && cd build
176
+ cmake ..
177
+ make
178
+ sudo make install
179
+ cd ../..
180
+
181
+ # Verify SoapySDR can see connected devices
182
+ SoapySDRUtil --find
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 5. Python Environment
188
+
189
+ The same for all platforms.
190
+
191
+ ```bash
192
+ # If using SoapySDR devices (AirSpy, etc.), the venv MUST inherit system
193
+ # packages so it can access the system-installed python3-soapysdr bindings:
194
+ python3 -m venv --system-site-packages venv
195
+
196
+ # If you already have an existing venv, enable system packages on it:
197
+ # sed -i 's/include-system-site-packages = false/include-system-site-packages = true/' /path/to/venv/pyvenv.cfg
198
+
199
+ # If only using RTL-SDR or HackRF (no SoapySDR), a standard venv is fine:
200
+ # python3 -m venv venv
201
+
202
+ source venv/bin/activate
203
+ ```
204
+
205
+ Then install substation. Most users want one of the first two:
206
+
207
+ ```bash
208
+ # From PyPI (stable release)
209
+ pip install substation
210
+
211
+ # From GitHub (latest, no release needed)
212
+ pip install git+https://github.com/simonholliday/substation.git
213
+
214
+ # From a local clone, editable — for development
215
+ pip install -e .
216
+ ```
217
+
218
+ The default configuration ships inside the package, so no clone is needed. After installing, create an editable starter config in your working directory:
219
+
220
+ ```bash
221
+ substation --init # writes ./config.yaml (the fully-commented defaults)
222
+ ```
223
+
224
+ ### Optional extras
225
+
226
+ ```bash
227
+ # OSC event forwarding (for MIDI sequencer, sampler, etc.)
228
+ pip install "substation[osc]"
229
+ ```
230
+
231
+ **Supervisor dashboard** (real-time WebSocket state broadcast) is a separate package installed from GitHub — it is *not* a PyPI extra, because PyPI does not permit direct-URL dependencies:
232
+
233
+ ```bash
234
+ pip install git+https://github.com/simonholliday/supervisor.git
235
+ ```
236
+
237
+ While the supervisor repository is private, this install uses SSH (`git+ssh://git@github.com/...`) and requires a GitHub SSH key on the machine — see [GitHub's SSH setup guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh). The scanner runs normally with the dashboard disabled if the package isn't present.
238
+
239
+ After installing supervisor, enable the dashboard in `config.yaml`:
240
+
241
+ ```yaml
242
+ supervisor:
243
+ enabled: true
244
+ port: 9004 # default
245
+ ```
246
+
247
+ The scanner logs `Supervisor dashboard server started on ws://0.0.0.0:9004` when it starts. If the extra is not installed, a warning is logged and the scan proceeds without the dashboard.
248
+
249
+ ---
250
+
251
+ ## 6. Verification
252
+
253
+ ```bash
254
+ # List available bands from the default configuration
255
+ substation --list-bands
256
+
257
+ # Or using the Python module directly
258
+ python3 -m substation --list-bands
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Platform-Specific Notes
264
+
265
+ ### Fedora
266
+
267
+ - **SELinux**: Fedora enables SELinux in enforcing mode by default. If USB devices aren't accessible even after udev rules are in place, check for denials with `sudo ausearch -m avc -ts recent`. Typically the udev rules are sufficient.
268
+ - **Firewalld**: If using OSC event forwarding or other network features, you may need to open ports: `sudo firewall-cmd --add-port=9000/udp --permanent && sudo firewall-cmd --reload`.
269
+ - **lib vs lib64**: Fedora uses `/usr/lib64` for 64-bit libraries. The `ldconfig` step after building RTL-SDR should handle this, but if you get "library not found" errors, check that `/usr/local/lib64` is listed in `/etc/ld.so.conf.d/` and re-run `sudo ldconfig`.