DL/T645 Driver
dc3-driver-dlt645 reads electricity meters speaking the Chinese DL/T645-2007 protocol over RS485. It builds the meter request frame (68H ... 16H), verifies the response checksum, and parses the data identifier (DI0-DI3) value; writes use the DL/T645 operator codes for meter programming.
Protocol background
DL/T645-2007 is the Chinese national standard for multi-function electricity meters. Frames are delimited by 68H, carry a 6-byte BCD meter address, and end with a cumulative checksum. Each measured quantity (voltage, current, power, energy) is addressed by a 4-byte data identifier DI0-DI3.
- Driver name / code:
DL/T645 Driver/Dlt645Driver - Type:
DRIVER_CLIENT (opens the serial port and polls the meter) - Underlying library: jSerialComm (self-built DL/T645-2007 frame encode/decode)
Attribute configuration
Driver attributes (device-level driver-attribute)
| Attribute | code | Type | Default | Description |
|---|---|---|---|---|
| Serial Port | port | STRING | /dev/ttyUSB0 | Serial port device path |
| Baud Rate | baudRate | INT | 2400 | Baud rate (DL/T645 default 2400) |
| Data Bits | dataBits | INT | 8 | Data bits |
| Stop Bits | stopBits | INT | 1 | Stop bits |
| Parity | parity | INT | 2 | Parity (2=Even, DL/T645 default) |
| Timeout | timeout | INT | 1000 | Read timeout in milliseconds |
| Meter Address | meterAddress | STRING | 000000000000 | 12-digit BCD meter address |
| Write Password | password | STRING | 00000000 | Meter password for writes |
| Operator Code | operatorCode | STRING | 00000000 | Operator code for writes |
Point attributes (point-attribute)
| Attribute | code | Type | Default | Description |
|---|---|---|---|---|
| Data Identifier | di | STRING | 00010000 | 4-byte data identifier as 8 hex chars (DI0-DI3; default = total active energy) |
| Data Format | dataFormat | STRING | HEX | HEX, BCD, INT, FLOAT, ASCII |
Command attributes (command-attribute)
| Attribute | code | Type | Default | Description |
|---|---|---|---|---|
| Data Identifier | di | STRING | 00010000 | Data identifier for writes (DI0-DI3, 8 hex chars) |
| Data Format | dataFormat | STRING | HEX | Encoding for the written value: HEX, BCD, INT, FLOAT, ASCII |
The write path does not read this table
write() takes di and dataFormat from the point attributes and meterAddress / password / operatorCode from the device attributes; the two command attributes above are only registered in the driver's application.yml and are not consumed by write(). To change write behavior, edit the point attributes.
Collection and health
- Collection cycle: default cron
0/30 * * * * ?(one polling round over all points every 30 seconds). - Health/online: device health defaults to cron
0/15 * * * * ?, lease timeout45 seconds.
Capability matrix
| Capability | Supported | Notes |
|---|---|---|
| Read | ✓ | |
| Write | ✓ | |
| Subscribe | — |
Implementation status: complete
The frame encoder/decoder (Dlt645Frame) and serial connection (Dlt645SerialPortConnection) are fully implemented, including address BCD encoding, checksum verification, and read/write frame building.
Troubleshooting
Serial devices fail at the physical layer first — match the symptom before touching anything else.
Failed to open serial port only means the port did not open
A wrong path, missing permissions for the driver process, or another program holding the port (a serial terminal, another driver instance) all make openPort() return false and raise a ConnectorException. In container deployments, also verify the serial device is actually mounted into the container.
- Symptom:
Invalid DL/T 645 meter addressorInvalid hexadecimal value→ cause:meterAddressmust be 12 decimal digits;di,passwordandoperatorCodemust each be 8 hexadecimal characters. Wrong length or characters are rejected before any frame is built. Check: pad with leading zeros against the meter nameplate; never use A-F inmeterAddress. - Symptom:
Empty DL/T 645 responsekeeps recurring and the connection keeps being rebuilt → cause: the meter is not answering — wrong meter address, baud rate or parity mismatching the meter's settings, or swapped A/B lines on the RS485 bus. An empty response raises aReadPointExceptionand invalidates the connection; the next cycle reopens the port and fails the same way. Check: send a read request by hand with a serial tool at the same settings, then verifymeterAddress,baudRateandparity. - Symptom: reads throw
Unexpected DL/T 645 response control code, or writes return failure → cause: the meter answered with a non-normal frame. Reads only accept the read-response control codes0x91/0xB1(with follow-up); anything else throws. A write only counts as success when the response control code is0x94— a wrong password or operator code, or a data identifier that is not writable, makes the meter return an error frame and the write return false without an exception. Check: confirmdiexists in the meter's data identifier table; verifypassword/operatorCodeagainst the meter's communication parameters. - Symptom:
checksum mismatch/response too short/invalid frame delimiters→ cause: a truncated or corrupted response frame — typically mismatched serial parameters, bus interference, or atimeouttoo short to receive the full frame. Check: recheck the serial parameters; raise the device attributetimeoutif needed. - Symptom: values arrive but the magnitude is obviously wrong → cause:
dataFormatdoes not match the actual encoding of that data identifier. The driver decodes purely by the point'sdataFormat; display-style identifiers (XXX.X) on meters are usually BCD, and configuring FLOAT yields garbage. Check: look up the DI's encoding and fix the point attribute. - Symptom: the device shows online but no values ever arrive → cause: the health check only tests whether the serial handle is still open, not whether the meter answers; read failures only surface in the driver log. Check: search the driver log for
ReadPointExceptionand match it against the list above.
How it lands in IoT DC3
One DL/T645 meter is one Device in the platform: the serial parameters (port / baudRate / dataBits / stopBits / parity / timeout) and the meter address (meterAddress) all live on device attributes, and the driver keeps one serial connection per deviceId, opened lazily on the first read, write or health check. The protocol itself is a one-master, many-slaves polling model on an RS485 bus, addressed by the 6-byte BCD meter address; one device carries exactly one meter address, so a bus with several meters means several devices, each with its own meterAddress.
The read path: the scheduler calls read() per point every 30 seconds by default. The driver builds a control-code 0x11 read-data request from the point attribute di, sends it on the serial port, verifies the checksum, reverses the +0x33 offset on each data byte, then formats the bytes into a string using the point attribute dataFormat (BCD / INT / FLOAT / ASCII / HEX) and hands it back as a PointValue. The write path reuses the same point attributes: write() locates the data identifier by the point's di, encodes the value per dataFormat, takes meterAddress / password / operatorCode from device attributes to build a control-code 0x14 write-data frame, and succeeds when the response control code is 0x94 (the command attributes are not consumed by write(), see the warning above); execute() is not implemented in this driver, so custom commands return the interface default — an empty map.
The connection is self-healing: any exception on the read path closes and removes that device's serial connection, and the next cycle reopens it; deleting or updating the device closes the old connection through a metadata event. Online state rides the health check plus the lease: the health check runs every 15 seconds by default and only confirms the serial handle is open, with a 45-second lease timeout — see Device. Alarms and automation trigger on the platform side from point values; the driver registers no event attributes, matching the "Subscribe —" row in the capability matrix.
Minimal onboarding example
- Create a Device using
DL/T645 Driver, setport=/dev/ttyUSB0,baudRate=2400,parity=2,meterAddress=<your 12-digit address>. - Add a Point (
READ_ONLY) withdi=02010100(phase A voltage) anddataFormat=FLOAT. - Start the driver; within 30 seconds the value appears in PointValue.
Further reading
- Driver overview — entry point to all protocol drivers and selection
- Driver capability matrix — quick reference of read/write/subscribe capabilities
- Device onboarding — a complete onboarding walkthrough