SL651 Driver
dc3-driver-sl651 connects SL651-2014 hydrological telemetry stations to IoT DC3: it listens on a TCP port, passively receives telemetry reports pushed by remote stations, and turns the element at a configured position in the report body into a PointValue. After reading this page you will understand how it differs from a polling driver, how to fill in the driver and point attributes correctly, and how to troubleshoot the classic " reports arrive but no point values" problem.
Protocol background
SL651-2014 is the PRC water-conservancy industry standard Hydrological Monitoring Data Communication Protocol, used for data communication between telemetry terminals (RTUs) — rain gauges, water-level stations, flow stations — and a central station. Its typical use is remote telemetry for basin hydrology, urban waterlogging, reservoirs and dams, and irrigation metering: stations are scattered in the field and use links such as GPRS / 4G / BeiDou to send scheduled or event-triggered hydrological elements back to the center.
Unlike field buses such as Modbus, where the master actively reads slaves, SL651 is a server-side protocol: telemetry stations scattered in the field push their collected data to a central server on their own schedule (on the hour, supplementary reports, alarms, and so on). This driver is that central server — it starts an SL651 TCP server on a listen port, waits for stations to connect and report, parses the telemetry elements out of the report body, matches the station address in the report header to a Device, and forwards the configured element as a point value.
In the four-layer IoT architecture, SL651 sits at the network layer: it defines how station terminals transmit and aggregate sensing-layer data over wide-area links to the platform. It does not specify how sensors measure (perception layer) or how the platform stores and analyzes (application layer); it only governs frame structure, function codes, element encoding, and uplink/downlink exchange. To see where it sits in the protocol spectrum and the trade-offs of " server passively receiving reports" versus a polling model, see the IoT network-layer chapter.
This is a listener driver, not a polling one
Because data arrives asynchronously and unsolicited from the stations, the SDK read / write methods do not participate in collection — by design read returns null and write returns false. Scheduled reads are disabled ( schedule.read.enable: false); the driver keeps only an internal schedule.custom cron and the device health check, and the real collection is triggered by station reports.
Two core terms
- Station address: the address in the SL651 report header that identifies the sender. The driver takes the bytes from
getRemoteStationAddress(), converts them to an uppercase hex string, and matches them against the device'sdeviceCodeordeviceName(case-insensitive). - Telemetry element: an ordered list of measured values in one report body (water level, rainfall, voltage, …). The driver collects every report body's
getBodyElements()into one ordered list, and a Point picks one of them by its indexindex.
Attribute configuration
Onboarding an SL651 station involves attributes at two levels: driver attributes (driver-attribute, which decide how the server listens) and point attributes (point-attribute, which decide which element to take from the report body). All come from the driver's application.yml, mapping to the dc3.driver.sl651.port / dc3.driver.sl651.pwd config keys and the point config index. The values are filled in on the Device instance; for the three-layer origin of attributes see Attribute and Config.
Driver attributes (device-level driver-attribute)
port decides which TCP port the whole driver process starts the SL651 server on; pwd is the authentication password passed when constructing SL651Server, used for the station's access credential check. Both have defaults and fall back to them when left blank.
| Attribute | code | Type | Default | Description |
|---|---|---|---|---|
| Listen Port | port | INT | 5001 | TCP port the SL651 server listens on |
| Auth Password | pwd | STRING | 0000 | Remote station authentication password |
The port is driver-level and shared by every station in the process
port decides which TCP port the whole driver process listens on; every station reporting to that port shares one server instance. Different stations are distinguished by their station address (i.e. the device's deviceCode / deviceName), not by port. A metadata change (device add / update) triggers restartServer(), and deleting a device calls stopServer().
Point attributes (point-attribute)
Each collected Point needs just one attribute — its index into the report body's element list. When a report arrives from a station, the driver collects all report-body elements into an ordered list in order; the Point's index selects which one to take.
| Attribute | code | Type | Default | Description |
|---|---|---|---|---|
| Element Index | index | INT | 0 | Zero-based index into the telemetry body element list |
index=0 takes the first element, index=1 the second, and so on. Points whose index is out of range (index < 0 or index >= elements.size()) are skipped for that round without error. validatePoint() requires index to be present; the point config fails validation if it is missing.
End-to-end pipeline
At startup startServer() constructs SL651Server via reflection and registers an ISl651MessageListener. Whenever a station reports, the onMessage callback hands the report header's station address (hex string) and the report body's element list to forwardTelemetry(): it iterates the devices under this driver, and for each device whose address matches, iterates its points, takes the value by index, assembles PointValue objects, and forwards them in a batch via driverSenderService.pointValueSender().
Troubleshooting
- Reports arrive but no point values: the most common cause is a station address that does not match the device code. The driver matches the report header's station address (uppercase hex string) against the device's
deviceCodeordeviceName(case-insensitive); a mismatch is silently dropped. First confirm the actualstationAddrreported from the driver log (the DEBUG-levelDriver SL651 message receivedprints it), then copy it verbatim intodeviceCode. - A point reads the wrong value:
indexis a zero-based element-list index whose order is determined by the station configuration; it is not an SL651 identifier code, nor a register address. Verify eachindexagainst the actual element order the station reports — do not guess by unit. - Station cannot connect / authentication fails: confirm the
porton the device matches the station's target port and the network is reachable;pwdmust equal the station's configured access credential (default0000). Changingporttriggers a server restart and a brief disconnect. sl651ApiMissingwarning in the driver log: the runtime is missing theiot-communicationSL651 classes, so the server does not start (Driver SL651 server unavailable). A normal build bundles the dependency; if you trimmed dependencies, add it back.- Device stays offline: the device health check cron is
0/15 * * * * ?with a45 secondlease timeout. If the station's reporting interval exceeds 45 seconds (e.g. hourly or long-interval supplementary reports), being judged offline between two reports is expected; see Device for the online determination. - A misconfigured write command has no effect: this driver's
writereturnsfalseby design, there is nocommand-attribute, and a write command on a Point is never dispatched. For remote control of a station, use the station's own downlink channel; it is outside this driver's scope.
How it lands in IoT DC3
dc3.driver.code:Sl651Driver(driver nameSL651 Hydrological Telemetry Driver, typeDRIVER_CLIENT). This is a stable routing identifier — do not change it casually.- Read / write / subscribe capability: subscribe / report only.
readreturnsnull,writereturnsfalse, scheduled reads are off, and collection is driven entirely by station reports. This matches the driver capability matrix: read —, write —, subscribe ✓. - Collection and health: passive listening with no active read cycle; the driver also has an internal
schedule.customcron0/5 * * * * ?(schedule()is currently a no-op and does not collect). The device health check cron is0/15 * * * * ?with a45 secondlease timeout.
The device code must equal the station address, or the data is dropped
The driver matches the station address (uppercase hex string) in the report header against the device's deviceCode or deviceName (case-insensitive). If they do not match, the report is silently dropped — you will see the driver receiving reports yet no point values. Confirm the address the station actually reports, and copy it verbatim into deviceCode before onboarding.
index is the "Nth element" of the body, not a register address
index is the element-list index the driver parses out, zero-based, matching the order of elements in the station's report one-to-one. It is not an SL651 identifier code, nor any register address. The element order is determined by the station configuration, so confirm which value each index maps to against the station's report content before onboarding.
Implementation status: available (graceful degradation when the server dependency is missing)
The SL651 server is invoked via reflection on the iot-communication library's SL651Server, and the report parsing and forwarding pipeline is complete, so this is an available driver. If the runtime lacks the library's SL651 classes, startServer() logs an sl651ApiMissing warning and skips startup without affecting the rest of the process; a normal build already bundles the dependency.
Minimal onboarding example
Onboard a water-level station with station address 12345678 reporting to local port 5001:
- Create a Device using
SL651 Hydrological Telemetry Driver, and set the device codedeviceCodeto12345678(it must match the address the station reports), with driver attributesport=5001andpwd=0000. - Add a water-level Point to the Profile bound to the device (set
pointTypeFlagto match the reported element's actual type,READ_ONLY), and set the point attributeindex=0(take the first element of the report body). - Start the driver and let the station push data; as soon as the station reports, the matched Point shows up in PointValue.
Further reading
- Driver overview — categories and selection of all drivers
- Driver capability matrix — read / write / subscribe capability per driver
- Device onboarding — a complete onboarding walkthrough
- IoT network-layer chapter — trade-offs of server-side passive ingest vs polling
- Listening Virtual Driver — the same passive-listener, report-triggered collection paradigm