diff --git a/app/routers/radio.py b/app/routers/radio.py
index 107be52..bb68086 100644
--- a/app/routers/radio.py
+++ b/app/routers/radio.py
@@ -1,4 +1,5 @@
import logging
+from typing import Literal
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
@@ -51,6 +52,10 @@ class RadioConfigResponse(BaseModel):
path_hash_mode_supported: bool = Field(
default=False, description="Whether firmware supports path hash mode setting"
)
+ advert_location_source: Literal["off", "node_gps", "saved_coords"] = Field(
+ default="saved_coords",
+ description="Source used for location included in adverts",
+ )
class RadioConfigUpdate(BaseModel):
@@ -65,6 +70,10 @@ class RadioConfigUpdate(BaseModel):
le=2,
description="Path hash mode (0=1-byte, 1=2-byte, 2=3-byte)",
)
+ advert_location_source: Literal["off", "node_gps", "saved_coords"] | None = Field(
+ default=None,
+ description="Source used for location included in adverts",
+ )
class PrivateKeyUpdate(BaseModel):
@@ -80,6 +89,15 @@ async def get_radio_config() -> RadioConfigResponse:
if not info:
raise HTTPException(status_code=503, detail="Radio info not available")
+ adv_loc_policy = info.get("adv_loc_policy", 2)
+ advert_location_source: Literal["off", "node_gps", "saved_coords"]
+ if adv_loc_policy == 0:
+ advert_location_source = "off"
+ elif adv_loc_policy == 1:
+ advert_location_source = "node_gps"
+ else:
+ advert_location_source = "saved_coords"
+
return RadioConfigResponse(
public_key=info.get("public_key", ""),
name=info.get("name", ""),
@@ -95,6 +113,7 @@ async def get_radio_config() -> RadioConfigResponse:
),
path_hash_mode=radio_manager.path_hash_mode,
path_hash_mode_supported=radio_manager.path_hash_mode_supported,
+ advert_location_source=advert_location_source,
)
diff --git a/app/services/radio_commands.py b/app/services/radio_commands.py
index 81fbeb9..53028c6 100644
--- a/app/services/radio_commands.py
+++ b/app/services/radio_commands.py
@@ -32,6 +32,22 @@ async def apply_radio_config_update(
sync_radio_time_fn: Callable[[Any], Awaitable[Any]],
) -> None:
"""Apply a validated radio-config update to the connected radio."""
+ if update.advert_location_source is not None:
+ advert_loc_policy = {
+ "off": 0,
+ "node_gps": 1,
+ "saved_coords": 2,
+ }[update.advert_location_source]
+ logger.info(
+ "Setting advert location policy to %s",
+ update.advert_location_source,
+ )
+ result = await mc.commands.set_advert_loc_policy(advert_loc_policy)
+ if result is not None and result.type == EventType.ERROR:
+ raise RadioCommandRejectedError(
+ f"Failed to set advert location policy: {result.payload}"
+ )
+
if update.name is not None:
logger.info("Setting radio name to %s", update.name)
await mc.commands.set_name(update.name)
diff --git a/frontend/src/components/settings/SettingsRadioSection.tsx b/frontend/src/components/settings/SettingsRadioSection.tsx
index 876d90b..8c091d7 100644
--- a/frontend/src/components/settings/SettingsRadioSection.tsx
+++ b/frontend/src/components/settings/SettingsRadioSection.tsx
@@ -54,6 +54,9 @@ export function SettingsRadioSection({
const [sf, setSf] = useState('');
const [cr, setCr] = useState('');
const [pathHashMode, setPathHashMode] = useState('0');
+ const [advertLocationSource, setAdvertLocationSource] = useState<
+ 'off' | 'node_gps' | 'saved_coords'
+ >('saved_coords');
const [gettingLocation, setGettingLocation] = useState(false);
const [busy, setBusy] = useState(false);
const [rebooting, setRebooting] = useState(false);
@@ -86,6 +89,7 @@ export function SettingsRadioSection({
setSf(String(config.radio.sf));
setCr(String(config.radio.cr));
setPathHashMode(String(config.path_hash_mode));
+ setAdvertLocationSource(config.advert_location_source ?? 'saved_coords');
}, [config]);
useEffect(() => {
@@ -175,6 +179,9 @@ export function SettingsRadioSection({
lat: parsedLat,
lon: parsedLon,
tx_power: parsedTxPower,
+ ...(advertLocationSource !== (config.advert_location_source ?? 'saved_coords')
+ ? { advert_location_source: advertLocationSource }
+ : {}),
radio: {
freq: parsedFreq,
bw: parsedBw,
@@ -506,6 +513,28 @@ export function SettingsRadioSection({
/>
+
+
+
+
+ This only controls which location source the radio puts into adverts. If you choose Use
+ Node GPS, GPS still has to be enabled manually on the node itself for live coordinates
+ to take effect; RemoteTerm cannot turn it on through the interface library. RemoteTerm
+ still uses the saved coordinates above for local distance math and similar UI
+ calculations.
+