Add duty cycle enforcement option, update dashboard duplicate badge text, and implement API fetch with fallback to local presets

This commit is contained in:
Lloyd
2025-10-27 20:47:20 +00:00
parent 733bdc4847
commit 1065949fac
4 changed files with 22 additions and 7 deletions

View File

@@ -89,9 +89,11 @@ delays:
direct_tx_delay_factor: 0.5 direct_tx_delay_factor: 0.5
duty_cycle: duty_cycle:
# Enable/disable duty cycle enforcement
# Set to false to disable airtime limits
enforcement_enabled: false
# Maximum airtime per minute in milliseconds # Maximum airtime per minute in milliseconds
# US/AU FCC limit: 100% duty cycle (3600ms/min)
# EU ETSI limit: 1% duty cycle (36ms/min)
max_airtime_per_minute: 3600 max_airtime_per_minute: 3600
logging: logging:

1
radio-presets.json Normal file
View File

@@ -0,0 +1 @@
{"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"}]}}}

View File

@@ -316,7 +316,7 @@
statusHtml += `<br><small class="drop-reason">${pkt.drop_reason}</small>`; statusHtml += `<br><small class="drop-reason">${pkt.drop_reason}</small>`;
} }
if (hasDuplicates) { if (hasDuplicates) {
statusHtml += ` <span class="dupe-badge">${pkt.duplicates.length} dupe${pkt.duplicates.length > 1 ? 's' : ''}</span>`; statusHtml += ` <span class="dupe-badge">${pkt.duplicates.length} Repeat ${pkt.duplicates.length > 1 ? 's' : ''}</span>`;
} }
let mainRow = ` let mainRow = `

View File

@@ -97,15 +97,27 @@ echo ""
echo "=== Step 2: Select Radio Settings ===" echo "=== Step 2: Select Radio Settings ==="
echo "" echo ""
# Fetch config from API # Fetch config from API with 5 second timeout, fallback to local file
echo "Fetching radio settings from API..." echo "Fetching radio settings from API..."
API_RESPONSE=$(curl -s https://api.meshcore.nz/api/v1/config) API_RESPONSE=$(curl -s --max-time 5 https://api.meshcore2.nz/api/v1/config 2>/dev/null)
if [ -z "$API_RESPONSE" ]; then if [ -z "$API_RESPONSE" ]; then
echo "Error: Failed to fetch configuration from API" echo "Warning: Failed to fetch configuration from API (timeout or error)"
echo "Using local radio presets file..."
LOCAL_PRESETS="$SCRIPT_DIR/radio-presets.json"
if [ ! -f "$LOCAL_PRESETS" ]; then
echo "Error: Local radio presets file not found at $LOCAL_PRESETS"
exit 1 exit 1
fi fi
API_RESPONSE=$(cat "$LOCAL_PRESETS")
if [ -z "$API_RESPONSE" ]; then
echo "Error: Failed to read local radio presets file"
exit 1
fi
fi
# Parse JSON entries - one per line, extracting each field # Parse JSON entries - one per line, extracting each field
SETTINGS=$(echo "$API_RESPONSE" | grep -o '{[^{}]*"title"[^{}]*"coding_rate"[^{}]*}' | sed 's/.*"title":"\([^"]*\)".*/\1/' | while read title; do SETTINGS=$(echo "$API_RESPONSE" | grep -o '{[^{}]*"title"[^{}]*"coding_rate"[^{}]*}' | sed 's/.*"title":"\([^"]*\)".*/\1/' | while read title; do
entry=$(echo "$API_RESPONSE" | grep -o "{[^{}]*\"title\":\"$title\"[^{}]*\"coding_rate\"[^{}]*}") entry=$(echo "$API_RESPONSE" | grep -o "{[^{}]*\"title\":\"$title\"[^{}]*\"coding_rate\"[^{}]*}")