openhop_repeater

openhop-devMIT活跃维护

基于 openhop_core 的轻量级 LoRa 中继守护进程,用 Python 实现,跑在 SX1262 硬件上,帮 MeshCore 网络扩展信号覆盖范围。

A lightweight Repeater Daemon implemented in Python, built using the openhop_core library.

1.1.4发布于 2026-09-08 23:02 UTC309star +4 / 7 天93fork同步于 2026-11-10 18:02 UTC

怎么上手

由 README 提炼,执行前请确认
git clone https://github.com/openhop-dev/openhop_repeater.git
cd openhop_repeater
sudo bash ./manage.sh install
硬件要求按 README 说明

面向树莓派级低功耗 Linux 设备、Proxmox LXC 容器和网络接入的电台调制解调器;支持单射频 SX1262 类收发器(原生 SPI 或 CH341 USB 转 SPI)、openHop TCP/USB-CDC 调制解调器与 KISS 串口调制解调器;不支持仅 UART 的 HAT 和 SX1302/SX1303 集中器板;README 未提及显存或 GPU 要求。

有 Docker 镜像
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

轻量级 LoRa MeshCore 中继守护进程,在树莓派等低功耗 Linux 设备上转发 LoRa 数据包并提供 Web 面板

基于 openhop_core 的轻量级 LoRa 中继守护进程,用 Python 实现,跑在 SX1262 硬件上,帮 MeshCore 网络扩展信号覆盖范围。

核心能力

  • 基于 openhop_core 调度与路由栈转发 LoRa 数据包
  • CherryPy 提供 Web 面板与 API,支持配置、监控、日志和更新
  • 支持 SPI SX1262、CH341 USB-SPI、TCP/USB 调制解调器与 KISS 串口
  • 模块化拆分策略引擎、存储、传感器、GPS、MQTT 等组件
  • 提供 systemd 服务与 Docker Compose 两种部署方式

容易踩的坑

安装脚本会创建 repeater 服务用户并写入 /opt、/etc、/var/log 下的目录,需要 sudo 权限;Web 面板默认监听 8000 端口;Docker 部署时需按实际硬件删除不需要的设备映射,且不要用 docker compose down -v 以免丢失配置和插件数据。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

1 个版本1.1.4
  1. 1.1.4最新正式版2026-09-08 · 2026-09-08 23:02 UTC

    What's Changed

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    openHop Repeater

    Lightweight Python MeshCore repeater daemon built on openhop_core.

    Formerly pyMC_Repeater built on pyMC_core.

    openHop 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.

    Contents

    Overview

    The repeater daemon runs as a background service and forwards LoRa packets using the openhop_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, openHop TCP/USB modem firmware, and KISS serial modems.

    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

    Real-time packet statistics, neighbor discovery, and system status.

    Statistics

    Statistics

    Historical statistics and performance metrics.

    Supported Hardware

    openHop Repeater supports these radio backends:

    • SX1262 over Linux SPI: set radio_type: sx1262
    • SX1262 over CH341 USB-to-SPI: set radio_type: sx1262_ch341
    • openHop Modem over Wi-Fi/Ethernet: set radio_type: modem_tcp
    • openHop Modem over USB-CDC: set radio_type: modem_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.

    InterfaceStatus
    Native SX1262 SPI radioSupported
    CH341 USB-to-SPI bridgeSupported
    openHop TCP modemSupported
    openHop USB-CDC modemSupported
    KISS serial modemSupported
    UART-only HATsNot supported
    SX1302/SX1303 concentrator boardsNot supported

    The following devices have out-of-the-box presets or known support:

    Device NamePlatformTX PowerConnectionRadio ModuleLink
    HackerGadgets uConsoleuConsole / Raspberry Pi CMUp to 22 dBmSPISX1262-classView
    Zindello Industries UltraPeaterLuckfoxUp to 30 dBmSPIE22, E22PView
    MeshSmith PiMesh-1WRaspberry PiUp to 30 dBmSPIE22PView
    MeshSmith EtherMesh-1WNetworkUp to 30 dBmTCPE22PView
    Frequency Labs meshadv-miniRaspberry PiUp to 30 dBmSPIE22View
    Frequency Labs meshadvRaspberry PiUp to 30 dBmSPIE22View

    Always confirm pin mappings, antenna setup, regional frequency rules, and TX power limits before transmitting.

    Installation

    Install Git

    sudo apt update
    sudo apt install git -y
    

    Clone The Repository

    git clone https://github.com/openhop-dev/openhop_repeater.git
    cd openhop_repeater
    

    Quick Install

    sudo bash ./manage.sh install
    

    The installer will:

    • Create a dedicated repeater service user with hardware access
    • Install application files to /opt/openhop_repeater
    • Create the configuration directory at /etc/openhop_repeater
    • Create the log directory at /var/log/openhop_repeater
    • Launch the interactive radio and hardware setup wizard
    • Install and enable the openhop-repeater systemd service

    After installation:

    # View live logs
    sudo journalctl -u openhop-repeater -f
    

    Open the web dashboard at:

    http://<repeater-ip>:8000
    

    Development Install

    pip install -e .
    

    For development tools:

    pip install -e ".[dev]"
    

    Configuration

    The main configuration file is created during installation:

    /etc/openhop_repeater/config.yaml
    

    Setup Wizard

    The web-based setup flow guides you through repeater identity, hardware selection, radio presets, and login setup.

    Start Setup

    Onboarding Step 1

    Repeater Name

    Onboarding Step 2

    Hardware Type

    Onboarding Step 3

    Choose A Preset

    Onboarding Step 5

    TX Power

    TX power defaults to 14 dBm and can be changed later.

    TX Power Notice

    Set A Password

    Onboarding Step 6

    Update TX settings

    Radio Configuration

    Run CAD Calibration

    CAD Calibration

    Reconfigure Radio And Hardware

    To reconfigure radio and hardware settings after installation:

    sudo bash setup-radio-config.sh /etc/openhop_repeater
    

    You can also launch the management menu:

    sudo ./manage.sh
    sudo systemctl restart openhop-repeater
    

    Optional pyMC_Glass Integration

    openHop 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:

    glass:
      enabled: true
      base_url: "http://localhost:8080"
      inform_interval_seconds: 30
    

    Policy Engine

    Use the policy engine to create packet management rules from the web interface.

    Policy

    Example: Drop Channel packets over two hops

    Policy Example

    Upgrading

    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.

    Existing native installations must run the updated sudo bash ./manage.sh upgrade once as an administrator to replace the privileged OTA helper after the security update. Updating only the Python package or using the old web updater does not refresh that helper. See native upgrade prerequisites.

    Upgrade

    CLI

    cd openhop_repeater
    sudo bash ./manage.sh upgrade
    

    The upgrade script will:

    • Pull the latest code from the main branch
    • Update application files
    • Upgrade Python dependencies if needed
    • Restart the service automatically
    • Preserve the existing configuration

    Proxmox LXC Installation

    openHop Repeater can run inside a Proxmox LXC container using a CH341 USB-to-SPI adapter or an openHop Modem over TCP or USB. This is useful for headless, always-on deployments without dedicating a full Raspberry Pi.

    Requirements

    Software:

    • Proxmox VE 8.x or 9.x host; 9.x is recommended for new deployments
    • A matching Debian 13 standard LXC template available through pveam
    • Internet access from the container during installation and updates

    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. Select the optional host-side CH341 udev rule for this setup.
    • openHop Modem over TCP, such as MeshSmith EtherMesh-1W, reachable from the container network. This does not need the CH341 udev rule or a USB device.
    • openHop Modem over USB, connected to the Proxmox host. The installer enables general USB passthrough by default; the CH341 udev rule is not needed.

    One-Line Install

    Run this command on the Proxmox host, not inside a container:

    bash -c "$(curl -fsSL https://raw.githubusercontent.com/openhop-dev/openhop_repeater/main/scripts/proxmox-install.sh)"
    

    Replace main in the URL with another branch name if needed.

    The installer will prompt for container settings (container ID, hostname, RAM, disk, bridge, etc.), whether to install the host-side CH341 udev rule, and whether to download the optional openHop Console WebUI. It will then:

    1. Download a Debian 13 LXC template matching the Proxmox host architecture.
    2. Create a privileged container with USB passthrough.
    3. Install the host-side CH341 udev rule only when selected. This is not needed for openHop Modem TCP or USB connections and defaults to No.
    4. Start the container, wait for network access, then run a full Debian package update and upgrade.
    5. Clone the repository and pre-seed CH341 GPIO pin mappings.
    6. Install an update command for Debian and openHop Repeater updates.
    7. Run manage.sh install inside the container.
    8. Optionally install openHop Console WebUI assets after Repeater installation. The public Console distribution repository is cloned as a depth-one, single-branch checkout without tags at /root/pymc_console, minimizing disk usage while keeping it upgradeable in the same way as Repeater. Console is not selected as the default frontend, allowing the Repeater setup wizard to be completed first.
    9. Display the dashboard URL.

    Default Container Settings

    SettingDefault
    Container IDNext available
    Hostnameopenhop-repeater
    RAM1024 MB
    Disk4 GB
    CPU cores2
    Bridgevmbr0
    VLAN IDNone
    Storagelocal-lvm
    PasswordopenHop1!
    Host-side CH341 udev ruleNo
    openHop Console WebUINo

    After Installation

    # Enter the container
    pct enter <CTID>
    
    # View service logs
    journalctl -u openhop-repeater -f
    
    # Manage the repeater
    cd /opt/openhop_repeater
    bash manage.sh
    

    Run update inside the LXC to update Debian packages, fast-forward the branch selected during installation, and run manage.sh upgrade. The command first lists every action and requires a y/N confirmation. When Console is installed, it also updates /root/pymc_console and refreshes the Console assets:

    update
    

    If openHop Console WebUI was installed, complete the Repeater setup wizard before selecting openHop Console from Web Settings.

    Open the dashboard at:

    http://<container-ip>:8000
    

    CH341 GPIO Pin Mapping

    The Proxmox installer pre-configures CH341 GPIO pins for an E22 module. These are not Raspberry Pi BCM pin numbers:

    FunctionCH341 GPIOPi BCM Default
    CS021
    RXEN1-1
    Reset218
    Busy420
    IRQ616

    The installer also enables use_dio3_tcxo and use_dio2_rf for E22 modules.

    Troubleshooting

    • 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:

      lxc.cgroup2.devices.allow: c 189:* rwm
      lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir 0 0
      
    • 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

    Read the Uninstallation guide and make a durable backup before continuing. The native uninstaller performs a complete removal after one confirmation: it deletes the current and legacy installation, configuration, logs, data, and the repeater service user.

    sudo bash ./manage.sh uninstall
    

    The script attempts a best-effort configuration-only backup under /tmp, but that is not a durable or complete backup and may be removed automatically. It does not prompt separately for individual paths. Docker Compose removal and persistent volume cleanup are separate operations covered by the guide.

    Docker Compose

    You can run openHop Repeater in Docker using the published image.

    Copy .env.example to .env before starting:

    cp .env.example .env
    

    Set DIALOUT_GID, GPIO_GID, and SPI_GID from getent group dialout, getent group gpio, and getent group spi if your host values are different.

    Default storage should use Docker named volumes. This avoids Portainer creating root-owned ./config and ./data bind mount folders on first start. If you want host bind mounts, use absolute host paths and pre-create/chown them to 15888:15888.

    Do not mount ./config.yaml:/etc/openhop_repeater/config.yaml; Docker can create that source as a directory, which breaks startup.

    Setup

    1. Copy .env.example to .env.
    2. Review .env and update OPENHOP_REPEATER_IMAGE, DIALOUT_GID, GPIO_GID, or SPI_GID if needed.
    3. Configure docker-compose.yml for your hardware. Remove every device mapping that is absent or unnecessary: the shipped file enables SPI, GPIO, and USB bus examples. Network-radio installations do not need those mappings.
    4. Add a serial-modem mapping only after preparing its host device path.
    5. Pull and start the container.
    docker compose up -d
    

    The Docker image includes the default RepeaterUI but no longer downloads or bundles openHop Console. Install optional Console functionality through the plugin catalogue.

    Before upgrading an older image with /opt/pymc_console/web/html selected as its frontend, switch back to the default RepeaterUI. The old bundled directory is absent from new images. Existing plugin data remains in the persistent data volume.

    Image updates and persistent plugins

    For a published image, select the intended image tag in .env, then run:

    docker compose pull
    docker compose up -d
    

    For a local source build, after updating the intended branch:

    docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build
    

    Pulling Git changes or restarting a container alone does not rebuild its image. The Dockerfile packages the frontend assets present in the build context; it does not fetch or build the default RepeaterUI. Frontend changes belong in RepeaterUI, using the matching UI branch (feat-plugin-ui for feat-plugin-manager). Stage the complete verified UI build for packaging; do not hand-edit generated JavaScript. Optional Console installation is managed through the plugin catalogue, independently of image builds.

    Back up both config and data volumes before upgrading. Do not use docker compose down -v if you want to retain configuration and plugins. The default data volume contains plugin releases, retained wheels, venvs, settings, logs, and manager state. A custom plugins.root outside that volume needs its own persistent writable mount.

    Plugin venvs can rebuild after a Python minor-version change. Keep retained wheels; plugins with external dependencies may need network access and compatible packages to rebuild. Older installations without retained wheels need plugin reinstallation. Changing CPU architecture or absolute storage paths is not covered by minor-version rebuild detection.

    The image runs Repeater and its plugin manager as an unprivileged user under a supervisor and tini. To run without the manager, set plugins.enabled: false in configuration, or explicitly add this to the Compose service:

    environment:
      OPENHOP_PLUGIN_MANAGER: "0"
    

    Putting that variable only in .env does not pass it through the shipped Compose file. Repeater remains available without the manager; plugin operations are then unavailable. Plugins are trusted applications, not sandboxed code.

    On startup, existing user configuration overrides defaults from the current image's bundled example; an older example in the config volume is preserved but is not the upgrade merge source. Keep config writable by the image user. The temporary merged config fallback is not persistent; use an absolute storage.storage_dir inside the mounted data directory.

    The volume variables accept the default named volumes or absolute bind paths. If you choose another named volume, also declare it under top-level volumes:; use external: true when intentionally attaching an existing volume.

    Example docker-compose.yml

    services:
      openhop-repeater:
        image: ${OPENHOP_REPEATER_IMAGE:-${PYMC_REPEATER_IMAGE:-openhop/openhop-repeater:main}}
        container_name: openhop-repeater
        restart: unless-stopped
        ports:
          - 8000:8000
    
        devices:
          # SPI devices. Your paths may differ. Remove if not using SPI hardware.
          - /dev/spidev0.0
          - /dev/gpiochip0
    
          # 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
    
        group_add:
          - "${DIALOUT_GID:-20}"
          - "${GPIO_GID:-986}"
          - "${SPI_GID:-989}"
          - plugdev
    
        volumes:
          - ${OPENHOP_CONFIG_VOLUME:-${PYMC_CONFIG_VOLUME:-openhop-repeater-config}}:/etc/openhop_repeater
          - ${OPENHOP_DATA_VOLUME:-${PYMC_DATA_VOLUME:-openhop-repeater-data}}:/var/lib/openhop_repeater
    
    volumes:
      openhop-repeater-config:
      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:

    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:

    devices:
      - /dev/openhop-modem:/dev/openhop-modem
    
    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 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

    Contributions are welcome.

    1. Fork the repository and clone your fork.

    2. Create a feature branch from dev:

      git checkout -b feature/your-feature-name dev
      
    3. Make your changes and test with real hardware when possible.

    4. Commit with a clear message:

      git commit -m "feat: describe your change"
      
    5. Push to your fork and open a pull request against dev.

    Include a clear description, hardware tested, and any related issues.

    Development Setup

    # Install in development mode with dev tools (ruff, pytest, mypy, etc)
    pip install -e ".[dev]"
    
    # Install pre-commit hooks
    pip install pre-commit
    pre-commit install
    
    # Run checks manually
    pre-commit run --all-files
    

    Hardware support for LoRa radio drivers is included in the base installation through openhop_core[hardware] on Linux. On other platforms (e.g. macOS), openhop_core is installed without the hardware extra, since spidev and similar packages only build against the Linux SPI kernel headers.

    Pre-commit hooks will automatically:

    • Lint and auto-fix Python issues with Ruff
    • Validate formatting with Ruff formatter
    • Fix trailing whitespace and other file issues

    Support

    Disclaimer

    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.

    By using this software, you acknowledge and agree that:

    • 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 use. Always test in a controlled environment before production deployment.

    License

    This project is licensed under the MIT License. See LICENSE for details.