lsc - Librescoot Control CLI¶
lsc is a command-line interface for controlling and monitoring Librescoot electric scooters via Redis. It provides a convenient, user-friendly interface to all Librescoot services and features.
Overview¶
The lsc tool acts as a bridge between human operators and the Librescoot Redis-based communication system. Instead of manually crafting Redis commands, you can use intuitive commands to:
- Control vehicle state (lock/unlock, hibernate)
- Monitor system status and diagnostics
- Manage OTA updates
- Configure settings
- View logs and events
- Control hardware components
Installation¶
The lsc binary is typically installed to /usr/bin/lsc on Librescoot systems.
Manual installation:
# From the lsc source directory
make build # Build for ARM
make build-native # Build for local platform
# Or manually
GOOS=linux GOARCH=arm GOARM=7 go build -o lsc .
Global Flags¶
All commands support these global flags:
--json- Output in JSON format for automation and scripting--redis-addr <host:port>- Redis server address (default:192.168.7.1:6379)--no-block- Don't wait for state change confirmation (vehicle commands only)
Commands¶
Vehicle Control¶
Control vehicle state and hardware.
# Lock the scooter (also via: lsc lock)
lsc vehicle lock
# Unlock the scooter (also via: lsc unlock)
lsc vehicle unlock
# Force standby without waiting for locks
lsc vehicle force-lock
# Lock and request hibernation
lsc vehicle hibernate
# Open seatbox (also via: lsc open)
lsc vehicle open
Redis operations:
- Sends commands to
scooter:statelist (lock, unlock, force-lock, lock-hibernate) - Sends commands to
scooter:seatboxlist (open) - Monitors
vehiclehash for state changes
Power Management¶
Control system power states.
# Show power manager status
lsc power status
# Set power state to run (normal operation, highest priority)
lsc power run
# Set power state to suspend (low power)
lsc power suspend
# Set power state to hibernate (power off)
lsc power hibernate
# Hibernate for a specific duration; nRF52 wakes the iMX6 afterwards
lsc hibernate-for 8h
lsc power hibernate-for 30m # equivalent
# Cancel a pending hibernate-for and disarm the wake timer
lsc hibernate-cancel
lsc power hibernate-cancel # equivalent
# Reboot the system
lsc power reboot
Schedule a recurring hibernation via the settings interface:
lsc settings set pm.scheduled-hibernate-cron "0 22 * * *"
lsc settings set pm.scheduled-hibernate-duration 8h
lsc settings set pm.scheduled-hibernate-enabled true
Redis operations:
- Sends commands to
scooter:powerlist - Reads from
power-managerhash
Service Management¶
Manage systemd services with convenient shorthand names.
# List all services with status
lsc service list
lsc svc list # Short alias
# Start/stop/restart a service
lsc svc start vehicle
lsc svc stop battery
lsc svc restart ecu
# Enable/disable service on boot
lsc svc enable alarm
lsc svc disable modem
# Show service status
lsc svc status pm
# View service logs
lsc svc logs vehicle
lsc svc logs battery --follow # Follow in real-time (-f)
lsc svc logs valkey --lines 100 # Show 100 lines (-n 100)
Service name shortcuts (from serviceNameMap in cmd/lsc/service/service.go;
a name with no entry is passed through with .service appended):
vehicle→librescoot-vehicle.servicebattery→librescoot-battery.serviceecu→librescoot-ecu.servicemodem→librescoot-modem.servicealarm→librescoot-alarm.servicesettings→librescoot-settings.servicekeycard→librescoot-keycard.serviceboot-led→librescoot-boot-led.servicebluetooth→librescoot-bluetooth.serviceums→librescoot-ums.servicebrightness→librescoot-brightness.serviceonboot→librescoot-onboot.servicebacklight→dbc-backlight.servicepm→librescoot-pm.serviceupdate→librescoot-update.serviceversion→librescoot-version.servicenetconfig→librescoot-netconfig.service
The datastore alias is special-cased: lsc asks systemd whether
valkey.service is loaded and uses it if so, falling back to redis.service.
Both shorthands hit whichever unit the image actually ships, so a script
written against either name works on both sides of the Librescoot 1.2 switch.
lsc service list shows the resolved name in its first row.
Older lsc builds (up to and including v0.6.6) had no such resolution: redis
resolved literally, so the datastore row read inactive / not-found on 1.2
images and status, restart and logs failed for it.
System integration:
- Uses
systemctlcommands via D-Bus - Uses
journalctlfor log retrieval
LED Control¶
Control LED cues and fade animations.
# Trigger LED cue by index
lsc led cue <index>
# Trigger LED fade animation
lsc led fade <channel> <index>
Redis operations:
- Sends commands to
scooter:led:cuelist - Sends commands to
scooter:led:fadelist
Battery Diagnostics¶
View detailed battery information.
# Show all batteries
lsc battery
lsc bat # Short alias
# Show specific battery
lsc battery 0
lsc bat 1
# JSON output for scripting
lsc battery --json
Redis operations:
- Reads from
battery:0andbattery:1hashes
GPS Tracking¶
Monitor GPS status and location.
# Show GPS status
lsc gps status
# Watch GPS location in real-time
lsc gps watch
# JSON output
lsc gps status --json
Redis operations:
- Reads from
gpshash - Subscribes to
gpschannel for real-time updates
Alarm System¶
Control the motion-based alarm system.
# Check alarm status
lsc alarm status
# Enable the alarm
lsc alarm arm
# Disable the alarm
lsc alarm disarm
# Manually trigger the alarm
lsc alarm trigger
Redis operations:
- Sends commands to
scooter:alarmlist (enable, disable, start, stop) - Reads from
alarmhash - Reads from
settingshash (alarm.enabled, alarm.honk)
Settings Management¶
View and modify scooter configuration.
# List all settings
lsc settings
# Get a specific setting (also via: lsc get)
lsc settings get alarm.enabled
lsc get scooter.mode
# Set a setting (also via: lsc set)
lsc settings set alarm.honk true
lsc set scooter.speed_limit 25
# Delete a setting (also via: lsc del)
lsc settings del custom.field
lsc del custom.field
Common settings:
alarm.enabled- Enable/disable alarm system (true/false)alarm.honk- Enable horn during alarm (true/false)alarm.duration- Alarm duration in secondsalarm.seatbox-trigger- Trigger alarm on unauthorized seatbox opening (true/false)alarm.hairtrigger- Enable hair trigger mode (true/false)alarm.hairtrigger-duration- Hair trigger alarm duration in secondsscooter.speed_limit- Speed limit in km/hscooter.mode- Drive mode (eco/sport)cellular.apn- Cellular APN configurationupdates.mdb.channel- MDB update channel (stable/testing/nightly)updates.dbc.channel- DBC update channel
Redis operations:
- Reads/writes
settingshash - Publishes to
settingschannel for changes
OTA Updates¶
Manage over-the-air updates.
# View OTA update status
lsc ota status
# Install update from local file
lsc ota install /path/to/update.mender
# Install update from URL
lsc ota install https://example.com/update.mender
# JSON output
lsc ota status --json
Redis operations:
- Reads from
otahash (status:mdb, status:dbc, download-progress, etc.) - Sends commands to
scooter:updatelist (check-now)
Diagnostics¶
System diagnostics and fault monitoring.
# Show firmware versions (also via: lsc ver)
lsc diag version
lsc version
# Show active faults (also via: lsc faults)
lsc diag faults
lsc faults
# View fault event stream (also via: lsc events)
lsc diag events
lsc events
# Follow events in real-time
lsc events --follow
# Show events since duration
lsc events --since 1h
lsc events --since 24h
lsc events --since 7d
# Filter events by regex
lsc events --filter "battery.*"
# Control blinkers
lsc blinkers off
lsc blinkers left
lsc blinkers right
lsc blinkers both
# Control horn
lsc diag horn on
lsc diag horn off
# Control handlebar lock
lsc diag handlebar lock
lsc diag handlebar unlock
Redis operations:
- Reads firmware versions from the
systemhash - Reads from
vehicle:fault,battery:0:faultsandbattery:1:faultssets - Reads from
events:faultsstream using XREAD - Sends commands to
scooter:blinker,scooter:horn,scooter:handlebarlists
Hardware Control¶
Direct hardware control commands.
# Control dashboard power (also via: lsc dbc)
lsc dashboard on
lsc dashboard off
lsc dbc on
lsc dbc off
# Control engine power (also via: lsc engine)
lsc engine on
lsc engine off
Redis operations:
- Sends commands to
scooter:hardwarelist (dashboard:on, dashboard:off, engine:on, engine:off)
Status Overview¶
Get overall system status.
Shows summary of:
- Vehicle state
- Motor status (speed, odometer, temperature)
- Battery status for all batteries
- Power manager state
- GPS status
- Internet connectivity
- Active faults
Real-time Monitoring¶
Monitor Redis pub/sub channels and record metrics.
Redis operations:
- Subscribes to all channels and displays real-time updates
- Samples and logs metrics at intervals
Log Extraction¶
Collect service journals, dmesg and a Redis snapshot into one archive.
# All services, last 24h, into /data/log-bundles
lsc logs
# One service, shorter window
lsc logs vehicle --since 1h
# Several services, explicit window and destination
lsc logs battery ecu --since 24h --output /data/debug
# Errors only
lsc logs all --priority err
Flags:
--since <time>- Start of the journal window, default24h. Bare durations (30m,1h,1d,2w) are rewritten to journalctl's "N units ago"; anything containing a space,-or:is passed through as an absolute timestamp--until <time>- End of the window, default now--priority <level>- journalctl priority filter (err,warning,info,debug)--output <dir>- Where the archive is written, default/data/log-bundles
Service names (from serviceMap in cmd/lsc/logs/logs.go; unknown names are
skipped with a warning): vehicle, battery, ecu/motor, modem,
pm/power, update, settings, keycard, bluetooth/ble, ums,
radio-gaga/uplink, all (the default).
One logs-<timestamp>.tar.gz lands in the output directory. The tree is staged
in a .staging-<timestamp> sibling and removed once the archive is written:
logs-2025-10-25-13-54/
metadata.json bundle format 2: collected_at, since, until, hosts, tool, services, priority
mdb/
metadata.json hostname, boot_timestamp, uptime_seconds, kernel_release, os_release_*, byte counts
dmesg.log
librescoot-vehicle.log one journalctl dump per requested service, short-monotonic format
librescoot-battery.log
redis/
vehicle.json one HGETALL snapshot per hash, ':' becomes '-' in the filename
battery-0.json
version-mdb.json
Redis operations:
- HGETALL over
settings,vehicle,gps,battery:0,battery:1,aux-battery,cb-battery,engine-ecu,power-manager,modem,internet,alarm,ble,system,dashboard,ota,power-mux,version:mdb,version:dbc. A hash that is missing or empty writes no file
redis/events-faults.log is the fault history, oldest entry first:
# events:faults (Redis stream, oldest first)
# stream-id time-utc event group code description
1761400443123-0 2025-10-25T13:54:03.123Z RAISE vehicle 3 CAN bus timeout
1761400500456-0 2025-10-25T13:55:00.456Z CLEAR vehicle 3
The time comes from the millisecond component of the entry ID, the only clock
the stream carries. A clear is stored as the raised code with a leading minus
and renders as CLEAR against the code it refers to. Missing fields print -.
The file is always written. A scooter that raised no faults this boot has no
events:faults key at all, and that case gets the two header lines plus
# no fault events recorded, so an empty history stays distinguishable from a
capture that failed. The entry count also lands in mdb/metadata.json as
fault_events.
Saved Locations¶
Manage GPS location bookmarks (if supported by implementation).
JSON Output Mode¶
All commands support --json flag for automation:
# Get structured output
lsc status --json | jq '.vehicle.state'
lsc battery --json | jq '.[0].charge'
lsc settings --json | jq '.["alarm.enabled"]'
# Check if alarm is enabled
if [ "$(lsc get alarm.enabled --json | jq -r .value)" = "true" ]; then
echo "Alarm is enabled"
fi
# Get battery charge percentage
CHARGE=$(lsc bat 0 --json | jq '.charge')
echo "Battery charge: $CHARGE%"
Shell Completion¶
Generate completion scripts for your shell:
# Bash
lsc completion bash > /etc/bash_completion.d/lsc
source /etc/bash_completion.d/lsc
# Zsh
lsc completion zsh > "${fpath[1]}/_lsc"
# Fish
lsc completion fish > ~/.config/fish/completions/lsc.fish
# PowerShell
lsc completion powershell > lsc.ps1
After installing completion, you can use Tab to autocomplete commands, flags, and arguments.
Common Use Cases¶
Check System Health¶
Lock/Unlock Scooter¶
# Lock (will wait for state change confirmation)
lsc lock
# Unlock
lsc unlock
# Force lock without waiting
lsc lock --no-block
# Lock and hibernate
lsc vehicle hibernate
Configure Alarm¶
# Enable alarm
lsc set alarm.enabled true
# Enable horn during alarm
lsc set alarm.honk true
# Arm the alarm
lsc alarm arm
# Check alarm status
lsc alarm status
Monitor Updates¶
# Check update status
lsc ota status
# Watch for update progress
watch -n 1 lsc ota status
# JSON monitoring
watch -n 1 'lsc ota status --json | jq'
Debugging Services¶
# List all services
lsc svc list
# Check specific service
lsc svc status vehicle
# View logs
lsc svc logs vehicle --follow
# Restart problematic service
lsc svc restart modem
Tracking Location¶
# Show current GPS status
lsc gps status
# Watch location in real-time
lsc gps watch
# Get coordinates in JSON
lsc gps status --json | jq '.latitude, .longitude'
Architecture¶
lsc communicates with Librescoot services via Redis:
Command Pattern¶
Commands are sent using LPUSH to command lists:
State Reading¶
Current state is read from Redis hashes:
State Monitoring¶
Real-time updates via pub/sub:
Event History¶
Historical events via streams:
Error Handling¶
lsc provides clear error messages for common issues:
- Redis connection failed: Check Redis server is running and accessible
- Command timeout: Service may not be running or responding
- Invalid setting: Check setting key spelling and format
- Permission denied: Check user has access to systemd commands
Development¶
Source: github.com/librescoot/lsc
# Build for development
cd lsc
go build -o lsc .
# Build for target (ARM)
make build
# Run tests
go test ./...
# Install
sudo cp lsc /usr/bin/
Related Documentation¶
- Redis Interface - Redis hashes, lists, and channels
- Librescoot Services - Service architecture
- Settings Service - Configuration management
- OTA Updates - Update system