Add support for Femtofox

- Introduce GPIO chip selection and GPIO backend selection
- Add default Femtofox settings (for SX1262 as LR1121 support may come later)
- Add support for Python 3.10 UTC to reduce footprint
- Fix airtime calculation bandwidth variable naming
- Add service auto-enable when starting
- Add Australia: SA, WA, QLD radio preset
- Add Snyk security instructions

Co-authored-by: theshaun <theshaun@users.noreply.github.com>
Based on PR #69
This commit is contained in:
theshaun
2026-02-03 22:34:14 +00:00
committed by Lloyd
parent f7c4e2b4a8
commit 57a25a2dc0
6 changed files with 190 additions and 5 deletions

View File

@@ -70,6 +70,11 @@ is_running() {
systemctl is-active "$SERVICE_NAME" >/dev/null 2>&1
}
# Function to check if service is enabled
is_enabled() {
systemctl is-enabled "$SERVICE_NAME" >/dev/null 2>&1
}
# Function to get current version
get_version() {
# Try to read from _version.py first (generated by setuptools_scm)
@@ -719,6 +724,9 @@ manage_service() {
case $action in
"start")
if ! is_enabled; then
systemctl enable "$SERVICE_NAME"
fi
systemctl start "$SERVICE_NAME"
if is_running; then
show_info "Service Started" "\n✓ pyMC Repeater service has been started successfully."

View File

@@ -1 +1,151 @@
{"config":{"connect_screen":{"info_message":"The default pin for devices without a screen is 123456. Trouble pairing? Forget the bluetooth device in system settings."},"remote_management":{"repeaters":{"guest_login_enabled":true,"guest_login_disabled_message":"Guest login has been temporarily disabled. Please try again later.","guest_login_passwords":[""],"flood_routed_guest_login_enabled":true,"flood_routed_guest_login_disabled_message":"To avoid overwhelming the mesh with flood packets, please set a path to log in to a repeater as a guest."}},"suggested_radio_settings":{"info_message":"These radio settings have been suggested by the community.","entries":[{"title":"Australia","description":"915.800MHz / SF10 / BW250 / CR5","frequency":"915.800","spreading_factor":"10","bandwidth":"250","coding_rate":"5"},{"title":"Australia: Victoria","description":"916.575MHz / SF7 / BW62.5 / CR8","frequency":"916.575","spreading_factor":"7","bandwidth":"62.5","coding_rate":"8"},{"title":"EU/UK (Narrow)","description":"869.618MHz / SF8 / BW62.5 / CR8","frequency":"869.618","spreading_factor":"8","bandwidth":"62.5","coding_rate":"8"},{"title":"EU/UK (Long Range)","description":"869.525MHz / SF11 / BW250 / CR5","frequency":"869.525","spreading_factor":"11","bandwidth":"250","coding_rate":"5"},{"title":"EU/UK (Medium Range)","description":"869.525MHz / SF10 / BW250 / CR5","frequency":"869.525","spreading_factor":"10","bandwidth":"250","coding_rate":"5"},{"title":"Czech Republic (Narrow)","description":"869.525MHz / SF7 / BW62.5 / CR5","frequency":"869.525","spreading_factor":"7","bandwidth":"62.5","coding_rate":"5"},{"title":"EU 433MHz (Long Range)","description":"433.650MHz / SF11 / BW250 / CR5","frequency":"433.650","spreading_factor":"11","bandwidth":"250","coding_rate":"5"},{"title":"New Zealand","description":"917.375MHz / SF11 / BW250 / CR5","frequency":"917.375","spreading_factor":"11","bandwidth":"250","coding_rate":"5"},{"title":"New Zealand (Narrow)","description":"917.375MHz / SF7 / BW62.5 / CR5","frequency":"917.375","spreading_factor":"7","bandwidth":"62.5","coding_rate":"5"},{"title":"Portugal 433","description":"433.375MHz / SF9 / BW62.5 / CR6","frequency":"433.375","spreading_factor":"9","bandwidth":"62.5","coding_rate":"6"},{"title":"Portugal 868","description":"869.618MHz / SF7 / BW62.5 / CR6","frequency":"869.618","spreading_factor":"7","bandwidth":"62.5","coding_rate":"6"},{"title":"Switzerland","description":"869.618MHz / SF8 / BW62.5 / CR8","frequency":"869.618","spreading_factor":"8","bandwidth":"62.5","coding_rate":"8"},{"title":"USA/Canada (Recommended)","description":"910.525MHz / SF7 / BW62.5 / CR5","frequency":"910.525","spreading_factor":"7","bandwidth":"62.5","coding_rate":"5"},{"title":"USA/Canada (Alternate)","description":"910.525MHz / SF11 / BW250 / CR5","frequency":"910.525","spreading_factor":"11","bandwidth":"250","coding_rate":"5"},{"title":"Vietnam","description":"920.250MHz / SF11 / BW250 / CR5","frequency":"920.250","spreading_factor":"11","bandwidth":"250","coding_rate":"5"}]}}}
{
"config": {
"connect_screen": {
"info_message": "The default pin for devices without a screen is 123456. Trouble pairing? Forget the bluetooth device in system settings."
},
"remote_management": {
"repeaters": {
"guest_login_enabled": true,
"guest_login_disabled_message": "Guest login has been temporarily disabled. Please try again later.",
"guest_login_passwords": [
""
],
"flood_routed_guest_login_enabled": true,
"flood_routed_guest_login_disabled_message": "To avoid overwhelming the mesh with flood packets, please set a path to log in to a repeater as a guest."
}
},
"suggested_radio_settings": {
"info_message": "These radio settings have been suggested by the community.",
"entries": [
{
"title": "Australia",
"description": "915.800MHz / SF10 / BW250 / CR5",
"frequency": "915.800",
"spreading_factor": "10",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "Australia (Narrow)",
"description": "916.575MHz / SF7 / BW62.5 / CR8",
"frequency": "916.575",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "8"
},
{
"title": "Australia: SA, WA, QLD",
"description": "923.125MHz / SF8 / BW62.5 / CR8",
"frequency": "923.125",
"spreading_factor": "8",
"bandwidth": "62.5",
"coding_rate": "8"
},
{
"title": "EU/UK (Narrow)",
"description": "869.618MHz / SF8 / BW62.5 / CR8",
"frequency": "869.618",
"spreading_factor": "8",
"bandwidth": "62.5",
"coding_rate": "8"
},
{
"title": "EU/UK (Long Range)",
"description": "869.525MHz / SF11 / BW250 / CR5",
"frequency": "869.525",
"spreading_factor": "11",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "EU/UK (Medium Range)",
"description": "869.525MHz / SF10 / BW250 / CR5",
"frequency": "869.525",
"spreading_factor": "10",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "Czech Republic (Narrow)",
"description": "869.525MHz / SF7 / BW62.5 / CR5",
"frequency": "869.525",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "5"
},
{
"title": "EU 433MHz (Long Range)",
"description": "433.650MHz / SF11 / BW250 / CR5",
"frequency": "433.650",
"spreading_factor": "11",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "New Zealand",
"description": "917.375MHz / SF11 / BW250 / CR5",
"frequency": "917.375",
"spreading_factor": "11",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "New Zealand (Narrow)",
"description": "917.375MHz / SF7 / BW62.5 / CR5",
"frequency": "917.375",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "5"
},
{
"title": "Portugal 433",
"description": "433.375MHz / SF9 / BW62.5 / CR6",
"frequency": "433.375",
"spreading_factor": "9",
"bandwidth": "62.5",
"coding_rate": "6"
},
{
"title": "Portugal 868",
"description": "869.618MHz / SF7 / BW62.5 / CR6",
"frequency": "869.618",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "6"
},
{
"title": "Switzerland",
"description": "869.618MHz / SF8 / BW62.5 / CR8",
"frequency": "869.618",
"spreading_factor": "8",
"bandwidth": "62.5",
"coding_rate": "8"
},
{
"title": "USA/Canada (Recommended)",
"description": "910.525MHz / SF7 / BW62.5 / CR5",
"frequency": "910.525",
"spreading_factor": "7",
"bandwidth": "62.5",
"coding_rate": "5"
},
{
"title": "USA/Canada (Alternate)",
"description": "910.525MHz / SF11 / BW250 / CR5",
"frequency": "910.525",
"spreading_factor": "11",
"bandwidth": "250",
"coding_rate": "5"
},
{
"title": "Vietnam",
"description": "920.250MHz / SF11 / BW250 / CR5",
"frequency": "920.250",
"spreading_factor": "11",
"bandwidth": "250",
"coding_rate": "5"
}
]
}
}
}

View File

@@ -111,6 +111,24 @@
"use_dio2_rf": true,
"preamble_length": 17
},
"femtofox-1W-SX": {
"name": "FemtoFox SX1262 (1W)",
"bus_id": 0,
"cs_id": 0,
"cs_pin": 16,
"gpio_chip": 1,
"use_gpiod_backend": true,
"reset_pin": 25,
"busy_pin": 22,
"irq_pin": 23,
"txen_pin": -1,
"rxen_pin": 24,
"txled_pin": -1,
"rxled_pin": -1,
"tx_power": 30,
"use_dio3_tcxo": true,
"preamble_length": 17
},
"nebrahat": {
"name": "NebraHat-2W",
"bus_id": 0,

View File

@@ -53,17 +53,17 @@ class AirtimeManager:
Airtime in milliseconds
"""
sf = spreading_factor or self.spreading_factor
bw_khz = (bandwidth_hz or self.bandwidth) / 1000
bw_hz = (bandwidth_hz or self.bandwidth)
cr = coding_rate or self.coding_rate
preamble_len = preamble_len or self.preamble_length
crc = 1 if crc_enabled else 0
h = 0 if explicit_header else 1 # H=0 for explicit, H=1 for implicit
# Low data rate optimization: required for SF11/SF12 at 125kHz
de = 1 if (sf >= 11 and bandwidth_hz <= 125000) else 0
de = 1 if (sf >= 11 and bw_hz <= 125000) else 0
# Symbol time in milliseconds: T_sym = 2^SF / BW_kHz
t_sym = (2 ** sf) / bw_khz
t_sym = (2 ** sf) / (bw_hz / 1000)
# Preamble time: T_preamble = (n_preamble + 4.25) * T_sym
t_preamble = (preamble_len + 4.25) * t_sym

View File

@@ -240,6 +240,8 @@ def get_radio_for_board(board_config: dict):
"bus_id": spi_config["bus_id"],
"cs_id": spi_config["cs_id"],
"cs_pin": spi_config["cs_pin"],
"gpio_chip": spi_config.get("gpio_chip", 0),
"use_gpiod_backend": spi_config.get("use_gpiod_backend", False),
"reset_pin": spi_config["reset_pin"],
"busy_pin": spi_config["busy_pin"],
"irq_pin": spi_config["irq_pin"],

View File

@@ -5,11 +5,18 @@ import base64
import paho.mqtt.client as mqtt
import threading
from datetime import datetime, timedelta, UTC
from datetime import datetime, timedelta
from nacl.signing import SigningKey
from typing import Callable, Optional, List, Dict
from .. import __version__
# Try to import datetime.UTC (Python 3.11+) otherwise fallback to timezone.utc
try:
from datetime import UTC
except Exception:
from datetime import timezone
UTC = timezone.utc
# Try to import paho-mqtt error code mappings
try: