Radio Gaga Configuration

Every option in the radio-gaga config file, what it does, and the values we recommend.

Overview

Radio Gaga is the small Go service that connects your scooter to Sunshine. It reads a single YAML config file at startup: scooter identity, broker connection, how often to report telemetry, which remote commands are allowed, and optional notifications.

You normally never write this file by hand. When you generate a token in Sunshine, the installer drops a ready-to-run config on the scooter. This page documents what is in that file and what you can change if you want to tune behaviour.

Durations use Go syntax: 500ms, 10s, 5m, 2h, 24h. There is no d unit, so a day is 24h.

The config file

The file location depends on the firmware:

  • Stock ScooterOS: /etc/rescoot/radio-gaga.yml
  • LibreScoot: /data/radio-gaga/config.yaml

The systemd unit starts the service with radio-gaga -config <path>. After editing the file, restart the service to apply changes:

systemctl restart radio-gaga

A minimal config, unix style

The generated config keeps only the keys that matter: your scooter's identity, the broker, and the handful of values that differ from radio-gaga's built-in defaults. Everything else is left commented out so you can see the option and uncomment it to override. Anything you delete falls back to its default.

scooter:
  identifier: WUN...            # your VIN (MQTT username)
  token: 64charsha256...        # MQTT password

mqtt:
  broker_url: ssl://mqtt.sunshine.rescoot.org:8883
  keepalive: 180s
  ca_cert_embedded: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----

telemetry:
  intervals:
    standby: 30m
    standby_no_battery: 2h
  transmit_period: 15m
  buffer:
    enabled: true
    max_retries: 50
    retry_interval: 5m

The full annotated example with every option lives in the radio-gaga repo as radio-gaga.example.yml.

Connection: scooter, MQTT, Redis

scooter

Key Default What it does
identifierrequiredVehicle id (VIN). Used as the MQTT username.
tokenrequiredAuthentication token (MQTT password).
name-Optional friendly name, cosmetic only.

mqtt

Key Default What it does
broker_urlrequiredssl://mqtt.sunshine.rescoot.org:8883
ca_cert-Path to the broker CA certificate file.
ca_cert_embedded-CA certificate inline (PEM). Takes precedence over ca_cert. This is what the installer uses.
keepalive30sMQTT keepalive. Sunshine ships 180s to be gentle on flaky cellular links.

redis_url, ntp, environment

Key Default What it does
redis_urlredis://127.0.0.1:6379On-board Redis the scooter's services use. Leave as-is.
ntp.enabledtrueSync the clock on boot (the scooter has no RTC battery).
ntp.serverpool.ntp.rescoot.orgNTP server to use.
environmentproductionproduction or development. The shell command only works in development.

Telemetry intervals and priorities

Two mechanisms decide when the scooter publishes data. They work together.

telemetry.intervals - periodic snapshots

A full telemetry snapshot is sent on a timer chosen by the vehicle's power state. Lower values mean fresher data but more cellular traffic.

Key Default Recommended When it applies
driving30s30s or higherWhile moving. Keep this at 30s or more; lower floods the broker.
standby5m30mParked, battery present.
standby_no_battery8h2h - 8hParked, no main battery.
hibernate24h24hDeep sleep. Minimal keepalive.

telemetry.priorities - change-driven flushing

Between snapshots, when a field changes, radio-gaga schedules an early publish. Each field has a priority, and the priority sets the deadline: the longest a changed field waits before being sent. This stops analog noise on battery and engine fields from firing a publish on every millivolt blip, while still pushing important changes quickly.

The four deadlines must stay ordered: immediate ≤ quick ≤ medium ≤ slow. Lower is more responsive but costs more traffic.

Priority Default Fields
immediate10sVehicle state, lock status, blinkers.
quick30sGPS, battery charge level.
medium5mMost other fields.
slow1hAux battery, connectivity battery, BLE status.

Dropping immediate too low brings back the data spam these deadlines exist to prevent. 10s keeps lock and state changes timely without publishing on every toggle.

Buffering and events

When the broker is unreachable (tunnel, dead spot, maintenance), telemetry is buffered and replayed on reconnect with the original timestamps. The on-disk path is auto-detected; you cannot set it in the config (older configs that did are ignored).

Key Default What it does
telemetry.buffer.enabledfalseBuffer telemetry while offline. Sunshine ships true.
telemetry.buffer.max_size1000Max buffered records before the oldest are dropped.
telemetry.buffer.max_retries5Send attempts per batch.
telemetry.buffer.retry_interval1mGap between retries.
telemetry.transmit_period5mHow often the buffer is drained.
events.enabledtrueDetect and publish discrete events (alarm, movement, faults).
events.max_retries10Send attempts per event before giving up.

Commands

Remote commands are enabled by default. You only list a command under commands: to disable it or to tune its parameters. ping and get_state can never be disabled.

To disable a command:

commands:
  shell:
    disabled: true

Some commands take parameters. These go under a params: map. The alarm params can be written either nested (shown) or as flat dotted keys (hazards.flash: true); both resolve the same way.

commands:
  honk:
    params:
      on_time: 100ms          # horn pulse for a single honk
  locate:
    params:
      honk_time: 40ms         # length of each locate beep
      honk_interval: 80ms     # gap between the two beeps in a pair
      interval: 4s            # gap between the two beep pairs
  alarm:
    params:
      hazards:
        flash: true
      horn:
        honk: true
        on_time: 400ms
        off_time: 400ms

Telegram notifications

Radio Gaga can send alerts straight to a Telegram chat (alarm triggered, unauthorized movement, low battery, and so on) without going through Sunshine. Setting it up takes about five minutes.

  1. 1

    Create a bot. In Telegram, message @BotFather, send /newbot, and follow the prompts (pick a name and a username ending in bot). BotFather replies with a bot token that looks like 123456789:AAH....

  2. 2

    Start a chat with your bot. Open your new bot and send it any message (for example hi). A bot cannot message you until you have messaged it first.

  3. 3

    Find your chat id. Open this URL in a browser, replacing <token> with your bot token:

https://api.telegram.org/bot<token>/getUpdates

Look for "chat":{"id":123456789 in the JSON. That number is your chat id. For a group chat the id is negative (for example -1001234567890); add the bot to the group first, then send a message there.

Now add the block to your config:

telegram:
  enabled: true
  bot_token: "123456789:AAH..."
  chat_id: "123456789"
  rate_limit: 1s          # minimum gap between messages
  queue_size: 100
  daily_limit: 0          # 0 = unlimited
  events:
    alarm: true
    unauthorized_movement: true
    battery_warning: true
    temperature_warning: true
    state_change: false
    connectivity: false
    fault: false

If you leave out the events: map, the first four (alarm, unauthorized movement, battery warning, temperature warning) are on and the rest are off. Restart radio-gaga and trigger the alarm once to confirm a message arrives.

Rule-based notifications and SMS

Beyond the built-in Telegram events, you can write your own rules. Each rule watches a Redis field (or a raw message), and when its conditions match, it routes a message to Telegram, SMS, or both. Rules are checked on every change, so a cooldown is usually a good idea.

notifications:
  rules:
    - name: "cbb_low"
      conditions:
        - source: "cb-battery"   # Redis hash to watch
          field: "charge"
          operator: "<"          # <, >, <=, >=, ==, !=
          value: "50"
      channels: [telegram]
      cooldown: "30m"
      message: "CB battery at {{cb-battery.charge}}%"   # {{source.field}} placeholders

    - name: "alarm_while_parked"  # multiple conditions are ANDed
      conditions:
        - source: "alarm"
          field: "status"
          operator: "=="
          value: "triggered"
        - source: "vehicle"
          field: "state"
          operator: "=="
          value: "standby"
      channels: [telegram, sms]

A condition matches either a hash field (field + operator + value) or a raw pub/sub payload (message: "==" or message: "contains" + value). You cannot set both on one condition.

SMS goes out through the cellular modem via ModemManager (mmcli), so it only works on hardware with a modem:

notifications:
  sms:
    enabled: false
    phone_number: "+491234567890"
    rate_limit: "30s"    # minimum gap between messages
    daily_limit: 20      # 0 = unlimited
    queue_size: 20

Command-line flags

Most settings live in the config file, but a few flags are handy for one-off runs and debugging. Flags override the config file. The systemd unit only passes -config.

-config string        path to config file (default: radio-gaga.yml)
-identifier string    vehicle identifier (MQTT username)
-token string         authentication token (MQTT password)
-mqtt-broker string   MQTT broker URL
-mqtt-cacert string   path to MQTT CA certificate
-mqtt-keepalive       MQTT keepalive (default: 30s)
-redis-url string     Redis URL (default: redis://localhost:6379)
-environment string   production or development
-debug                enable debug logging
-driving-interval     telemetry interval while driving (default: 30s)
-standby-interval     telemetry interval in standby (default: 5m)
-transmit-period      buffer transmission period (default: 5m)
-version              print version and exit

Changing config at runtime

You do not have to SSH in and restart the service to change a setting. Radio Gaga accepts remote config commands that take effect immediately, addressing keys with dot notation:

  • config:get - read a key, for example telemetry.intervals.driving
  • config:set - change a key. Applies right away, in memory.
  • config:del - remove a key (reverting it to its default).
  • config:save - persist the current in-memory config to disk. Creates a backup of the previous file first.

So the usual flow is config:set to try a value, then config:save once you are happy with it. Without a save, the change is lost on the next restart. These commands are issued for you from Sunshine's admin scooter config editor; you rarely send them by hand.

Other options

Key Default What it does
unu_uplink.enabledfalseOn stock firmware, point the legacy unu-uplink service at this broker and restart it. Only touches the config if it still points at the defunct unu cloud.
service_nameauto-detectedsystemd unit radio-gaga manages itself as (for self-update).
debugfalseVerbose logging. Same as the -debug flag.

Need to get a scooter online in the first place? See the setup guide.