17 Commits

Author SHA1 Message Date
Yellowcooln 6de2b23266 Merge pull request #319 from yellowcooln/fix/ha-addon-dispatch-repo
fix: update HA add-on dispatch target
2026-06-26 09:39:08 -04:00
yellowcooln 864030283c fix: update HA add-on dispatch target 2026-06-26 09:35:19 -04:00
Yellowcooln 751c9e3807 Merge pull request #318 from yellowcooln/fix/openhop-docker-vars
Update Docker image branding
2026-06-26 09:23:21 -04:00
yellowcooln fbbc7e6844 fix: handle advert timeout cancellation 2026-06-26 09:18:41 -04:00
yellowcooln 4d095dad42 fix: update Docker image branding 2026-06-26 09:10:58 -04:00
Lloyd fcaad1dacf feat: add ensure_service_user_home function to manage service user home directory 2026-06-26 13:49:54 +01:00
Yellowcooln e2ae7e18a6 Merge pull request #317 from openhop-dev/revert-316-fix/updater-venv-pip-shim
Revert "fix: repair updater venv pip shim"
2026-06-25 22:13:57 -04:00
Yellowcooln 11f8ea2f43 Revert "fix: repair updater venv pip shim" 2026-06-25 22:13:42 -04:00
Yellowcooln d24a346cf7 Merge pull request #316 from yellowcooln/fix/updater-venv-pip-shim
fix: repair updater venv pip shim
2026-06-25 22:13:14 -04:00
yellowcooln af6bea5bbe fix: repair updater venv pip shim 2026-06-25 22:04:25 -04:00
Yellowcooln 9846666076 Merge pull request #315 from yellowcooln/fix/openhop-updater-repo
fix: update updater GitHub repository
2026-06-25 21:46:58 -04:00
yellowcooln 42340f683f fix: update updater GitHub repository 2026-06-25 21:32:52 -04:00
Yellowcooln 27e68167d5 Merge pull request #314 from openhop-dev/yellowcooln-patch-1
Update default Docker image repository
2026-06-25 20:07:28 -04:00
Yellowcooln f0408d263d Update default Docker image repository 2026-06-25 19:54:18 -04:00
Lloyd 135d6b1d8d Merge pull request #313 from openhop-dev/fix-venv-in-manage
Fix venv in manage
2026-06-25 23:36:48 +01:00
Lloyd 9748058010 fix: update virtual environment pip usage in manage.sh 2026-06-25 23:32:19 +01:00
Lloyd cc0dc2ffd6 fix: virtual environment creation logic in manage.sh 2026-06-25 23:13:28 +01:00
15 changed files with 128 additions and 65 deletions
+4 -4
View File
@@ -3,7 +3,7 @@
# Published image to run. Use a different repository or tag if you are testing
# a fork or a specific release.
PYMC_REPEATER_IMAGE=pymcdev/openhop-repeater:main
OPENHOP_REPEATER_IMAGE=openhop/openhop-repeater:main
# Storage defaults to Docker named volumes. This is the safest option for
# Portainer and fresh installs because Docker preserves the image ownership.
@@ -12,8 +12,8 @@ PYMC_REPEATER_IMAGE=pymcdev/openhop-repeater:main
# sudo mkdir -p /opt/openhop-repeater/config /opt/openhop-repeater/data
# sudo chown -R 15888:15888 /opt/openhop-repeater/config /opt/openhop-repeater/data
# Then uncomment and adjust these paths:
# PYMC_CONFIG_VOLUME=/opt/openhop-repeater/config
# PYMC_DATA_VOLUME=/opt/openhop-repeater/data
# OPENHOP_CONFIG_VOLUME=/opt/openhop-repeater/config
# OPENHOP_DATA_VOLUME=/opt/openhop-repeater/data
# Serial/SPI/GPIO access uses the host's numeric group IDs. Check your host with:
# getent group dialout
@@ -29,6 +29,6 @@ GPIO_GID=986
SPI_GID=989
# Local build only. These are used by docker-compose.build.yml if you build the
# image yourself instead of pulling PYMC_REPEATER_IMAGE.
# image yourself instead of pulling OPENHOP_REPEATER_IMAGE.
PUID=15888
PGID=15888
+3 -3
View File
@@ -10,7 +10,7 @@ on:
image_repository:
description: "Docker image repository to publish to"
required: false
default: "pymcdev/openhop-repeater"
default: "openhop/openhop-repeater"
jobs:
docker:
@@ -61,7 +61,7 @@ jobs:
elif [ "${{ github.repository }}" = "yellowcooln/openhop_repeater" ]; then
image_repository="yellowcooln/openhop-repeater"
else
image_repository="pymcdev/openhop-repeater"
image_repository="openhop/openhop-repeater"
fi
echo "Using image repository: ${image_repository}"
@@ -107,5 +107,5 @@ jobs:
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${DISPATCH_TOKEN}" \
https://api.github.com/repos/pyMC-dev/pyMC-HA-Add-on/dispatches \
https://api.github.com/repos/openhop-dev/openHop-HA-Add-on/dispatches \
-d "{\"event_type\":\"sync-upstream-channel\",\"client_payload\":{\"channel\":\"${CHANNEL}\",\"revision\":\"${REVISION}\"}}"
+11 -9
View File
@@ -2,6 +2,8 @@
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
@@ -111,8 +113,8 @@ sudo apt install git -y
### Clone The Repository
```bash
git clone https://github.com/openhop-dev/openhop-repeater.git
cd openhop-repeater
git clone https://github.com/openhop-dev/openhop_repeater.git
cd openhop_repeater
```
### Quick Install
@@ -258,7 +260,7 @@ The web interface can upgrade an installation or switch branches.
### CLI
```bash
cd openhop-repeater
cd openhop_repeater
sudo bash ./manage.sh upgrade
```
@@ -295,7 +297,7 @@ Hardware, choose one:
Run this command on the Proxmox host, not inside a container:
```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/pyMC-dev/openhop-repeater/main/scripts/proxmox-install.sh)"
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.
@@ -416,7 +418,7 @@ that source as a directory, which breaks startup.
### Setup
1. Copy `.env.example` to `.env`.
2. Review `.env` and update `PYMC_REPEATER_IMAGE`, `DIALOUT_GID`,
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 and device paths.
4. Uncomment the USB device mapping only if your host has that device path.
@@ -431,7 +433,7 @@ docker compose up -d
```yaml
services:
openhop-repeater:
image: ${PYMC_REPEATER_IMAGE:-pymcdev/openhop-repeater:main}
image: ${OPENHOP_REPEATER_IMAGE:-${PYMC_REPEATER_IMAGE:-openhop/openhop-repeater:main}}
container_name: openhop-repeater
restart: unless-stopped
ports:
@@ -455,8 +457,8 @@ services:
- plugdev
volumes:
- ${PYMC_CONFIG_VOLUME:-openhop-repeater-config}:/etc/openhop_repeater
- ${PYMC_DATA_VOLUME:-openhop-repeater-data}:/var/lib/openhop_repeater
- ${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:
@@ -518,7 +520,7 @@ Pre-commit hooks will automatically:
## Support
- [pyMC Core](https://github.com/openhop-dev/openhop-core)
- [pyMC Core](https://github.com/openhop-dev/openhop_core)
- [MeshCore Discord](https://meshcore.gg)
## Disclaimer
+3 -3
View File
@@ -22,7 +22,7 @@ R2_BASE_URL="https://wheel.pymc.dev/pymc_build_deps"
PIWHEELS_INDEX_URL="https://www.piwheels.org/simple"
R2_ENABLED=1
YQ_VERSION="${YQ_VERSION:-v4.44.3}"
PYMC_CORE_REPO="${PYMC_CORE_REPO:-https://github.com/rightup/openhop-core.git}"
PYMC_CORE_REPO="${PYMC_CORE_REPO:-https://github.com/openhop-dev/openhop_core.git}"
PYMC_CORE_REF="${PYMC_CORE_REF:-}"
PYMC_CORE_LOCAL_DIR="${PYMC_CORE_LOCAL_DIR:-}"
PYMC_SKIP_BUILDROOT_DEP_INSTALL="${PYMC_SKIP_BUILDROOT_DEP_INSTALL:-0}"
@@ -1247,12 +1247,12 @@ prepare_git_version() {
git -C "$SCRIPT_DIR" fetch --tags 2>/dev/null || true
git_version=$(python3 -m setuptools_scm 2>/dev/null || echo "1.0.5")
export SETUPTOOLS_SCM_PRETEND_VERSION="$git_version"
export SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYMC_REPEATER="$git_version"
export SETUPTOOLS_SCM_PRETEND_VERSION_FOR_OPENHOP_REPEATER="$git_version"
info "Using version: $git_version"
else
git_version="1.0.5"
export SETUPTOOLS_SCM_PRETEND_VERSION="$git_version"
export SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYMC_REPEATER="$git_version"
export SETUPTOOLS_SCM_PRETEND_VERSION_FOR_OPENHOP_REPEATER="$git_version"
info "Using fallback version: $git_version"
fi
+1 -1
View File
@@ -15,7 +15,7 @@ Build-Depends: debhelper-compat (= 13),
python3-psutil,
git
Standards-Version: 4.6.2
Homepage: https://github.com/rightup/openhop-repeater
Homepage: https://github.com/openhop-dev/openhop_repeater
X-Python3-Version: >= 3.9
Package: openhop-repeater
+3 -3
View File
@@ -1,6 +1,6 @@
services:
openhop-repeater:
image: ${PYMC_REPEATER_IMAGE:-pymcdev/openhop-repeater:main}
image: ${OPENHOP_REPEATER_IMAGE:-${PYMC_REPEATER_IMAGE:-openhop/openhop-repeater:main}}
container_name: openhop-repeater
restart: unless-stopped
ports:
@@ -21,8 +21,8 @@ services:
- "${SPI_GID:-989}"
- plugdev
volumes:
- ${PYMC_CONFIG_VOLUME:-openhop-repeater-config}:/etc/openhop_repeater
- ${PYMC_DATA_VOLUME:-openhop-repeater-data}:/var/lib/openhop_repeater
- ${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:
+1 -1
View File
@@ -3,7 +3,7 @@ set -eu
INSTALL_DIR="${INSTALL_DIR:-/opt/openhop_repeater}"
CONFIG_DIR="${CONFIG_DIR:-/etc/openhop_repeater}"
CONFIG_PATH="${PYMC_REPEATER_CONFIG:-${CONFIG_DIR}/config.yaml}"
CONFIG_PATH="${OPENHOP_REPEATER_CONFIG:-${PYMC_REPEATER_CONFIG:-${CONFIG_DIR}/config.yaml}}"
EXAMPLE_PATH="${CONFIG_DIR}/config.yaml.example"
BUNDLED_EXAMPLE_PATH="${INSTALL_DIR}/config.yaml.example"
RUNTIME_USER="${USER:-repeater}"
+1 -1
View File
@@ -17,7 +17,7 @@ ENV INSTALL_DIR=/opt/openhop_repeater \
HOME_DIR=/home/${USER} \
PATH=/home/${USER}/.local/bin:${PATH} \
PYTHONUNBUFFERED=1 \
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYMC_REPEATER=${PACKAGE_VERSION} \
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_OPENHOP_REPEATER=${PACKAGE_VERSION} \
PUID=${PUID} \
PGID=${PGID} \
DIALOUT_GID=${DIALOUT_GID} \
+4 -4
View File
@@ -3,7 +3,7 @@
# Published image to run. Use a different repository or tag if you are testing
# a fork or a specific release.
PYMC_REPEATER_IMAGE=pymcdev/openhop-repeater:main
OPENHOP_REPEATER_IMAGE=openhop/openhop-repeater:main
# Storage defaults to Docker named volumes. This is the safest option for
# Portainer and fresh installs because Docker preserves the image ownership.
@@ -12,8 +12,8 @@ PYMC_REPEATER_IMAGE=pymcdev/openhop-repeater:main
# sudo mkdir -p /opt/openhop-repeater/config /opt/openhop-repeater/data
# sudo chown -R 15888:15888 /opt/openhop-repeater/config /opt/openhop-repeater/data
# Then uncomment and adjust these paths:
# PYMC_CONFIG_VOLUME=/opt/openhop-repeater/config
# PYMC_DATA_VOLUME=/opt/openhop-repeater/data
# OPENHOP_CONFIG_VOLUME=/opt/openhop-repeater/config
# OPENHOP_DATA_VOLUME=/opt/openhop-repeater/data
# SPI/GPIO access uses the host's numeric group IDs. Check your host with:
# getent group gpio
@@ -26,6 +26,6 @@ GPIO_GID=986
SPI_GID=989
# Local build only. These are used by docker-compose.build.yml if you build the
# image yourself instead of pulling PYMC_REPEATER_IMAGE.
# image yourself instead of pulling OPENHOP_REPEATER_IMAGE.
PUID=15888
PGID=15888
+58 -18
View File
@@ -88,14 +88,51 @@ migrate_legacy_paths() {
migrate_one_path "$LEGACY_PYMC_INSTALL_DIR" "$INSTALL_DIR" "install"
}
ensure_service_user_home() {
local current_home
if ! id "$SERVICE_USER" &>/dev/null; then
return 0
fi
current_home="$(getent passwd "$SERVICE_USER" | cut -d: -f6)"
if [ -z "$current_home" ]; then
return 0
fi
if [ "$current_home" != "$DATA_DIR" ]; then
mkdir -p "$DATA_DIR" 2>/dev/null || true
usermod -d "$DATA_DIR" "$SERVICE_USER" 2>/dev/null || true
echo " ✓ Updated $SERVICE_USER home directory: $current_home -> $DATA_DIR"
fi
}
# Create (or re-create) the dedicated venv for openhop_repeater
ensure_venv() {
local recreate=0
if [ ! -x "$VENV_PYTHON" ]; then
echo ">>> Creating virtual environment at $VENV_DIR ..."
python3 -m venv --system-site-packages "$VENV_DIR"
# Upgrade pip inside the venv
"$VENV_PIP" install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
recreate=1
elif ! "$VENV_PYTHON" -c 'import sys; print(sys.executable)' >/dev/null 2>&1; then
# Venv python exists but points to a missing interpreter (stale venv).
recreate=1
elif ! "$VENV_PYTHON" -m pip --version >/dev/null 2>&1; then
# Pip script/shebang can break after Python upgrades; treat as stale.
recreate=1
fi
if [ "$recreate" -eq 1 ]; then
if [ -d "$VENV_DIR" ]; then
echo ">>> Rebuilding broken virtual environment at $VENV_DIR ..."
rm -rf "$VENV_DIR"
else
echo ">>> Creating virtual environment at $VENV_DIR ..."
fi
python3 -m venv --system-site-packages "$VENV_DIR"
fi
# Always use python -m pip so we don't rely on a potentially stale pip wrapper.
"$VENV_PYTHON" -m pip install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
}
# Migrate an existing system-pip install into the venv.
@@ -105,6 +142,7 @@ migrate_to_venv() {
# 1. Ensure the venv exists
ensure_venv
ensure_service_user_home
# 2. Remove legacy PYTHONPATH from the service unit
local svc_unit="/etc/systemd/system/openhop-repeater.service"
@@ -424,6 +462,7 @@ install_repeater() {
if ! id "$SERVICE_USER" &>/dev/null; then
useradd --system --home "$DATA_DIR" --shell /sbin/nologin "$SERVICE_USER"
fi
ensure_service_user_home
disable_legacy_services
@@ -567,7 +606,7 @@ fi
if [ ! -x "$VENV_PYTHON" ]; then
echo "[pymc-do-upgrade] Creating venv at $VENV_DIR ..."
python3 -m venv --system-site-packages "$VENV_DIR"
"$VENV_PIP" install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
"$VENV_PYTHON" -m pip install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
fi
# ---- Migration: clean up legacy service unit issues ----
SVC_UNIT=/etc/systemd/system/openhop-repeater.service
@@ -615,15 +654,15 @@ if [ -n "$ARCH_TAG" ]; then
PY_TAG=$("$VENV_PYTHON" -c 'import sys; v=f"cp{sys.version_info.major}{sys.version_info.minor}"; print(f"{v}-{v}")' 2>/dev/null || echo "cp311-cp311")
WHEEL_BASE="${R2_BASE_URL}/${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG}"
echo "[pymc-do-upgrade] Trying dependencies from R2 wheels..."
"$VENV_PIP" install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null || true
"$VENV_PYTHON" -m pip install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null || true
fi
# ---- Install openhop_repeater from git ----
if "$VENV_PIP" install \
if "$VENV_PYTHON" -m pip install \
--upgrade \
--no-cache-dir \
"openhop_repeater[hardware] @ git+https://github.com/rightup/openhop-repeater.git@${CHANNEL}"; then
"openhop_repeater[hardware] @ git+https://github.com/openhop-dev/openhop_repeater.git@${CHANNEL}"; then
# Keep web/OTA updates aligned with manage.sh install/upgrade defaults.
RADIO_BASE_URL="https://raw.githubusercontent.com/rightup/openhop-repeater/${CHANNEL}"
RADIO_BASE_URL="https://raw.githubusercontent.com/openhop-dev/openhop_repeater/${CHANNEL}"
RADIO_STORAGE_DIR="/var/lib/openhop_repeater"
mkdir -p "$RADIO_STORAGE_DIR"
wget -qO "$RADIO_STORAGE_DIR/radio-settings.json" "${RADIO_BASE_URL}/radio-settings.json" 2>/dev/null || true
@@ -687,7 +726,7 @@ UPGRADEEOF
WHEEL_BASE="${R2_BASE_URL}/${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG}"
echo " Checking for R2 wheels (${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG})..."
echo " Trying install from R2 pre-built wheels..."
"$VENV_PIP" install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null && R2_SUCCESS=1 || R2_SUCCESS=0
"$VENV_PYTHON" -m pip install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null && R2_SUCCESS=1 || R2_SUCCESS=0
if [ "$R2_SUCCESS" -eq 1 ]; then
echo " ✓ R2 wheels installed"
else
@@ -696,7 +735,7 @@ UPGRADEEOF
fi
fi
if "$VENV_PIP" install --upgrade --no-cache-dir .[hardware]; then
if "$VENV_PYTHON" -m pip install --upgrade --no-cache-dir .[hardware]; then
echo ""
echo "✓ Python package installation completed successfully!"
@@ -868,6 +907,7 @@ upgrade_repeater() {
echo "[1.6/9] Ensuring required directories..."
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$LOG_DIR" "$DATA_DIR"
ensure_service_user_home
echo "[2/9] Backing up configuration..."
if [ -d "$CONFIG_DIR" ]; then
@@ -1002,7 +1042,7 @@ fi
if [ ! -x "$VENV_PYTHON" ]; then
echo "[pymc-do-upgrade] Creating venv at $VENV_DIR ..."
python3 -m venv --system-site-packages "$VENV_DIR"
"$VENV_PIP" install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
"$VENV_PYTHON" -m pip install --upgrade pip setuptools wheel >/dev/null 2>&1 || true
fi
# ---- Migration: clean up legacy service unit issues ----
SVC_UNIT=/etc/systemd/system/openhop-repeater.service
@@ -1050,15 +1090,15 @@ python3 -m pip uninstall -y pymc_core 2>/dev/null || true
PY_TAG=$("$VENV_PYTHON" -c 'import sys; v=f"cp{sys.version_info.major}{sys.version_info.minor}"; print(f"{v}-{v}")' 2>/dev/null || echo "cp311-cp311")
WHEEL_BASE="${R2_BASE_URL}/${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG}"
echo "[pymc-do-upgrade] Trying dependencies from R2 wheels..."
"$VENV_PIP" install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null || true
"$VENV_PYTHON" -m pip install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null || true
fi
# ---- Install openhop_repeater from git ----
if "$VENV_PIP" install \
if "$VENV_PYTHON" -m pip install \
--upgrade \
--no-cache-dir \
"openhop_repeater[hardware] @ git+https://github.com/rightup/openhop-repeater.git@${CHANNEL}"; then
"openhop_repeater[hardware] @ git+https://github.com/openhop-dev/openhop_repeater.git@${CHANNEL}"; then
# Keep web/OTA updates aligned with manage.sh install/upgrade defaults.
RADIO_BASE_URL="https://raw.githubusercontent.com/rightup/openhop-repeater/${CHANNEL}"
RADIO_BASE_URL="https://raw.githubusercontent.com/openhop-dev/openhop_repeater/${CHANNEL}"
RADIO_STORAGE_DIR="/var/lib/openhop_repeater"
mkdir -p "$RADIO_STORAGE_DIR"
wget -qO "$RADIO_STORAGE_DIR/radio-settings.json" "${RADIO_BASE_URL}/radio-settings.json" 2>/dev/null || true
@@ -1122,7 +1162,7 @@ UPGRADEEOF
WHEEL_BASE="${R2_BASE_URL}/${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG}"
echo " Checking for R2 wheels (${ARCH_TAG}/${PLATFORM_TAG}/${PY_TAG})..."
echo " Trying install from R2 pre-built wheels..."
"$VENV_PIP" install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null && R2_SUCCESS=1 || R2_SUCCESS=0
"$VENV_PYTHON" -m pip install --find-links "${WHEEL_BASE}/index.html" --no-cache-dir "pycryptodome>=3.23.0" "PyNaCl>=1.5.0" cffi "pyyaml>=6.0.0" 2>/dev/null && R2_SUCCESS=1 || R2_SUCCESS=0
if [ "$R2_SUCCESS" -eq 1 ]; then
echo " ✓ R2 wheels installed"
else
@@ -1131,7 +1171,7 @@ UPGRADEEOF
fi
fi
if "$VENV_PIP" install --upgrade --no-cache-dir .[hardware]; then
if "$VENV_PYTHON" -m pip install --upgrade --no-cache-dir .[hardware]; then
echo ""
echo "✓ Package and dependencies upgraded successfully!"
else
+13 -6
View File
@@ -195,7 +195,10 @@ def get_node_info(config: Dict[str, Any]) -> Dict[str, Any]:
def load_config(config_path: Optional[str] = None) -> Dict[str, Any]:
if config_path is None:
config_path = os.getenv("PYMC_REPEATER_CONFIG", "/etc/openhop_repeater/config.yaml")
config_path = os.getenv(
"OPENHOP_REPEATER_CONFIG",
os.getenv("PYMC_REPEATER_CONFIG", "/etc/openhop_repeater/config.yaml"),
)
# Check if config file exists
if not Path(config_path).exists():
@@ -301,10 +304,11 @@ def load_config(config_path: Optional[str] = None) -> Dict[str, Any]:
else:
config["repeater"]["identity_key"] = _load_or_create_identity_key()
if os.getenv("PYMC_REPEATER_LOG_LEVEL"):
env_log_level = os.getenv("OPENHOP_REPEATER_LOG_LEVEL", os.getenv("PYMC_REPEATER_LOG_LEVEL"))
if env_log_level:
if "logging" not in config:
config["logging"] = {}
config["logging"]["level"] = os.getenv("PYMC_REPEATER_LOG_LEVEL")
config["logging"]["level"] = env_log_level
config = _load_policy_engine_config(config, config_path)
@@ -323,7 +327,10 @@ def save_config(config_data: Dict[str, Any], config_path: Optional[str] = None)
True if successful, False otherwise
"""
if config_path is None:
config_path = os.getenv("PYMC_REPEATER_CONFIG", "/etc/openhop_repeater/config.yaml")
config_path = os.getenv(
"OPENHOP_REPEATER_CONFIG",
os.getenv("PYMC_REPEATER_CONFIG", "/etc/openhop_repeater/config.yaml"),
)
try:
# Create backup of existing config
@@ -617,7 +624,7 @@ def get_radio_for_board(board_config: dict):
except ImportError:
raise RuntimeError(
"pymc_tcp radio requires openhop-core >= the release that includes "
"PR pyMC-dev/openhop-core#68 (merged 2026-05-13). "
"the openhop-core release with TCP modem support. "
"Reinstall the [hardware] extra to pick it up."
) from None
@@ -661,7 +668,7 @@ def get_radio_for_board(board_config: dict):
except ImportError:
raise RuntimeError(
"pymc_usb radio requires openhop-core >= the release that includes "
"PR pyMC-dev/openhop-core#68 (merged 2026-05-13). "
"the openhop-core release with TCP modem support. "
"Reinstall the [hardware] extra to pick it up."
) from None
+3 -6
View File
@@ -1580,6 +1580,7 @@ class APIEndpoints:
if cherrypy.request.method == "OPTIONS":
return ""
future = None
try:
self._require_post()
if not self.send_advert_func:
@@ -1588,7 +1589,6 @@ class APIEndpoints:
return self._error("Event loop not available")
import asyncio
future = None
future = asyncio.run_coroutine_threadsafe(self.send_advert_func(), self.event_loop)
result = future.result(timeout=10)
return (
@@ -1601,11 +1601,8 @@ class APIEndpoints:
"Error sending advert: timeout waiting for advert transmission to complete",
exc_info=True,
)
try:
if future is not None:
future.cancel()
except Exception:
pass
if future is not None:
future.cancel()
return self._error("Timed out waiting for advert transmission after 10 seconds")
except cherrypy.HTTPError:
# Re-raise HTTP errors (like 405 Method Not Allowed) without logging
+1 -1
View File
@@ -15,7 +15,7 @@ info:
version: 1.0.0
contact:
name: openHop Repeater
url: https://github.com/rightup/openhop-repeater
url: https://github.com/openhop-dev/openhop_repeater
servers:
- url: /api
+4 -4
View File
@@ -3,15 +3,15 @@
# Creates an LXC container with USB passthrough and installs openHop Repeater
#
# Usage (run on the Proxmox host):
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/pyMC-dev/openhop-repeater/main/scripts/proxmox-install.sh)"
# bash -c "$(curl -fsSL https://raw.githubusercontent.com/openhop-dev/openhop_repeater/main/scripts/proxmox-install.sh)"
#
# License: MIT
# Source: https://github.com/openhop-dev/openhop-repeater
# Source: https://github.com/openhop-dev/openhop_repeater
set -euo pipefail
# ── Defaults ───────────────────────────────────────────────────────────────
REPO="https://github.com/openhop-dev/openhop-repeater.git"
REPO="https://github.com/openhop-dev/openhop_repeater.git"
BRANCH="dev"
CT_TEMPLATE="debian-12-standard"
CT_RAM=1024
@@ -210,7 +210,7 @@ OS=\$(. /etc/os-release && echo \"\$NAME\")
VER=\$(. /etc/os-release && echo \"\$VERSION_ID\")
echo \"\"
echo \" openHop Repeater LXC Container\"
echo \" 🌐 GitHub: https://github.com/openhop-dev/openhop-repeater\"
echo \" 🌐 GitHub: https://github.com/openhop-dev/openhop_repeater\"
echo \"\"
echo \" 🖥️ OS: \$OS - Version: \$VER\"
echo \" 🏠 Hostname: \$HOSTNAME\"
+18 -1
View File
@@ -1,6 +1,6 @@
from types import SimpleNamespace
from repeater.config import BaselineCrcCounterRadio
from repeater.config import BaselineCrcCounterRadio, load_config
def test_baseline_crc_counter_radio_reports_delta_from_initial_raw_count():
@@ -26,3 +26,20 @@ def test_baseline_crc_counter_radio_handles_delayed_modem_counter():
raw.crc_error_count = 148
assert radio.crc_error_count == 3
def test_load_config_prefers_openhop_env_names(tmp_path, monkeypatch):
legacy_path = tmp_path / "legacy.yaml"
openhop_path = tmp_path / "openhop.yaml"
legacy_path.write_text("repeater:\n identity_key: legacy\n", encoding="utf-8")
openhop_path.write_text("repeater:\n identity_key: openhop\n", encoding="utf-8")
monkeypatch.setenv("PYMC_REPEATER_CONFIG", str(legacy_path))
monkeypatch.setenv("OPENHOP_REPEATER_CONFIG", str(openhop_path))
monkeypatch.setenv("PYMC_REPEATER_LOG_LEVEL", "WARNING")
monkeypatch.setenv("OPENHOP_REPEATER_LOG_LEVEL", "DEBUG")
config = load_config()
assert config["repeater"]["identity_key"] == "openhop"
assert config["logging"]["level"] == "DEBUG"