Add get/set dutycycle command

We translate to af internally, it's easier to store and doesn't break
stored prefs. Made get/set af command show deprecated, but it still
works fine.
This commit is contained in:
Wessel Nieboer 2026-03-07 14:55:14 +01:00 committed by Wessel Nieboer
parent df01fd3efb
commit 0aa0ec1f16
No known key found for this signature in database
GPG key ID: 929C8E45E33B5FD2
3 changed files with 40 additions and 16 deletions

View file

@ -500,20 +500,22 @@ This document provides an overview of CLI commands that can be sent to MeshCore
---
#### View or change the airtime factor (duty cycle limit)
#### View or change the duty cycle limit
**Usage:**
- `get af`
- `set af <value>`
- `get dutycycle`
- `set dutycycle <value>`
**Parameters:**
- `value`: Airtime factor (0-9). After each transmission, the repeater enforces a silent period of approximately the on-air transmission time multiplied by the value. This results in a long-term duty cycle of roughly 1 divided by (1 plus the value). For example:
- `af = 1` → ~50% duty
- `af = 2` → ~33% duty
- `af = 3` → ~25% duty
- `af = 9` → ~10% duty
Yyou are responsible for choosing a value that is appropriate for your jurisdiction and channel plan (for example EU 868 Mhz 10% duty cycle regulation).
- `value`: Duty cycle percentage (10-100)
**Default:** `1.0`
**Default:** `50%` (equivalent to airtime factor 1.0)
**Examples:**
- `set dutycycle 100` — no duty cycle limit
- `set dutycycle 50` — 50% duty cycle (default)
- `set dutycycle 10` — 10% duty cycle (strictest EU requirement)
> **Deprecated:** `get af` / `set af` still work but are deprecated in favour of `dutycycle`.
---

View file

@ -28,9 +28,11 @@ set lon {longitude}
Sets your advertisement map longitude. (decimal degrees)
```
set af {air-time-factor}
set dutycycle {percent}
```
Sets the transmit air-time-factor.
Sets the transmit duty cycle limit (10-100%). Example: `set dutycycle 10` for 10%.
> **Deprecated:** `set af` still works but is deprecated in favour of `set dutycycle`.
```

View file

@ -294,8 +294,13 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
*/
} else if (memcmp(command, "get ", 4) == 0) {
const char* config = &command[4];
if (memcmp(config, "af", 2) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor));
if (memcmp(config, "dutycycle", 8) == 0) {
float dc = 100.0f / (_prefs->airtime_factor + 1.0f);
int dc_int = (int)dc;
int dc_frac = (int)((dc - dc_int) * 10.0f + 0.5f);
sprintf(reply, "> %d.%d%%", dc_int, dc_frac);
} else if (memcmp(config, "af", 2) == 0) {
sprintf(reply, "> %s (deprecated, use 'get dutycycle')", StrHelper::ftoa(_prefs->airtime_factor));
} else if (memcmp(config, "int.thresh", 10) == 0) {
sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold);
} else if (memcmp(config, "agc.reset.interval", 18) == 0) {
@ -451,10 +456,25 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
*/
} else if (memcmp(command, "set ", 4) == 0) {
const char* config = &command[4];
if (memcmp(config, "af ", 3) == 0) {
if (memcmp(config, "dutycycle ", 9) == 0) {
float dc = atof(&config[9]);
if (dc < 10 || dc > 100) {
strcpy(reply, "ERROR: dutycycle must be 10-100");
} else {
_prefs->airtime_factor = (100.0f / dc) - 1.0f;
savePrefs();
float actual = 100.0f / (_prefs->airtime_factor + 1.0f);
int a_int = (int)actual;
int a_frac = (int)((actual - a_int) * 10.0f + 0.5f);
sprintf(reply, "OK - %d.%d%%", a_int, a_frac);
}
} else if (memcmp(config, "af ", 3) == 0) {
_prefs->airtime_factor = atof(&config[3]);
savePrefs();
strcpy(reply, "OK");
float actual = 100.0f / (_prefs->airtime_factor + 1.0f);
int a_int = (int)actual;
int a_frac = (int)((actual - a_int) * 10.0f + 0.5f);
sprintf(reply, "OK - %d.%d%% (deprecated, use 'set dutycycle')", a_int, a_frac);
} else if (memcmp(config, "int.thresh ", 11) == 0) {
_prefs->interference_threshold = atoi(&config[11]);
savePrefs();