Skip to content

librescoot-scootui (scootui-qt)

The original Flutter/Dart scootui is deprecated and replaced by this Qt/QML version.

Description

ScootUI is the primary user interface for Librescoot. It runs on the DBC (Dashboard Computer) and communicates with all Librescoot services via Redis.

  • Qt 6 / QML — UI framework
  • QMapLibre — Vector map rendering
  • Valhalla — Routing engine
  • hiredis — Redis client (async pub/sub + worker thread for polling)
  • CMake — Build system

Features

Real-time Telemetry Display

  • Speed (raw or wheel-corrected), power output, battery levels
  • Odometer, trip meter, GPS status, connectivity indicators
  • System warnings and fault codes

View Modes

  • Cluster — Speedometer and vehicle status
  • Map — 3D-tilted navigation with turn-by-turn directions
  • Destination — Saved locations and destination input
  • Navigation Setup — Route preview and confirmation
  • OTA Update — System update progress and control
  • Offline vector map support (MBTiles via QMapLibre)
  • Online map tiles (VersaTiles OSM) as alternative
  • Valhalla routing (on-device or remote)
  • Speed limit indicators from vector tiles
  • Auto-rotating map with heading tracking

Other

  • Alarm status display
  • Hop-on / hop-off combo lock screen
  • Light and dark themes with auto-switching
  • Configurable blinker overlay styles
  • Multi-language support

Build

Desktop (simulator mode)

./run-desktop.sh

Or manually:

cmake -B build -DDESKTOP_MODE=ON -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j$(nproc)
SCOOTUI_REDIS_HOST=none ./build/bin/scootui

SCOOTUI_REDIS_HOST=none disables Redis and activates the built-in simulator.

Target (cross-compile for i.MX6 armhf)

./cross-build.sh [Release|Debug]

Produces deploy-armhf/ with binary, Qt plugins, and launcher. Deploy:

scp -r deploy-armhf/* target:/opt/scootui/
ssh target /opt/scootui/run-scootui.sh

Make shortcuts

make build    # Configure and build
make run      # Build and run
make clean    # Remove build directory

Environment Variables

Variable Default Description
SCOOTUI_REDIS_HOST 192.168.7.1 Redis host. none = simulator mode. Supports host:port.
SCOOTUI_RESOLUTION 480x480 Display resolution (WIDTHxHEIGHT)
SCOOTUI_SETTINGS_PATH (none) Path to persistent settings file

Redis Operations

Subscriptions (pub/sub + periodic HGETALL)

Channel Store Poll interval
engine-ecu EngineStore 200 ms
vehicle VehicleStore, AutoStandbyStore 500–1000 ms
buttons VehicleStore, ShortcutMenuStore event-driven
battery:0, battery:1 BatteryStore 30 s
gps:tpv (pub/sub) + gps hash GpsStore push + 5 s safety poll
motion:heading (5 Hz) + motion:sensors (10 Hz) pub/sub + motion hash MotionStore push + 5 s safety poll
ble BluetoothStore 5 s
internet InternetStore 5 s
modem ModemStore 5 s
navigation NavigationStore 5 s
settings SettingsStore 5 s
ota OtaStore 5 s
usb UsbStore 5 s
speed-limit SpeedLimitStore 5 s
cb-battery CbBatteryStore 30 s
aux-battery AuxBatteryStore 30 s
dashboard DashboardStore 500 ms

Additionally polled (no subscription): system, version:mdb, version:dbc (30 s).

HSET Writes

Hash Field Value When
dashboard ready true Startup and every Redis reconnect
dashboard serial-number Hardware serial Startup (if readable)
dashboard backlight-enabled true/false On backlight control
navigation latitude, longitude, address, timestamp, destination lat/lon (6 dp), address string, ISO-8601 UTC, lat,lon When the rider picks a destination in the UI (then publishes navigation = updated)
settings dashboard.* user values On settings changes via menu
settings updates.{mdb,dbc}.channel, .method, .check-interval user values Settings > System > Updates; channel only after confirmation
usb mode normal/ums-by-dbc On USB mode change

Note: scootui is not consume-only on the navigation hash. When the rider sets a destination in the UI, NavigationService writes the destination fields above and publishes navigation = updated; clearing the destination blanks the same fields and publishes navigation = cleared.

LPUSH Commands

List Commands Written by
scooter:blinker left, right, both, off Blinker/hazard controls
scooter:hop-on engage, engage-learning, release HopOnStore
scooter:update:{mdb,dbc} check-now, preview-channel:<channel> Settings > System > Updates

HDEL

  • navigation destination, latitude, longitude, address, timestamp — on destination clear

LRANGE

  • usb:log (indices 0–19) — UMS transfer log, polled while usb status is processing

Settings

Settings are stored in the settings Redis hash. Managed by settings-service.

Key Values Default Description
dashboard.show-raw-speed true/false false Raw ECU speed vs wheel-corrected
dashboard.show-gps always/active-or-error/error/never error GPS icon visibility
dashboard.show-bluetooth always/active-or-error/error/never active-or-error Bluetooth icon
dashboard.show-cloud always/active-or-error/error/never active-or-error Cloud connection icon. Only shown when internet[unu-cloud] is present (a cloud client is running); hidden on de-clouded scooters
dashboard.show-internet always/active-or-error/error/never active-or-error Cellular icon. active-or-error shows when internet[connectivity] is connected/disconnected/failed, hides on disabled/no-sim/denied
dashboard.show-clock always/date-time/alternate/never always Clock format and visibility
dashboard.theme light/dark/auto auto UI theme
dashboard.blinker-style icon/overlay icon Blinker indicator style
dashboard.language en, de, … en UI language
dashboard.battery-display-mode percentage/range/icon percentage Battery display
dashboard.power-display-mode kw/amps kw Power unit
dashboard.mode speedometer/navigation/debug speedometer Default screen
dashboard.map.type online/offline offline Map source
dashboard.map.render-mode vector/raster vector Offline map rendering
dashboard.map.traffic-overlay true/false false Traffic overlay (online only)
dashboard.valhalla-url URL http://127.0.0.1:8002/ Valhalla routing endpoint
dashboard.maps.check-for-updates true/false false Auto-check for map updates
dashboard.maps.auto-download true/false false Auto-download map updates
dashboard.milestone-celebrations true/false false Confetti + banner when passing a 500 km odometer milestone or an easter-egg number. Off suppresses all milestone output (including easter eggs)
dashboard.hop-on-combo pipe-delimited tokens (empty) Custom hop-on unlock combo

Settings > System > Updates also writes the update-service keys. Each entry writes both components at once, so the two boards never end up on different channels:

Key Values Description
updates.{mdb,dbc}.channel stable/testing/nightly Release channel. Written only after the rider confirms on the channel-switch screen
updates.{mdb,dbc}.method delta/full Update type
updates.{mdb,dbc}.check-interval duration, 0 to disable How often to look for updates

Neither of the two entries that write these applies on the tap that lands on it: Change Update Type and Switch Release Channel both open a list of checkable rows, because a single stray brake tap on a cycle would have turned the next update into a full-image download with no confirmation. Both rows carry their current value beside the chevron.

The Switch Release Channel entry does not apply a selection directly either. It first pushes preview-channel:<channel> to both scooter:update:mdb and scooter:update:dbc, sums the two ota[preview-size:*] answers, and shows the total on a confirm screen; only confirming writes the setting and pushes check-now to both components. With no connectivity there is nothing to preview and nothing that could download, so the same screen instead explains that the target channel's .mender can be installed over Update Mode. See update-service for the preview protocol.

When dashboard.theme is auto, AutoThemeService drives light/dark switching from the dashboard hash field brightness (lux). It listens on the dashboard pub/sub channel and also polls every 1 s, and switches with hysteresis (dark below 8 lux, light above 20 lux) after the reading has held past the threshold for 2.5 s, then locks out the reverse flip for 10 s.

Hardware Interfaces

Serial Number

Primary: /sys/devices/soc0/serial_number

Fallback (OTP fuses): /sys/fsl_otp/HW_OCOTP_CFG0 + HW_OCOTP_CFG1

Boot Animation

On Linux startup:

  1. Fades in framebuffer overlay: imx-overlay-alpha fade 0 255 1000 (skipped on kernel 6.6 imx-drm)
  2. Stops boot animation: systemctl stop boot-animation.service

Shutdown

On SIGTERM or vehicle state → shutting-down: ShutdownStore::forceBlackout() blacks out the display.

Map Tiles

Offline tiles expected at /data/maps/map.mbtiles on the DBC. The app watches /data/maps/ via inotify and reloads map services when the file appears or changes.

What is installed is recorded in /data/maps/metadata.json (region slug, per-artifact SHA-256, upstream publication time, last update check) and mirrored into the maps Redis hash on the MDB. scootui-qt republishes the hash on every Redis reconnect, because the MDB's valkey keeps nothing across a reboot. The same values back the System > Info > Maps screen, so the dashboard and an MDB-side consumer cannot report different things.

Routing tiles live separately at /data/valhalla/tiles.tar, which Valhalla mmaps as its tile_extract and which therefore has to stay an uncompressed seekable tar.

MapDownloadService fetches both from the manifest at downloads.librescoot.org/releases/tiles.json, keyed by region slug. Each region's valhalla entry may carry an optional nested compressed object (codec, url, size, sha256); when it is present and the codec is zstd, the service downloads that instead, verifies its SHA256, and decompresses it into place at install. The parent url, size and sha256 continue to describe the uncompressed tar, so a client that predates the compressed asset keeps working unchanged. Downloads resume via HTTP Range against the artifact actually being fetched; the compressed variant uses its own .part file.

The .mbtiles is not compressed for transport. Its vector tiles are already gzipped per tile, so the archive only compresses by about 1.14x.

Project Structure

src/
  core/           App initialization, environment config
  models/         Data models and enums
  repositories/   Redis (hiredis-based) and in-memory MDB implementations
  stores/         QML-exposed state stores
  services/       System services (navigation, settings, map, input, ...)
  routing/        Valhalla client and route models
  simulator/      Simulator service (desktop mode only)
  l10n/           Translations
qml/
  screens/        Main UI screens
  widgets/        Reusable UI components
  overlays/       Modal overlays (menu, toast, ...)
  simulator/      Simulator panel (desktop mode only)

Dependencies

  • Redis server
  • Qt 6.4+ (Quick, Qml, Svg, Network, Sql, Concurrent)
  • QMapLibre (required on target; optional in desktop mode)
  • hiredis
  • Valhalla routing engine