API Band Plan Auto-Detection
Overview
The WirelessChassis model now automatically detects band plan information from manufacturer APIs (Shure System API, etc.). This minimizes data entry by extracting frequencyBand from API responses and resolving it to standard band plans with min/max frequencies.
How It Works
1. Shure System API provides frequencyBand
The Shure System API returns a frequencyBand field in device status responses:
{ "device_id": "ULXD4Q_001", "model": "ULXD4Q", "frequencyBand": "G50", "status": "online"}2. Detection Functions in device_specs.py
Three new functions handle band plan detection:
-
detect_band_plan_from_api_string(api_band_value, manufacturer)- Input: API frequencyBand value (e.g., “G50”, “G50 (470-534)”)
- Output: Normalized band plan name (e.g., “G50 (470-534 MHz)”)
- Handles multiple format variations from different manufacturers
-
get_band_plan_from_model_code(manufacturer, model)- Input: Model code (e.g., “ULXD4Q”, “AD4Q”)
- Output: Band plan name inferred from model
- Fallback when API doesn’t provide frequencyBand
-
parse_band_plan_from_name(name)- Input: Band plan name with frequencies (e.g., “G50 (470-534 MHz)”)
- Output: Extracted min/max frequencies
- Supports multiple format variations
3. WirelessChassis Services
Service: detect_band_plan_from_api_data(chassis, api_band_value=None)
Detects band plan from API frequency band value with preferred fallback to model code detection.
from micboard.services.hardware.chassis_regulatory_service import detect_band_plan_from_api_data
chassis = WirelessChassis(manufacturer=shure, model="ULXD4Q")result = detect_band_plan_from_api_data(chassis, api_band_value="G50")
# Returns a validated BandPlanInfo DTO:result.name # "G50"result.min_mhz # 470.0result.max_mhz # 534.0result.source # "api"result.message # "Detected from API frequencyBand 'G50'"Service: apply_detected_band_plan(chassis, api_band_value=None)
Convenience method that applies detected band plan directly to the chassis:
from micboard.services.hardware.chassis_regulatory_service import apply_detected_band_plan
chassis = WirelessChassis(manufacturer=shure, model="ULXD4Q")if apply_detected_band_plan(chassis, api_band_value="G50"): chassis.save() # band_plan_name, band_plan_min_mhz, band_plan_max_mhz all set automaticallyelse: print("Could not detect band plan")Automatic Detection on Save
When you set band_plan_name directly, save() automatically resolves frequencies:
chassis = WirelessChassis(manufacturer=shure, model="ULXD4Q")chassis.band_plan_name = "G50 (470-534 MHz)"chassis.save()# band_plan_min_mhz=470.0, band_plan_max_mhz=534.0 automatically populatedIntegration with Device Sync
Using with Shure System API Sync
In your device sync code (e.g., poll_devices command or manufacturer plugin):
from micboard.models.discovery.manufacturer import Manufacturerfrom micboard.models.hardware.wireless_chassis import WirelessChassis
shure_mfg = Manufacturer.objects.get(code="shure")
# 1. Fetch device from Shure System APIapi_response = shure_client.devices.get_device("ULXD4Q_001")
# 2. Create chassis with basic infochassis, created = WirelessChassis.objects.update_or_create( manufacturer=shure_mfg, api_device_id=api_response["device_id"], defaults={ "model": api_response["model"], "name": api_response.get("name", ""), })
# 3. Auto-detect band plan from API frequencyBandfrom micboard.services.hardware.chassis_regulatory_service import apply_detected_band_plan
apply_detected_band_plan(chassis, api_band_value=api_response.get("frequencyBand"))chassis.save()
print(f"✅ Setup band plan: {chassis.band_plan_name}")# Output: ✅ Setup band plan: G50 (470-534 MHz)Bulk Update from API
from micboard.models.hardware.wireless_chassis import WirelessChassisfrom micboard.services.hardware.chassis_regulatory_service import apply_detected_band_plan
# Update all online Shure devicesfor chassis in WirelessChassis.objects.filter( manufacturer__code="shure", status="online"): # Get current status from API api_status = shure_client.devices.get_device(chassis.api_device_id)
# Apply detected band plan if apply_detected_band_plan( chassis, api_band_value=api_status.get("frequencyBand") ): chassis.save(update_fields=["band_plan_name", "band_plan_min_mhz", "band_plan_max_mhz"]) print(f"✅ {chassis.name}: {chassis.band_plan_name}") else: print(f"⚠️ {chassis.name}: Could not detect band plan")Supported API Format Variations
The detector handles multiple format variations from different manufacturers:
| API Value | Detected As | Source |
|---|---|---|
G50 |
G50 (470-534 MHz) |
Registry lookup |
G50 (470-534) |
G50 (470-534 MHz) |
Registry lookup |
G50 (470-534 MHz) |
G50 (470-534 MHz) |
Registry lookup |
470-534 |
G50 (470-534 MHz) |
Registry lookup by frequency range |
| (missing) | G50 (470-534 MHz) |
Model code inference (ULXD4Q → G50) |
API frequencyBand Values by Manufacturer
Shure Wireless Systems
| Model | Typical frequencyBand | Band Plan |
|---|---|---|
| ULXD4Q | G50 |
G50 (470-534 MHz) |
| ULXD4D | G50 |
G50 (470-534 MHz) |
| AD4Q | G50 |
G50 (470-534 MHz) |
| ULXD1 (handheld) | G50 |
G50 (470-534 MHz) |
| ULXD2/ULXD4 (older) | Variable | Check API response |
| Axient Digital ANX4 | G50 |
G50 (470-534 MHz) |
Note: As of 25.01.26, actual API responses from https://localhost:10000/v1.0/devices should be tested to confirm frequencyBand field availability and format.
Sennheiser Wireless Systems
Currently developing Sennheiser support. Expected format similar to Shure.
Fallback Strategy
If API doesn’t provide frequencyBand, the detector falls back to model code inference:
-
API Detection (preferred)
- Uses
frequencyBandfrom API - Most accurate, manufacturer-provided
- Uses
-
Model Code Detection (fallback)
- Infers from model number (e.g., ULXD4Q → G50)
- Useful when API doesn’t provide frequencyBand
- Uses pattern matching in
get_band_plan_from_model_code()
-
Manual Entry (last resort)
- Admin selects from dropdown
- Frequencies auto-populate
Testing Queries
Check Available Band Plans
from micboard.models.discovery.manufacturer import Manufacturerfrom micboard.models.band_plans import get_available_band_plansfrom micboard.models.hardware.wireless_chassis import WirelessChassis
shure = Manufacturer.objects.get(code="shure")chassis = WirelessChassis(manufacturer=shure)
plans = get_available_band_plans(manufacturer=chassis.manufacturer.code)# Output: [# ("g50_470_534", "G50 (470-534 MHz)"),# ("h50_520_600", "H50 (520-600 MHz)"),# ...# ]Test Detection
from micboard.models.hardware.wireless_chassis import WirelessChassisfrom micboard.services.hardware.chassis_regulatory_service import ( apply_detected_band_plan, detect_band_plan_from_api_data,)
chassis = WirelessChassis(manufacturer=shure, model="ULXD4Q")
# Test API detectionresult = detect_band_plan_from_api_data(chassis, api_band_value="G50")print(result.name) # "G50"
# Test model detection (no API value)result = detect_band_plan_from_api_data(chassis, api_band_value=None)print(result.name) # "G50" (from ULXD4Q model code)
# Test applyif apply_detected_band_plan(chassis, api_band_value="G50"): print(f"{chassis.band_plan_min_mhz}-{chassis.band_plan_max_mhz} MHz") # Output: 470.0-534.0 MHzData Accuracy
- Registry accuracy: Band plans sourced from official manufacturer specifications
- Model inference: ULXD models map to G50, H50, etc. based on model code patterns
- Frequency ranges: Min/max frequencies verified against regulatory and manufacturer documentation
- Fallback behavior: If API omits frequencyBand, model code inference provides reasonable defaults
Continuing Development
As API integrations mature, this system can be extended to:
- Store API response history for debugging
- Track band plan changes over time
- Validate band plan against regulatory domains
- Alert on mismatches between API and stored data
