SL400 is an OSGi/Karaf-based integration for the Trotec SL400 sound level meter. It reads live dB values from the device over serial, calculates rolling acoustic metrics, stores incidents, captures short audio clips, analyzes audio hints, and publishes alerts and reports to Matrix.
This project is split into small OSGi bundles so the serial input, runtime logic, storage, reporting, and Matrix integration stay modular and replaceable.
The system can be controlled and queried directly from Matrix. Commands such as !sl400 graph today or !sl400 set threshold 70 can trigger reports, graphs, and configuration changes without needing a separate web frontend.
The runtime can generate PNG graphs showing live values, rolling LAeq values, threshold lines, and reset thresholds. This makes it easy to inspect noise incidents and daily trends directly from Matrix or exported reports.
The runtime can generate FFT spectrum PNGs for captured clips via Matrix commands. This makes it easy to spot dominant frequency bands and overall spectral balance without pulling the raw WAV.
-
Read SL400 measurements from a serial port
-
Decode device frames into structured samples
-
Calculate rolling metrics:
- live dB
- LAeq 1 min
- LAeq 5 min
- LAeq 15 min
- max 1 min
-
Trigger alerts with hysteresis and configurable send modes
-
Store incidents in JSONL
-
Capture audio clips around alert events
-
Generate simple audio hints such as:
- voices / crowd
- wind / rumble
- bass-heavy music
- mechanical / hum
-
Send alerts, status updates, clips, files, and images to Matrix
-
Accept Matrix commands for querying and changing configuration
-
Generate daily summaries, JSON exports, and incident graphs
-
Package the whole stack as a Karaf feature
Public API bundle shared by the other modules.
Contains:
-
data records such as
Sl400Sample,AcousticMetrics,IncidentRecord -
service interfaces such as:
Sl400SourceIncidentRepositoryMatrixPublisherAlertConfigServiceMatrixConfigServiceLiveStateServiceAudioStatusService
Use this module if you want to implement your own storage, transport, or source bundle.
Pure logic bundle.
Contains:
Sl400Decoderfor turning raw SL400 serial frames into samplesAcousticMetricsEnginefor rolling LAeq/max calculationsAlarmEvaluatorfor threshold logic with hysteresis and interval control
This bundle has no OSGi DS components by itself. It is intended to be reused by runtime bundles.
Serial source implementation using jSerialComm.
Provides:
Sl400Source
Reads data from the configured serial port, decodes frames through Sl400Decoder, and forwards samples into the runtime pipeline.
Config PID:
de.drremote.trotecsl400.serial
JSONL-based storage implementation.
Provides:
IncidentRepository
Stores incidents in a line-based JSON file and supports:
- append new incidents
- query by time range
- lookup by incident id
- attach clip path
- attach audio hint
- mark Matrix upload state
- cleanup old incidents and clip files
Config PID:
de.drremote.trotecsl400.storage
Outgoing Matrix sender.
Provides:
MatrixPublisher
Handles:
- text messages
- alert events
- status messages
- file uploads
- image uploads
- audio uploads
- clip reuse via existing MXC URL
This bundle performs direct Matrix HTTP API calls with the JDK HttpClient.
Matrix command parsing and sync client helpers.
Contains:
MatrixSyncClientMatrixCommandProcessor
Supports commands such as:
!sl400 help!sl400 status!sl400 set threshold 70!sl400 incidents since 30m!sl400 summary today!sl400 json yesterday!sl400 report now!sl400 graph since 6h!sl400 clip last!sl400 hint last!sl400 hint incident <id>!sl400 fft last!sl400 fft incident <id>!sl400 audio status
Reporting and export helpers.
Contains:
SummaryFormatterJsonExporterIncidentGraphRenderer
Used by the runtime to generate:
- human-readable summaries
- JSON exports
- PNG incident graphs
Runtime requirement:
sl400-report uses Java2D (BufferedImage, Graphics2D, ImageIO) to render PNG graphs.
On Raspberry Pi / headless Linux this works fine as long as the Java runtime includes the
java.desktop module. If you use a minimized runtime image, make sure java.desktop is present.
Main orchestration bundle.
Provides and coordinates:
- live state updates
- alert evaluation
- Matrix alert sending
- audio clip capture
- audio hint analysis
- Matrix status publishing
- Matrix command handling
- daily reports
- ConfigAdmin-backed services for alert and Matrix config
Important services:
AlertConfigServiceMatrixConfigServiceLiveStateServiceAudioStatusService
Config PIDs:
de.drremote.trotecsl400.alertde.drremote.trotecsl400.matrixde.drremote.trotecsl400.matrix.statusde.drremote.trotecsl400.audio
SL400 device
-> serial port
-> sl400-serial-jserialcomm
-> sl400-core decoder + metrics
-> sl400-runtime
-> alert evaluation
-> JSON incident storage
-> audio capture / hint analysis
-> Matrix publisher
-> reports / graphs / exports
Build everything from the parent project:
mvn clean installIf you deploy to your Maven repository:
mvn clean deployBefore installing this project, first prepare your Karaf base setup as described here:
https://github.com/DoctorRemoteControl/drremote-karaf-setup
That repository contains the required base setup for Karaf, Maven repositories, and common DrRemote feature repositories.
feature:repo-add mvn:de.drremote.trotecsl400/sl400-features/0.1.0-SNAPSHOT/xml/featuresfeature:install sl400feature:repo-list | grep sl400
feature:list | grep sl400
bundle:list | grep trotecsl400PID:
de.drremote.trotecsl400.serial
config:edit de.drremote.trotecsl400.serial
config:property-set port AUTO
config:property-set baudRate 9600
config:property-set dataBits 8
config:property-set stopBits 1
config:property-set parity NONE
config:property-set readTimeoutMs 1000
config:property-set reconnectDelayMs 5000
config:property-set autoDetect true
config:property-set preferredPortHint
config:property-set probeTimeoutMs 1500
config:property-set minSamplesForAutoDetect 2
config:property-set enabled true
config:updatePID:
de.drremote.trotecsl400.storage
config:edit de.drremote.trotecsl400.storage
config:property-set baseDir ${karaf.data}/sl400
config:property-set fileName incidents.jsonl
config:updatePID:
de.drremote.trotecsl400.matrix
config:edit de.drremote.trotecsl400.matrix
config:property-set homeserverBaseUrl https://matrix.example.org
config:property-set accessToken syt_xxxxxxxxxxxxxxxxx
config:property-set roomId !alerts:matrix.example.org
config:property-set deviceId sl400-node-01
config:property-set enabled true
config:updatePID:
de.drremote.trotecsl400.matrix.status
config:edit de.drremote.trotecsl400.matrix.status
config:property-set enabled true
config:property-set publishIntervalMs 60000
config:property-set maxSilenceMs 300000
config:property-set offlineThresholdMs 15000
config:property-set onlyOnChange true
config:property-set statusDbStep 1.0
config:property-set statusRoomId
config:updatePID:
de.drremote.trotecsl400.alert
config:edit de.drremote.trotecsl400.alert
config:property-set enabled true
config:property-set thresholdDb 70.0
config:property-set hysteresisDb 2.0
config:property-set minSendIntervalMs 60000
config:property-set sendMode CROSSING_ONLY
config:property-set metricMode LAEQ_5_MIN
config:property-set allowedSendersCsv @operator:matrix.example.org
config:property-set commandRoomId !commands:matrix.example.org
config:property-set targetRoomId !alerts:matrix.example.org
config:property-set alertHintFollowupEnabled true
config:property-set dailyReportEnabled false
config:property-set dailyReportHour 9
config:property-set dailyReportMinute 0
config:property-set dailyReportRoomId !reports:matrix.example.org
config:property-set dailyReportJsonEnabled true
config:property-set dailyReportGraphEnabled true
config:updatePID:
de.drremote.trotecsl400.audio
config:edit de.drremote.trotecsl400.audio
config:property-set baseDir ${karaf.data}/sl400
config:property-set clipsDirName clips
config:property-set sampleRate 16000
config:property-set channels 1
config:property-set sampleSizeBits 16
config:property-set bufferSeconds 30
config:property-set preRollMs 10000
config:property-set postRollMs 20000
config:property-set preferredMixerName USB
config:property-set autoStart true
config:updateThe command processor listens for m.room.message text messages and reacts to commands starting with !sl400.
Examples:
!sl400 help
!sl400 status
!sl400 config
!sl400 set enable true
!sl400 set threshold 70
!sl400 set hysteresis 2
!sl400 set metric laeq5
!sl400 set mode crossing
!sl400 set interval 60000
!sl400 set dailyreport true
!sl400 set reporttime 09:00
!sl400 set reportroom !reports:matrix.example.org
!sl400 set reportjson true
!sl400 set reportgraph true
!sl400 set alerthint true
!sl400 incidents today
!sl400 incidents yesterday
!sl400 incidents since 30m
!sl400 incidents between 2026-03-27T18:00 2026-03-27T23:00
!sl400 summary today
!sl400 summary since 6h
!sl400 json yesterday
!sl400 graph since 24h
!sl400 report now
!sl400 clip last
!sl400 clip incident 1743360000000-550e8400-e29b-41d4-a716-446655440000
!sl400 clips since 2h
!sl400 hint last
!sl400 hint incident 1743360000000-550e8400-e29b-41d4-a716-446655440000
!sl400 fft last
!sl400 fft incident 1743360000000-550e8400-e29b-41d4-a716-446655440000
!sl400 audio status
!sl400 audio start
!sl400 audio stop
Alert generation is based on AlertConfig:
-
enabledturns alerting on or off -
thresholdDbdefines the trigger threshold -
hysteresisDbdefines the reset distance below threshold -
metricModechooses which metric is evaluated:LIVELAEQ_1_MINLAEQ_5_MINLAEQ_15_MINMAX_1_MIN
-
sendModecontrols repetition:CROSSING_ONLYPERIODIC_WHILE_ABOVE
-
minSendIntervalMscontrols periodic resend delay
For rolling LAeq modes, alerts are only evaluated when enough window coverage exists.
Each incident can contain:
- incident id
- timestamp
- room id
- metric mode
- metric value
- threshold
- hysteresis
- LAeq metrics
- max 1 min
- time above threshold
- local clip path
- clip uploaded flag
- uploaded Matrix MXC URL
- audio hint
Storage file format:
- JSONL
- default file:
${karaf.data}/sl400/incidents.jsonl
When audio capture is enabled, the runtime can:
- keep a rolling PCM ring buffer
- extract pre-roll and post-roll audio around an incident
- write a WAV file
- analyze the clip
- store a simple audio hint
- upload the clip to Matrix
- remember the resulting MXC URL for reuse
Heuristic hints include:
- low signal / uncertain
- wind / rumble
- bass-heavy music
- voices / crowd
- broad noise
- mechanical / hum
- mixed / uncertain
The runtime can produce:
Human-readable report with:
- number of incidents
- highest incident
- highest LAeq 5 min
- average incident
- time above threshold
- saved clips
- top hints
- top incidents
Pretty-printed incident export file.
PNG graph with:
- metric values over time
- LAeq 5 min series
- threshold line
- reset (threshold - hysteresis) line
The daily report service sends a report for yesterday at the configured hour/minute.
The last report date is persisted to ${karaf.data}/sl400/daily-report-last.txt to avoid duplicates after restarts.
-
Java target: Java 21
-
Packaging:
- regular modules use
jar - features module uses
feature
- regular modules use
-
OSGi metadata is generated with bnd-maven-plugin
-
Declarative Services components are used throughout runtime, serial, storage, and Matrix sender bundles
-
Install the
sl400feature -
Configure serial, storage, Matrix, alerting, and audio
-
Start with Matrix disabled until serial input works
-
Verify that samples arrive from the SL400
-
Enable Matrix output
-
Test commands in the configured command room
-
Trigger a threshold event and verify:
- incident written
- Matrix alert sent
- clip created
- hint stored
- optional report output
Current artifact version in the provided modules:
0.1.0-SNAPSHOT
Main Karaf feature:
sl400
Main feature repository artifact:
mvn:de.drremote.trotecsl400/sl400-features/0.1.0-SNAPSHOT/xml/features
MIT
