DTS238-7 W (older firmware, manufactured 2020-01) - different protocol/data format
Hardware
- Device: DTS238-7 W (3-phase energy meter with WiFi)
- Manufacturing date: January 2020 (from label)
- Original firmware: WISEN app (older version)
- ESP chip: ESP8285 (flashed with ESPHome 2026.4.5)
- Component version: 1.1.1000
Problem
Older hardware (pre-2021) uses a different communication protocol than what the current dxs238xw component expects. The device communicates but measurement sensors (voltage, current, power, frequency) remain unknown.
What works
- WiFi connection and ESPHome API

meter_state_detail= "Power Ok"
phase_count= 3
max_voltage_limit,min_voltage_limit,max_current_limit
meter_staterelay switch (read-only, ON state detected)
import_active_energy= 281.96 kWh
(parsed from spontaneous message)
What does NOT work
- Voltage / current / power / frequency sensors → Unknown
- Relay control (SET_POWER_STATE cmd=0x09 is ignored by older firmware)
- GET_MEASUREMENT request (cmd=0x0A) returns only echo, no measurement data
Protocol differences (older firmware)
Message types received
The device spontaneously sends only two message types — it does NOT respond to GET requests with data:
cmd=0x08 (25 bytes) — sent every ~5 seconds:
48.19.01.01.08.00.FA.00.C8.29.04.00.00.00.00.00.00.00.00.00.00.03.E8.00.45
Parsed correctly: max_voltage=250V, min_voltage=200V, max_current=105A
cmd=0x0B (67 bytes) — sent sporadically (observed once after SET command):
48.43.01.01.0B.00.00.0C.00.00.09.00.00.08.09.0D.09.0E.09.0D.00.00.00.00.00.00.00.00.00.00.00.00.00.00.10.00.00.0B.00.00.00.00.00.00.00.E5.01.88.03.E8.03.E8.13.83.00.00.6E.24.00.00.6E.24.00.00.00.00.11
cmd=0x0B data format (67 bytes, different from newer firmware)
Older firmware uses little-endian 16-bit values with different byte offsets:
| Value | Offset | Format | Scale | Result |
|---|---|---|---|---|
| voltage_L1 | d[9..10] | LE16 | ×0.1 | 230.4 V |
| voltage_L2 | d[13..14] | LE16 | ×0.1 | 231.2 V |
| voltage_L3 | d[15..16] | LE16 | ×0.1 | 231.7 V |
| current_L1 | d[7..8] | LE16 | ×0.01 | 0.12 A |
| current_L2 | d[11..12] | LE16 | ×0.01 | 0.00 A |
| current_L3 | d[19..20] | LE16 | ×0.01 | 0.13 A |
| active_power_total | d[34..35] | LE16 | ×1 | 16 W |
| frequency | d[51..52] | LE16 | ×0.01 | 50.96 Hz |
| import_active_energy | d[56..57] | BE16 | ×0.01 | 281.96 kWh |
| total_energy | d[60..61] | BE16 | ×0.01 | 281.96 kWh |
Note: All three L1/L2/L3 inputs were connected to the same phase (L1) during testing, so all voltage readings are expected to be ~230V.
CRC differences
Older firmware sends confirmation messages (6 bytes) with a different/incorrect CRC value. The component rejects these as "CRC check failed". Workaround: skip CRC check for confirmation messages.
Confirmation echo
Older firmware echoes the sent command (6 bytes, type=0x02) immediately. The component expected type=0x01 for answers, causing "WRONG_BYTES_TYPE_MESSAGE" errors.
GET_MEASUREMENT behavior
- Sending cmd=0x0A (GET_MEASUREMENT) returns only a 6-byte echo
- Measurement data (cmd=0x0B, 67 bytes) is sent spontaneously by the device, not as a response to GET requests
- cmd=0x0B was observed once after sending a SET_POWER_STATE (cmd=0x09) command
Relay control
- SET_POWER_STATE (cmd=0x09) is sent but the relay does NOT activate
- The device acknowledges the command with an echo but ignores it
Suggested fix
Add detection of older firmware based on message length (67 bytes for cmd=0x0B vs 66 bytes for newer firmware) and use the correct little-endian parsing offsets. A prototype patch is available that detects the message length and switches between parsing modes:
case HEKR_CMD_RECEIVE_MEASUREMENT: {
if (receive_array[1] == 67) {
// Older firmware (little-endian format)
#define LE16(a, i) ((a)[(i)] + ((a)[(i)+1] << 8))
UPDATE_SENSOR_MEASUREMENTS(voltage_phase_1, LE16(receive_array, 9) * 0.1)
UPDATE_SENSOR_MEASUREMENTS(voltage_phase_2, LE16(receive_array, 13) * 0.1)
UPDATE_SENSOR_MEASUREMENTS(voltage_phase_3, LE16(receive_array, 15) * 0.1)
UPDATE_SENSOR_MEASUREMENTS_CURRENT(current_phase_1, LE16(receive_array, 7) * 0.01)
UPDATE_SENSOR_MEASUREMENTS_CURRENT(current_phase_2, LE16(receive_array, 11) * 0.01)
UPDATE_SENSOR_MEASUREMENTS_CURRENT(current_phase_3, LE16(receive_array, 19) * 0.01)
UPDATE_SENSOR_MEASUREMENTS_POWER(active_power_total, LE16(receive_array, 34) * 1.0)
UPDATE_SENSOR_MEASUREMENTS(frequency, LE16(receive_array, 51) * 0.01)
UPDATE_SENSOR_MEASUREMENTS(import_active_energy, ((receive_array[56] << 8) | receive_array[57]) * 0.01)
UPDATE_SENSOR_MEASUREMENTS(total_energy, ((receive_array[60] << 8) | receive_array[61]) * 0.01)
#undef LE16
} else {
// Newer firmware (existing big-endian parsing)
// ... existing code ...
}
break;
}
Open questions
- What is the correct command to trigger measurement data on older firmware?
- What is the correct command to control the relay on older firmware?
- Are there other byte offsets in the 67-byte cmd=0x0B message that we haven't identified yet (per-phase power, power factor, reactive power)?
ESPHome log excerpt
[I][dxs238xw]: * CMD=0x08 len=25 raw: 48.19.01.01.08.00.FA.00.C8.29.04... (25)
[I][dxs238xw]: * CMD=0x0B len=67 raw: 48.43.01.01.0B.00.00.0C.00.00.09... (67)