Merge branch 'pr-284' into dev

# Conflicts:
#	README.md
This commit is contained in:
Lloyd
2026-06-09 08:55:34 +01:00
17 changed files with 339 additions and 265 deletions
+339 -265
View File
@@ -1,210 +1,227 @@
# pyMC_repeater
# pyMC Repeater
Repeater Daemon in Python using the `pymc_core` Lib.
Lightweight Python MeshCore repeater daemon built on `pymc_core`.
---
pyMC Repeater is designed to run continuously on low-power Linux hardware such
as Raspberry Pi-class devices, Proxmox LXC containers, and network-attached
radio modems. It forwards LoRa packets, exposes a web dashboard, and provides
configuration tools for radio setup, policy management, monitoring, and
integrations.
I started **pyMC_core** as a way to really get under the skin of **MeshCore** — to see how it ticked and why it behaved the way it did.
After a few late nights of tinkering, testing, and head-scratching, I shared what Id learned with the community.
The response was honestly overwhelming — loads of encouragement, great feedback, and a few people asking if I could spin it into a lightweight **repeater daemon** that would run happily on low-power, Pi-class hardware.
## Contents
That challenge shaped much of what followed:
- I went with a lightweight HTTP server (**CherryPy**) instead of a full-fat framework.
- I stuck with simple polling over WebSockets — its more reliable, has fewer dependencies, and is far less resource hungry.
- I kept the architecture focused on being **clear, modular, and hackable** rather than chasing performance numbers.
Theres still plenty of room for this project to grow and improve — but youve got to start somewhere!
My hope is that **pyMC_repeater** serves as a solid, approachable foundation that others can learn from, build on, and maybe even have a bit of fun with along the way.
> **Id love to see these repeaters out in the wild — actually running in real networks and production setups.**
> My own testing so far has been in a very synthetic environment with little to no other users in my area,
> so feedback from real-world deployments would be incredibly valuable!
---
- [Overview](#overview)
- [Screenshots](#screenshots)
- [Supported Hardware](#supported-hardware)
- [Installation](#installation)
- [Configuration](#configuration)
- [Policy Engine](#policy-engine)
- [Upgrading](#upgrading)
- [Proxmox LXC Installation](#proxmox-lxc-installation)
- [Docker Compose](#docker-compose)
- [Contributing](#contributing)
- [Support](#support)
## Overview
The repeater daemon runs continuously as a background process, forwarding LoRa packets using `pymc_core`'s Dispatcher and packet routing.
The repeater daemon runs as a background service and forwards LoRa packets using
the `pymc_core` dispatcher and routing stack. The project favors a simple,
hackable architecture:
---
- CherryPy provides a lightweight HTTP server for the web UI and API.
- The web interface supports setup, monitoring, logs, configuration, and updates.
- Packet routing, policy checks, storage, sensors, GPS, MQTT, and optional
pyMC_Glass integration are kept in modular components.
- Hardware support covers direct SPI radios, CH341 USB-to-SPI adapters,
pyMC TCP/USB modem firmware, and KISS serial modems.
## Supported Hardware (Out of the Box)
The repeater supports two radio backends:
- **SX1262 (SPI)** — Direct connection to LoRa modules (HATs, etc.) as listed below.
- **KISS modem** — Serial TNC using the KISS protocol. Set `radio_type: kiss` in config and configure `kiss.port` and `kiss.baud_rate`.
> [!CAUTION]
> ## Compatibility
>
> ### Supported Radio Interfaces
>
> | Interface | Supported |
> |------------|------------|
> | Native SPI radio SX1262 | ✅ Yes |
> | USBSPI bridge (CH341F) | ✅ Yes |
> | UART-based HATs | ❌ No |
> | SX1302 concentrator boards | ❌ No |
> | SX1303 concentrator boards | ❌ No |
>
> This project supports **single-radio SPI transceivers only**, either:
> - Connected directly via SPI
> - Connected via a CH341F USBSPI adapter
> - Connected using hardware that supports Meshcore Kiss Modem firmware
The following hardware is currently supported out-of-the-box:
HackerGadgets uConsole
Hardware: uConsole RTL-SDR/LoRa/GPS/RTC/USB Hub
Platform: Clockwork uConsole (Raspberry Pi CM4/CM5)
Frequency: 433/915MHz (configurable)
TX Power: Up to 22dBm
SPI Bus: SPI1
GPIO Pins: CS=-1, Reset=25, Busy=24, IRQ=26
Additional Setup: Requires SPI1 overlay and GPS/RTC configuration (see uConsole setup guide)
Frequency Labs meshadv-mini
Hardware: FrequencyLabs meshadv-mini Hat
Platform: Raspberry Pi (or compatible single-board computer)
Frequency: 868MHz (EU) or 915MHz (US)
TX Power: Up to 22dBm
SPI Bus: SPI0
GPIO Pins: CS=8, Reset=24, Busy=20, IRQ=16
Frequency Labs meshadv
Hardware: FrequencyLabs meshadv-mini Hat
Platform: Raspberry Pi (or compatible single-board computer)
Frequency: 868MHz (EU) or 915MHz (US)
TX Power: Up to 22dBm
SPI Bus: SPI0
GPIO Pins: CS=21, Reset=18, Busy=20, IRQ=16, TXEN=13, RXEN=12, use_dio3_tcxo=True
HT-RA62 module
Hardware: Heltec HT-RA62 LoRa module
Platform: Raspberry Pi (or compatible single-board computer)
Frequency: 868MHz (EU) or 915MHz (US)
TX Power: Up to 22dBm
SPI Bus: SPI0
GPIO Pins: CS=21, Reset=18, Busy=20, IRQ=16, use_dio3_tcxo=True, use_dio2_rf=True
Zindello Industries UltraPeater
Hardware: EBYTE E22/P 1W Module
Platform: Luckfox Pico Ultra/W (NOT A PI DEVICE)
Frequency: 868MHz (EU) or 915Mhz (US/AU)
Tx Power: Up to 30dBm
SPI Bus: SPI0
GPIO Pins: CS=16, Reset=22, Busy=11, IRQ=10, TXEN=20 , RXEN=21 (E22 Only), EN=21 (E22P Only), TXLED=9, RXLED=1, use_dio2_rf=False, use_dio3_tcxo=True, use_gpiod_backend=True, gpio_chip=1
Waveshare LoRaWAN/GNSS HAT (SPI Version Only)
NO LONGER RECOMMENDED
Note: May experience issues on "Narrow" (62.5KHz) settings due to a lack of TCXO
Hardware: Waveshare SX1262 LoRa HAT (SPI interface - UART version not supported)
Platform: Raspberry Pi (or compatible single-board computer)
Frequency: 868MHz (EU) or 915MHz (US)
TX Power: Up to 22dBm
SPI Bus: SPI0
GPIO Pins: CS=21, Reset=18, Busy=20, IRQ=16
Note: Only the SPI version is supported. The UART version will not work.
...
Real-world deployment feedback is especially welcome. Dense networks, unusual
hardware, and production-style installations are the best way to find the rough
edges and make the repeater better for everyone.
## Screenshots
### Dashboard
![Dashboard](docs/dashboard.png)
*Real-time monitoring dashboard showing packet statistics, neighbor discovery, and system status*
Real-time packet statistics, neighbor discovery, and system status.
### Statistics
![Statistics](docs/stats.png)
*statistics and performance metrics*
Historical statistics and performance metrics.
## Supported Hardware
pyMC Repeater supports these radio backends:
- **SX1262 over Linux SPI**: set `radio_type: sx1262`
- **SX1262 over CH341 USB-to-SPI**: set `radio_type: sx1262_ch341`
- **pyMC TCP modem**: set `radio_type: pymc_tcp`
- **pyMC USB-CDC modem**: set `radio_type: pymc_usb`
- **KISS serial modem**: set `radio_type: kiss`
- **No radio hardware**: set `radio_type: null` for setup, testing, or API-only work
> [!CAUTION]
> **Compatibility**
>
> This project targets single-radio SX1262-class transceivers and supported
> modem integrations. It does not support UART-only HATs or SX1302/SX1303
> concentrator boards.
| Interface | Status |
|-----------|--------|
| Native SX1262 SPI radio | Supported |
| CH341 USB-to-SPI bridge | Supported |
| pyMC TCP modem | Supported |
| pyMC USB-CDC modem | Supported |
| KISS serial modem | Supported |
| UART-only HATs | Not supported |
| SX1302/SX1303 concentrator boards | Not supported |
The following devices have out-of-the-box presets or known support:
| Device Name | Platform | TX Power | Connection | Radio Module | Link |
|-------------|----------|----------|:----------:|:------------:|------|
| HackerGadgets uConsole | uConsole / Raspberry Pi CM | Up to 22 dBm | SPI | SX1262-class | [View](https://www.clockworkpi.com/home-uconsole) |
| Zindello Industries UltraPeater | Luckfox | Up to 30 dBm | SPI | E22, E22P | [View](https://zindello.com.au/ultrapeater/) |
| MeshSmith PiMesh-1W | Raspberry Pi | Up to 30 dBm | SPI | E22P | [View](https://meshsmith.net/products/pimesh-1w) |
| MeshSmith EtherMesh-1W | Network | Up to 30 dBm | TCP | E22P | [View](https://meshsmith.net/products/ethermesh-1w) |
| Frequency Labs meshadv-mini | Raspberry Pi | Up to 30 dBm | SPI | E22 | [View](https://www.etsy.com/shop/FrequencyLabs) |
| Frequency Labs meshadv | Raspberry Pi | Up to 30 dBm | SPI | E22 | [View](https://www.etsy.com/shop/FrequencyLabs) |
Always confirm pin mappings, antenna setup, regional frequency rules, and TX
power limits before transmitting.
## Installation
Before You Begin
### Install Git
Make sure SPI is switched on using raspi-config:
```bash
sudo raspi-config
```
1. Go to Interface Options
2. Select SPI
3. Choose Enable
4. Reboot when prompted:
```bash
sudo reboot
```
After reboot, you can confirm SPI is active:
```bash
ls /dev/spi*
```
You should see something like:
```bash
/dev/spidev0.0 /dev/spidev0.1
```
**Install Git (if not already installed):**
```bash
sudo apt update
sudo apt install git -y
```
**Clone the Repository:**
### Clone The Repository
```bash
git clone https://github.com/rightup/pyMC_Repeater.git
cd pyMC_Repeater
```
**Quick Install:**
### Quick Install
```bash
sudo ./manage.sh
sudo bash ./manage.sh install
```
This script will:
- Create a dedicated `repeater` service user with hardware access
- Install files to `/opt/pymc_repeater`
- Create configuration directory at `/etc/pymc_repeater`
- Setup log directory at `/var/log/pymc_repeater`
- **Launch interactive radio & hardware configuration wizard**
- Install and enable systemd service
The installer will:
- Create a dedicated `repeater` service user with hardware access
- Install application files to `/opt/pymc_repeater`
- Create the configuration directory at `/etc/pymc_repeater`
- Create the log directory at `/var/log/pymc_repeater`
- Launch the interactive radio and hardware setup wizard
- Install and enable the `pymc-repeater` systemd service
After installation:
**After Installation:**
```bash
# View live logs
sudo journalctl -u pymc-repeater -f
```
# Access web dashboard
Open the web dashboard at:
```text
http://<repeater-ip>:8000
```
**Development Install:**
### Development Install
```bash
pip install -e .
```
For development tools:
```bash
pip install -e ".[dev]"
```
## Configuration
The configuration file is created and configured during installation at:
```
The main configuration file is created during installation:
```text
/etc/pymc_repeater/config.yaml
```
### Optional pyMC_Glass integration
The repeater now supports an additive `glass` config section for central control-plane integration.
When enabled, it sends periodic `/inform` payloads to pyMC_Glass, receives queued commands, and reports command results on the next inform cycle.
### Setup Wizard
The web-based setup flow guides you through repeater identity, hardware
selection, radio presets, and login setup.
#### Start Setup
![Onboarding Step 1](docs/onboarding1.png)
#### Repeater Name
![Onboarding Step 2](docs/onboarding2.png)
#### Hardware Type
![Onboarding Step 3](docs/onboarding3.png)
#### Choose A Preset
![Onboarding Step 5](docs/onboarding5.png)
#### TX Power
TX power defaults to 14 dBm and can be changed later.
![TX Power Notice](docs/onboarding-tx-disclaimer.png)
#### Set A Password
![Onboarding Step 6](docs/onboarding6.png)
#### Update TX settings
![Radio Configuration](docs/config.png)
#### Run CAD Calibration
![CAD Calibration](docs/CAD-Tool.png)
### Reconfigure Radio And Hardware
To reconfigure radio and hardware settings after installation:
```bash
sudo bash setup-radio-config.sh /etc/pymc_repeater
```
You can also launch the management menu:
```bash
sudo ./manage.sh
sudo systemctl restart pymc-repeater
```
### Optional pyMC_Glass Integration
pyMC Repeater supports an optional `glass` configuration section for
pyMC_Glass control-plane integration. When enabled, the repeater sends periodic
`/inform` payloads to pyMC_Glass, receives queued commands, and reports command
results on the next inform cycle.
Minimal example:
```yaml
glass:
enabled: true
@@ -212,77 +229,93 @@ glass:
inform_interval_seconds: 30
```
To reconfigure radio and hardware settings after installation, run:
```bash
sudo bash setup-radio-config.sh /etc/pymc_repeater
# or
sudo ./manage.sh
# then restart the service
sudo systemctl restart pymc-repeater
## Policy Engine
Use the policy engine to create Fortinet-style packet management rules from the
web interface.
![Policy](docs/config-policy.png)
### Example: Drop Channel packets over two hops
![Policy Example](docs/policy-example1.png)
```
## Upgrading
To upgrade an existing installation to the latest version:
### Web Interface
The web interface can upgrade an installation or switch branches.
> [!NOTE]
> Docker installs cannot be upgraded or branch-switched from the web interface.
> Update the container image instead.
![Upgrade](docs/webui-upgrade.png)
### CLI
```bash
# Navigate to your pyMC_Repeater directory
cd pyMC_Repeater
# Run the upgrade script
sudo ./manage.sh
sudo bash ./manage.sh upgrade
```
The upgrade script will:
- Pull the latest code from the main branch
- Update all application files
- Update application files
- Upgrade Python dependencies if needed
- Restart the service automatically
- Preserve your existing configuration
- Preserve the existing configuration
---
## Proxmox LXC Installation
## Installing on Proxmox (LXC Container)
pyMC Repeater can run inside a Proxmox LXC container using a **CH341 USB-to-SPI adapter** for radio communication. This is ideal for headless, always-on deployments without dedicating a full Raspberry Pi.
pyMC Repeater can run inside a Proxmox LXC container using a CH341 USB-to-SPI
adapter or a TCP modem. This is useful for headless, always-on deployments
without dedicating a full Raspberry Pi.
### Requirements
- **Proxmox VE 7.x or 8.x** host
- **CH341 USB-to-SPI adapter** (VID `1a86`, PID `5512`) connected to the Proxmox host
- **SX1262-based LoRa module** (e.g. Ebyte E22-900M30S) wired to the CH341 adapter
- Internet connectivity for the container
Software:
- Proxmox VE 7.x or 8.x host
- Internet access for the container
Hardware, choose one:
- CH341 USB-to-SPI adapter with VID `1a86` and PID `5512`, connected to the
Proxmox host and wired to an SX1262-based LoRa module such as an Ebyte
E22-900M30S
- TCP modem, such as MeshSmith EtherMesh
### One-Line Install
Run this on the **Proxmox host** (not inside a container):
Run this command on the Proxmox host, not inside a container:
```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/rightup/pyMC_Repeater/dev/scripts/proxmox-install.sh)"
bash -c "$(curl -fsSL https://raw.githubusercontent.com/rightup/pyMC_Repeater/main/scripts/proxmox-install.sh)"
```
> **Tip:** Replace `dev` in the URL with whichever branch you want to install.
Replace `main` in the URL with another branch name if needed.
The installer will interactively prompt you for container settings (hostname, RAM, disk, bridge, etc.) and then:
The installer will prompt for container settings and then:
1. Download a Debian 12 LXC template
2. Create a **privileged** container with USB passthrough
3. Install a host-side udev rule for the CH341 device
4. Clone the repository and pre-seed the config with CH341 GPIO pin mappings
5. Run `manage.sh install` inside the container
6. Display the dashboard URL when finished
1. Download a Debian 12 LXC template.
2. Create a privileged container with USB passthrough.
3. Install a host-side udev rule for the CH341 device.
4. Clone the repository and pre-seed CH341 GPIO pin mappings.
5. Run `manage.sh install` inside the container.
6. Display the dashboard URL.
### Default Container Settings
| Setting | Default |
|-----------|-----------------|
| Hostname | `pymc-repeater` |
| RAM | 1024 MB |
| Disk | 4 GB |
| CPU cores | 2 |
| Bridge | `vmbr0` |
| Storage | `local-lvm` |
| Password | `pymc` |
| Setting | Default |
|---------|---------|
| Hostname | `pymc-repeater` |
| RAM | 1024 MB |
| Disk | 4 GB |
| CPU cores | 2 |
| Bridge | `vmbr0` |
| Storage | `local-lvm` |
| Password | `pymc` |
### After Installation
@@ -293,108 +326,145 @@ pct enter <CTID>
# View service logs
journalctl -u pymc-repeater -f
# Access web dashboard
http://<container-ip>:8000
# Manage the repeater
cd /opt/pymc_repeater && bash manage.sh
cd /opt/pymc_repeater
bash manage.sh
```
Open the dashboard at:
```text
http://<container-ip>:8000
```
### CH341 GPIO Pin Mapping
The installer pre-configures the CH341 GPIO pins for an E22 module. These differ from the Raspberry Pi BCM pin numbers:
The Proxmox installer pre-configures CH341 GPIO pins for an E22 module. These
are not Raspberry Pi BCM pin numbers:
| Function | CH341 GPIO | Pi BCM (default) |
|----------|-----------|-------------------|
| CS | 0 | 21 |
| RXEN | 1 | -1 |
| Reset | 2 | 18 |
| Busy | 4 | 20 |
| IRQ | 6 | 16 |
| Function | CH341 GPIO | Pi BCM Default |
|----------|-----------:|---------------:|
| CS | 0 | 21 |
| RXEN | 1 | -1 |
| Reset | 2 | 18 |
| Busy | 4 | 20 |
| IRQ | 6 | 16 |
The installer also enables `use_dio3_tcxo` and `use_dio2_rf` for E22 modules.
### Troubleshooting (Proxmox)
### Troubleshooting
- **USB device not found**: Make sure the CH341 is plugged into the Proxmox host and shows up with `lsusb -d 1a86:5512`
- **Permission denied on USB**: The installer creates a host udev rule (`/etc/udev/rules.d/99-ch341.rules`). Run `udevadm trigger` on the host if needed
- **Container can't see USB**: Verify USB passthrough lines exist in `/etc/pve/lxc/<CTID>.conf`:
```
- **USB device not found**: confirm the CH341 is plugged into the Proxmox host
and appears in `lsusb -d 1a86:5512`.
- **Permission denied on USB**: the installer creates
`/etc/udev/rules.d/99-ch341.rules`. Run `udevadm trigger` on the host if
needed.
- **Container cannot see USB**: verify USB passthrough lines exist in
`/etc/pve/lxc/<CTID>.conf`:
```text
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir 0 0
```
- **NoBackendError (libusb)**: The installer installs `libusb-1.0-0` automatically. If you see this error, run `apt-get install libusb-1.0-0` inside the container
- **NoBackendError for libusb**: the installer installs `libusb-1.0-0`
automatically. If needed, run `apt-get install libusb-1.0-0` inside the
container.
## Uninstallation
```bash
sudo ./manage.sh
sudo bash ./manage.sh uninstall
```
This script will:
The uninstaller will:
- Stop and disable the systemd service
- Remove the installation directory
- Optionally remove configuration, logs, and user data
- Optionally remove the service user account
The script will prompt you for each optional removal step.
The script prompts before each optional removal step.
## Docker Compose
You can now run pyMC Repeater from within a [Docker Container](https://www.docker.com/). Checkout the example [Docker Compose](./docker-compose.yml) file before you get started. It will need some configuration changes based on what hardware you're using (USB vs SPI). Look at the commented out lines to see which hardware requires what lines and only enable what you need.
You can run pyMC Repeater in Docker using the published image:
Here is what you'll need to do in order to get the container running:
1. Copy the `config.yaml.example` to `config.yaml`
```bash
cp ./config.yaml.example ./config.yaml
```yaml
image: ${PYMC_REPEATER_IMAGE:-pymcdev/pymc-repeater:main}
```
2. Run the configuration script and follow the prompts.
### Setup
1. Configure `docker-compose.yml` for your hardware and device paths.
2. Comment out or remove device mappings that do not apply to your hardware.
3. Pull and start the container.
```bash
sudo bash ./setup-radio-config.sh
docker compose pull
docker compose up -d --force-recreate
```
3. Modify the `config.yaml` file with a unique web UI password. This allows you to bypass the `/setup` page when logging for the first time. You can find the value under `repeater.security.admin_password`. Change to _anything_ besides the default of `admin123`.
### Example `docker-compose.yml`
4. Configure the [docker compose](./docker-compose.yml) to your specific hardware and file paths. Be sure to comment-out or delete lines that aren't required for your hardware. Please note that your hardware devices might be at a different path than those listed in the docker compose file.
```yaml
services:
pymc-repeater:
image: pymcdev/pymc-repeater:main
container_name: pymc-repeater
restart: unless-stopped
ports:
- 8000:8000
5. Build and start the container.
devices:
# SPI devices. Your paths may differ.
- /dev/spidev0.0
- /dev/gpiochip0
```bash
docker compose up -d --force-recreate --build
# USB devices. Your paths may differ.
- /dev/bus/usb/002:/dev/bus/usb/002
cap_add:
- SYS_RAWIO
group_add:
- plugdev
volumes:
- ./config:/etc/pymc_repeater
- ./data:/var/lib/pymc_repeater
```
## Roadmap / Planned Features
- [ ] **Public Map Integration** - Submit repeater location and details to public map for discovery
- [ ] **Remote Administration over LoRa** - Manage repeater configuration remotely via LoRa mesh
- [ ] **Trace Request Handling** - Respond to trace/diagnostic requests from mesh network
## Roadmap
- [ ] **Public map integration**: submit repeater location and details to a
public map for discovery.
- [ ] **Remote administration over LoRa**: manage repeater configuration from
the mesh.
- [ ] **Trace request handling**: respond to trace and diagnostic requests from
the mesh network.
## Contributing
I welcome contributions! To contribute to pyMC_repeater:
Contributions are welcome.
1. Fork the repository and clone your fork.
2. Create a feature branch from `dev`:
1. **Fork the repository** and clone your fork
2. **Create a feature branch** from the `dev` branch:
```bash
git checkout -b feature/your-feature-name dev
```
3. **Make your changes** and test with **real** hardware
4. **Commit with clear messages**:
3. Make your changes and test with real hardware when possible.
4. Commit with a clear message:
```bash
git commit -m "feat: description of changes"
git commit -m "feat: describe your change"
```
5. **Push to your fork** and submit a **Pull Request to the `dev` branch**
- Include a clear description of the changes
- Reference any related issues
5. Push to your fork and open a pull request against `dev`.
Include a clear description, hardware tested, and any related issues.
### Development Setup
@@ -402,15 +472,16 @@ I welcome contributions! To contribute to pyMC_repeater:
# Install in development mode with dev tools (ruff, pytest, mypy, etc)
pip install -e ".[dev]"
# Setup pre-commit hooks for code quality
# Install pre-commit hooks
pip install pre-commit
pre-commit install
# Manually run pre-commit checks on all files
# Run checks manually
pre-commit run --all-files
```
**Note:** Hardware support (LoRa radio drivers) is included in the base installation automatically via `pymc_core[hardware]`.
Hardware support for LoRa radio drivers is included in the base installation
through `pymc_core[hardware]`.
Pre-commit hooks will automatically:
- Lint and auto-fix Python issues with Ruff
@@ -419,26 +490,29 @@ Pre-commit hooks will automatically:
## Support
- [Core Lib Documentation](https://rightup.github.io/pyMC_core/)
- [Meshcore Discord](https://discordapp.com/channels/1343693475589263471/1431414286974189639)
- [pyMC Core](https://github.com/pyMC-dev/pyMC_core)
- [MeshCore Discord](https://meshcore.gg)
## Disclaimer
**⚠️ Important Notice**
This software has been tested on actual hardware, but it is provided "as is"
without warranty of any kind, express or implied. No guarantee is made about
performance, compatibility, or suitability for any particular purpose.
This software has been tested on actual hardware, but is provided "as is" without warranty of any kind, express or implied. While care has been taken to ensure stability and reliability, I make no guarantees about the software's performance, compatibility, or suitability for any particular purpose.
By using this software, you acknowledge and agree that:
**By using this software, you acknowledge and agree that:**
- You use this software entirely at your own risk
- I hold no responsibility for any damage to hardware, data loss, or system failures
- You are responsible for ensuring compliance with local radio regulations and licensing requirements
- No support or warranty is guaranteed, though community assistance is available
- You use it entirely at your own risk.
- The author is not responsible for hardware damage, data loss, or system
failures.
- You are responsible for complying with local radio regulations and licensing
requirements.
- No support or warranty is guaranteed, though community assistance may be
available.
This software is intended for educational and experimental purposes. Always test in a controlled environment before deploying to production.
This software is intended for educational and experimental use. Always test in a
controlled environment before production deployment.
## License
This project is licensed under the MIT License - see the LICENSE file for details.
This project is licensed under the MIT License. See [LICENSE](LICENSE) for
details.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 327 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB