mirror of
https://github.com/pyMC-dev/pyMC_Repeater.git
synced 2026-10-31 04:01:59 +01:00
Merge branch 'pr-392' into dev
This commit is contained in:
commit
e840c10ed9
6 files changed
+113
-1
No files matched your search
@@ -457,6 +457,10 @@ services:
|
||||
# USB devices. Uncomment/change only if needed.
|
||||
# - /dev/bus/usb/002:/dev/bus/usb/002
|
||||
|
||||
# USB serial modem. See "USB serial modems" below before using a
|
||||
# /dev/serial/by-id/ path here.
|
||||
# - /dev/openhop-modem:/dev/openhop-modem
|
||||
|
||||
cap_add:
|
||||
- SYS_RAWIO
|
||||
|
||||
@@ -475,6 +479,52 @@ volumes:
|
||||
openhop-repeater-data:
|
||||
```
|
||||
|
||||
### USB serial modems
|
||||
|
||||
A `/dev/serial/by-id/` path is the stable way to name a USB modem, but it cannot
|
||||
always be handed to a container. ESP32-S3 boards that use the chip's native
|
||||
USB-Serial-JTAG peripheral report their factory MAC address as the USB serial
|
||||
number, colons included, so udev produces a name like:
|
||||
|
||||
```
|
||||
/dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_60:55:F9:C0:27:18-if00
|
||||
```
|
||||
|
||||
Docker parses `devices:` entries as `host:container[:permissions]` and has no way
|
||||
to escape a colon inside the path, so that name is rejected. `/dev/serial/by-path/`
|
||||
does not help either, since those contain PCI addresses with colons of their own.
|
||||
|
||||
Two further things to know: `/dev/serial/by-id` is built by udev on the host, and
|
||||
udev does not run inside the container, so the directory is not visible in there
|
||||
unless you bind-mount it. And a bare `/dev/ttyACM0` is not stable across re-plugs
|
||||
or reboots.
|
||||
|
||||
Install the udev rule shipped with openHop Core, which creates a colon-free
|
||||
symlink that survives re-plugs:
|
||||
|
||||
```bash
|
||||
sudo cp 99-openhop-modem.rules /etc/udev/rules.d/
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --subsystem-match=tty --action=change
|
||||
```
|
||||
|
||||
Then map the symlink and point the config at the same path:
|
||||
|
||||
```yaml
|
||||
devices:
|
||||
- /dev/openhop-modem:/dev/openhop-modem
|
||||
```
|
||||
|
||||
```yaml
|
||||
kiss:
|
||||
port: "/dev/openhop-modem"
|
||||
```
|
||||
|
||||
The rule matches USB ID `303a:1001`, which every ESP32-S3 board using native USB
|
||||
shares. With more than one attached, pin the rule to a single board's serial
|
||||
number — the rules file has a commented example and the `udevadm` command to read
|
||||
it.
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [ ] **Public map integration**: submit repeater location and details to a
|
||||
|
||||
+4
-1
@@ -528,7 +528,10 @@ radio:
|
||||
|
||||
# KISS modem (when radio_type: kiss). Requires openhop-core with KISS support.
|
||||
# kiss:
|
||||
# port: "/dev/ttyUSB0"
|
||||
# port: "/dev/ttyUSB0" # 99-openhop-modem.rules symlinks to /dev/openhop-modem.
|
||||
# # Prefer that over /dev/serial/by-id/ in Docker: an
|
||||
# # ESP32-S3 by-id name contains colons and Docker reads
|
||||
# # those as its host:container separator.
|
||||
# baud_rate: 9600
|
||||
# # Optional KISS key-up / CSMA tuning, forwarded to the modem firmware.
|
||||
# # Omit to keep the wrapper/firmware defaults. For a host-managed repeater the
|
||||
|
||||
@@ -11,6 +11,12 @@ services:
|
||||
- /dev/gpiochip0
|
||||
# USB DEVICES (Your path may differ)
|
||||
- /dev/bus/usb/002:/dev/bus/usb/002
|
||||
# USB SERIAL MODEM (KISS / openHop USB). Do NOT use a /dev/serial/by-id/
|
||||
# path here: ESP32-S3 boards report their MAC as the USB serial number, so
|
||||
# the name contains colons and Docker reads those as the host:container
|
||||
# separator. Install 99-openhop-modem.rules on the host and map the
|
||||
# symlink it creates instead. See README, "USB serial modems".
|
||||
# - /dev/openhop-modem:/dev/openhop-modem
|
||||
# SPI DEVICES PERMISSIONS
|
||||
cap_add:
|
||||
- SYS_RAWIO
|
||||
|
||||
@@ -651,6 +651,13 @@ install_repeater() {
|
||||
udevadm trigger 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "59"; echo "# Installing udev rules for USB modems..."
|
||||
if [ -f "$SCRIPT_DIR/../openhop-core/99-openhop-modem.rules" ]; then
|
||||
cp "$SCRIPT_DIR/../openhop-core/99-openhop-modem.rules" /etc/udev/rules.d/99-openhop-modem.rules
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
udevadm trigger --subsystem-match=tty --action=change 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "65"; echo "# Setting permissions..."
|
||||
# Venv stays root-owned (pip runs as root); service user only needs read+execute
|
||||
chown -R "$SERVICE_USER:$SERVICE_USER" "$CONFIG_DIR" "$LOG_DIR" "$DATA_DIR"
|
||||
@@ -1148,6 +1155,14 @@ upgrade_repeater() {
|
||||
elif [ -f /etc/udev/rules.d/99-ch341.rules ]; then
|
||||
echo " ✓ CH341 udev rules already present"
|
||||
fi
|
||||
if [ -f "$SCRIPT_DIR/../openhop-core/99-openhop-modem.rules" ]; then
|
||||
cp "$SCRIPT_DIR/../openhop-core/99-openhop-modem.rules" /etc/udev/rules.d/99-openhop-modem.rules
|
||||
udevadm control --reload-rules 2>/dev/null || true
|
||||
udevadm trigger --subsystem-match=tty --action=change 2>/dev/null || true
|
||||
echo " ✓ USB modem udev rules updated"
|
||||
elif [ -f /etc/udev/rules.d/99-openhop-modem.rules ]; then
|
||||
echo " ✓ USB modem udev rules already present"
|
||||
fi
|
||||
echo " ✓ User groups updated"
|
||||
|
||||
echo "[7/9] Fixing permissions and helper files..."
|
||||
|
||||
@@ -1436,6 +1436,11 @@ class APIEndpoints:
|
||||
for item in devices:
|
||||
dev = item.get("device")
|
||||
if dev and dev not in dedup:
|
||||
# Docker reads `devices:` entries as host:container[:perms] and
|
||||
# cannot escape a colon inside the path, so a /dev/serial/by-id/
|
||||
# name carrying an ESP32-S3 MAC serial is unusable in a
|
||||
# container. Flag it so the UI can offer a symlink instead.
|
||||
item["docker_safe"] = ":" not in dev
|
||||
dedup[dev] = item
|
||||
|
||||
sorted_devices = sorted(dedup.values(), key=lambda x: x["device"])
|
||||
|
||||
@@ -535,6 +535,39 @@ def test_serial_ports_dedupes_duplicate_devices(cherrypy_ctx):
|
||||
assert "first" in result["data"][0]["description"]
|
||||
|
||||
|
||||
def test_serial_ports_flags_paths_docker_cannot_map(cherrypy_ctx):
|
||||
del cherrypy_ctx
|
||||
api = _make_api()
|
||||
|
||||
# ESP32-S3 boards on the native USB-Serial-JTAG peripheral report their MAC
|
||||
# as the USB serial number, colons included. Docker reads `devices:` as
|
||||
# host:container, so this path cannot be passed into a container.
|
||||
by_id = SimpleNamespace(
|
||||
device="/dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_60:55:F9:C0:27:18-if00",
|
||||
description="USB JTAG/serial debug unit",
|
||||
hwid="USB VID:PID=303A:1001",
|
||||
)
|
||||
|
||||
with patch("serial.tools.list_ports.comports", return_value=[by_id]):
|
||||
result = api.serial_ports()
|
||||
|
||||
assert result["success"] is True
|
||||
assert result["data"][0]["docker_safe"] is False
|
||||
|
||||
|
||||
def test_serial_ports_marks_ordinary_paths_docker_safe(cherrypy_ctx):
|
||||
del cherrypy_ctx
|
||||
api = _make_api()
|
||||
|
||||
p1 = SimpleNamespace(device="/dev/ttyACM0", description="USB CDC", hwid="n/a")
|
||||
|
||||
with patch("serial.tools.list_ports.comports", return_value=[p1]):
|
||||
result = api.serial_ports()
|
||||
|
||||
assert result["success"] is True
|
||||
assert result["data"][0]["docker_safe"] is True
|
||||
|
||||
|
||||
def test_config_export_redacts_secrets_and_identity_keys(cherrypy_ctx):
|
||||
request, _ = cherrypy_ctx
|
||||
request.method = "GET"
|
||||
|
||||
Reference in new issue
Block a user