7 in 1 Water quality monitor


Got new multi sensor, but cannot find a driver that work with it.

7in1 Zigbee Water Quality Monitor Smart Home Probe Temperature Humidity Sensor TDS SG Meter EC Salnity Tester For Zigbee2mqtt

https://a.aliexpress.com/_EHyBZYO

04.394

info

Zigbee parsed:[raw:catchall: 0000 0013 00 00 0040 00 9A2B 00 00 0000 00 00 002B9AC9A30F153038C1A480, profileId:0000, clusterId:0013, clusterInt:19, sourceEndpoint:00, destinationEndpoint:00, options:0040, messageType:00, dni:9A2B, isClusterSpecific:false, isManufacturerSpecific:false, manufacturerId:0000, command:00, direction:00, data:[00, 2B, 9A, C9, A3, 0F, 15, 30, 38, C1, A4, 80]]

**dev:1005**2026-08-14 18:07:45.937

info

fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0003,EF00,0001,0500,0101,1000", outClusters:"0003,EF00,1000", model:"Excellux", manufacturer:"DTS1XM9", controllerType: "ZGB"


All help welcome

@kkossev

My go-to these days is to have AI write drivers when there are none. Just the Google Search Gemini AI does pretty well with it now. Your post is almost an AI prompt already, just take that info and add in that you need it to write a Hubitat Elevation Groovy driver for it using that info. Test and cycle back with AI with any errors until it gives you code that works.

I agree; I was about to propose the exact same approach. The information in the first post is already a solid starting prompt for an AI-assisted Hubitat driver.

The important part is validating it with the actual device and refining it from real logs, especially the Tuya EF00 datapoints.

@petteri.joutseno - If you get a first working draft, please share the code; we can help review it.

Looking at this device on Ali, it has two temp readings, one each for the probe and the device, as well as humidity, beyond what would be specific water quality attributes.

It might help to tell AI to make child devices for the temp sensors and humidity sensors, using the built-in generic component temp and humidity drivers, and then have TDS, EC, Salinity, and SG have it's own custom sensor child device. Or put the quality attributes in the parent, then have a child temp device for the probe sensor, and another child device that uses the generic component temp and humidity sensor driver for sensor temp/humidity.

Sometimes you still need to give AI a bit of guidance on how you want it to manage the attribute names and how you want it to use child devices, or use no children at all and stuff it all into one main driver.

How did you get the "Zigbee parsed" and "fingerprint profiled" information to start the AI prompt? Can you please share?

From the logs

How - does that show up in the logs when you first pair the device?

Yes when paired

Here is one from Gemini. Temperature and tds seems to populate fine. This so not chatty that getting those rest measurements will take time. How to enable debug logging?

Cheers

Petteri

/**

* Tuya Zigbee 7-in-1 Water Quality Monitor Driver for Hubitat Elevation

* Model: Excellux | Manufacturer: DTS1XM9

*/

metadata {

definition (name: "Tuya Zigbee 7-in-1 Water Quality Monitor", namespace: "custom", author: "Community") {

    capability "TemperatureMeasurement"

    capability "RelativeHumidityMeasurement"

    capability "Sensor"

    capability "Configuration"

    // Custom attributes for water quality parameters

    attribute "tds", "number"       // Total Dissolved Solids (ppm)

    attribute "ec", "number"        // Electrical Conductivity (us/cm)

    attribute "salinity", "number"  // Salinity (%)

    attribute "sg", "number"        // Specific Gravity

    // Hardware fingerprint matched from your device log

    fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0003,EF00,0001,0500,0101,1000", outClusters: "0003,EF00,1000", model: "Excellux", manufacturer: "DTS1XM9", controllerType: "ZGB"

}

preferences {

    input name: "logEnable", type: "boolean", title: "Enable debug logging", defaultValue: true

}

}

// Device initialization

def installed() {

log.info "Tuya 7-in-1 Water Quality Monitor Installed"

configure()

}

def configure() {

log.info "Configuring device..."

// Tuya devices require a wakeup/initialization command to start reporting data

return \["he raw 0x${device.deviceNetworkId} 1 0x01 0xEF00 {}"\]

}

// Hubitat calls this function whenever the device sends a Zigbee message

def parse(String description) {

if (logEnable) log.debug "parse description: ${description}"



// Safely parse the description into a Map to avoid SmartShield missing property exceptions

def descMap = zigbee.parseDescriptionAsMap(description)

if (logEnable) log.debug "parsed descMap: ${descMap}"



if (descMap) {

    // Tuya EF00 cluster can appear as hex string "EF00" in the map

    if (descMap.cluster == "EF00" || descMap.clusterId == 0xEF00) {

        

        // Get the raw data payload list

        def data = descMap.data

        

        // Tuya data structure: \[status, command, DP_ID, DP_Type, length_high, length_low, data...\]

        if (data && data.size() > 6) {

            // Convert hex string array or list elements safely if needed, assuming standard integer list

            def dp = Integer.parseInt(data\[2\], 16)   // Datapoint ID

            def type = data\[3\]                       // Data type

            

            // Parse 4-byte integer from data payload (elements 6, 7, 8, 9)

            def value = 0

            if (data.size() >= 10) {

                value = (Integer.parseInt(data\[6\], 16) << 24) | 

                        (Integer.parseInt(data\[7\], 16) << 16) | 

                        (Integer.parseInt(data\[8\], 16) << 8)  | 

                        Integer.parseInt(data\[9\], 16)

            }

            

            if (logEnable) log.debug "Tuya DP parsed -> DP: ${dp}, Type: ${type}, Value: ${value}"

            

            // Mapping Datapoints (DP) to Hubitat attributes

            switch (dp) {

                case 1: // Typical Temperature DP

                    def temp = value / 10.0

                    sendEvent(name: "temperature", value: temp, unit: "°C")

                    break

                case 2: // Typical TDS / EC DP

                    sendEvent(name: "tds", value: value, unit: "ppm")

                    break

                // Add more DP cases here as you observe them in live logs

                default:

                    if (logEnable) log.info "Unknown Tuya DP: ${dp} with value ${value}. Please note this down."

                    break

            }

        }

    }

}

}

Hi @petteri.joutseno ,

Try this prompt with Gemini :

I have a Zigbee device paired to a Hubitat Elevation hub that has no driver.
Write me a working Hubitat Groovy driver for it.

Device fingerprint from the Hubitat pairing log:
profileId:"0104", endpointId:"01",
inClusters:"0000,0003,EF00,0001,0500,0101,1000",
outClusters:"0003,EF00,1000", model:"Excellux", manufacturer:"DTS1XM9"

Sold as: "7in1 Zigbee Water Quality Monitor Smart Home Probe - Temperature,
Humidity, TDS, SG, EC, Salinity"

BEFORE writing any code, research it. Do not invent datapoint numbers.
1. Search Zigbee2MQTT (zigbee2mqtt.io/supported-devices) and the
   Koenkk/zigbee-herdsman-converters GitHub repo — including merged and open
   pull requests and issues — for this exact model/manufacturer string. These
   devices are almost always already supported there.
2. Also check ZHA quirks (zigpy/zha-device-handlers) and the Tuya IoT
   developer docs if Z2M has nothing.
3. From whatever converter you find, extract the complete tuyaDatapoints map:
   every DP id, its meaning, data type, scaling divisor, units, enum values,
   and which DPs are writable.
4. Tell me which source you used and paste the datapoint table you found, so I
   can verify it before trusting the driver.

THEN write the driver:
- Port that datapoint map faithfully to Groovy — it is a Tuya EF00 device, so
  parse cluster 0xEF00 commands 0x01/0x02/0x06, handle multiple DPs per
  payload, and read the payload length field rather than assuming 4 bytes.
- Standard capabilities where they fit, custom attributes for the rest.
- Writable DPs exposed as driver commands/preferences.
- Log unknown DPs at info level with the raw hex so I can report gaps.
- Hubitat-specific correctness: preferences use type "bool" (not "boolean"),
  unschedule() in updated(), auto-off for debug logging, include the
  fingerprint line verbatim, and make sure it compiles on Hubitat's Groovy.

If your research turns up nothing at all, say so plainly instead of guessing,
and give me a logging-only driver that dumps every DP it sees.

(This prompt was written by Claude Code)

When I wrote my curtain driver (revised yours) at some point in the conversation with AI, it wrote a DP finder into the code it gave me. That allowed me to feed back the logs to Gemini with the unknown DP, and what action I took (moving the curtain by hand, light sensor tests, etc). It was quite a manual process though. Do something, feed AI the logs, and repeat.

I like your prompt though, it is similar to what I would say.

Verified the Gemini output - it was not good... :frowning:

It did exactly the thing the last paragraph was supposed to prevent: no source cited, no research output, and the datapoint map is invented from start to finish. Not one DP is right.

I asked Claude to fix it - posted below :

/**
 *  Excellux ZG-109TDS - Tuya 7-in-1 Water Quality Monitor
 *
 *  Probe temperature, air temperature, humidity, TDS, EC, salinity, specific gravity.
 *  Model: Excellux   Manufacturer: DTS1XM9
 *
 *  Datapoint map ported from the Zigbee2MQTT converter:
 *  https://github.com/Koenkk/zigbee-herdsman-converters/pull/12294
 *
 *  NOTE: this device has NO pH and NO ORP sensor. Those belong to the
 *  floating pool tester, which is a different product.
 */

metadata {
    definition(name: "Tuya 7-in-1 Water Quality Monitor (ZG-109TDS)", namespace: "community", author: "Community") {
        capability "TemperatureMeasurement"
        capability "RelativeHumidityMeasurement"
        capability "Battery"
        capability "Sensor"
        capability "Refresh"
        capability "Configuration"

        attribute "probeTemperature", "number"      // DP 1   - water probe
        attribute "airTemperature", "number"        // DP 5   - device body sensor
        attribute "tds", "number"                   // DP 124 - ppm
        attribute "ec", "number"                    // DP 127 - uS/cm
        attribute "salinity", "number"              // DP 131 - ppt
        attribute "sg", "number"                    // DP 132 - specific gravity
        attribute "mode", "enum", ["freshwater", "seawater"]
        attribute "samplingInterval", "number"
        attribute "probeTemperatureWarning", "enum", ["none", "low", "high"]
        attribute "temperatureWarning", "enum", ["none", "low", "high"]
        attribute "humidityWarning", "enum", ["none", "low", "high"]
        attribute "tdsWarning", "enum", ["none", "high"]
        attribute "ecWarning", "enum", ["none", "low", "high"]

        command "setMode", [[name: "mode*", type: "ENUM", constraints: ["freshwater", "seawater"]]]
        command "setSamplingInterval", [[name: "seconds*", type: "NUMBER", description: "5..1200, step 5"]]
        command "setProbeTemperatureCalibration", [[name: "offset*", type: "NUMBER", description: "-2.0 .. 2.0 C"]]
        command "setTemperatureCalibration", [[name: "offset*", type: "NUMBER", description: "-2.0 .. 2.0 C"]]
        command "setHumidityCalibration", [[name: "offset*", type: "NUMBER", description: "-10.0 .. 10.0 %"]]
        command "setTdsWarningThreshold", [[name: "ppm*", type: "NUMBER", description: "0 .. 13000 ppm"]]

        fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0003,EF00,0001,0500,0101,1000", outClusters: "0003,EF00,1000", model: "Excellux", manufacturer: "DTS1XM9"
    }

    preferences {
        input name: "temperatureSource", type: "enum", title: "Source for the standard 'temperature' attribute",
              options: ["probe": "Water probe (DP 1)", "device": "Device body (DP 5)"], defaultValue: "probe"
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
        input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
    }
}

// Tuya datapoint types
@groovy.transform.Field static final String DP_TYPE_BOOL  = "01"
@groovy.transform.Field static final String DP_TYPE_VALUE = "02"
@groovy.transform.Field static final String DP_TYPE_ENUM  = "04"

@groovy.transform.Field static final Map WARN3 = [0: "none", 1: "low", 2: "high"]
@groovy.transform.Field static final Map WARN2 = [0: "none", 1: "high"]
@groovy.transform.Field static final Map MODES = [0: "freshwater", 1: "seawater"]

// ---------------------------------------------------------------- lifecycle

void installed() {
    log.info "${device.displayName}: installed"
    state.settingsReported = [:]
}

void updated() {
    unschedule()
    log.info "${device.displayName}: preferences updated"
    if (logEnable) {
        log.info "${device.displayName}: debug logging will auto-disable in 30 minutes"
        runIn(1800, "logsOff")
    }
}

void logsOff() {
    log.info "${device.displayName}: debug logging disabled"
    device.updateSetting("logEnable", [value: "false", type: "bool"])
}

List<String> configure() {
    log.info "${device.displayName}: configuring"
    state.settingsReported = [:]
    List<String> cmds = []
    // The Tuya "magic" read - without it many EF00 devices never start reporting.
    cmds += zigbee.readAttribute(0x0000, [0x0004, 0x0000, 0x0001, 0x0005, 0x0007, 0xFFFE], [:], 200)
    cmds += syncTuyaDateTime()
    cmds += tuyaQuery()
    return cmds
}

List<String> refresh() {
    logDebug "refresh: querying all datapoints"
    return tuyaQuery()
}

// ------------------------------------------------------------------- parse

void parse(String description) {
    logDebug "parse: ${description}"
    Map descMap = zigbee.parseDescriptionAsMap(description)
    if (!descMap) { return }
    logDebug "descMap: ${descMap}"

    if (descMap.clusterInt == 0xEF00 || descMap.cluster == "EF00") {
        String cmd = descMap.command
        if (cmd == "24") {                       // device is asking for the time
            sendZigbee(syncTuyaDateTime())
        }
        else if (cmd in ["01", "02", "05", "06"]) {
            parseTuyaPayload(descMap.data)
        }
        else {
            logDebug "unhandled EF00 command ${cmd}, data=${descMap.data}"
        }
        return
    }

    if (descMap.clusterInt == 0x0000) { return }   // basic cluster, magic-read replies
    logDebug "unhandled cluster ${descMap.cluster}"
}

private void parseTuyaPayload(List<String> data) {
    if (!data || data.size() < 6) {
        logDebug "payload too short: ${data}"
        return
    }
    List<Integer> b = data.collect { Integer.parseInt(it, 16) }

    int i = 2                                     // skip the 2-byte sequence number
    while (i + 4 <= b.size()) {
        int dp     = b[i]
        int type   = b[i + 1]
        int length = (b[i + 2] << 8) | b[i + 3]
        i += 4
        if (i + length > b.size()) {
            log.warn "${device.displayName}: truncated DP ${dp} - need ${length} bytes, have ${b.size() - i}"
            return
        }
        List<Integer> bytes = b.subList(i, i + length)
        i += length
        processDatapoint(dp, type, length, bytes)
    }
}

// Tuya "value" type is a signed big-endian integer.
private long rawValue(List<Integer> bytes) {
    long v = 0
    bytes.each { v = (v << 8) | (it & 0xFF) }
    if (bytes.size() > 0 && (bytes[0] & 0x80)) {   // sign-extend
        v -= (1L << (8 * bytes.size()))
    }
    return v
}

private String hexOf(List<Integer> bytes) {
    return bytes.collect { String.format("%02X", it) }.join("")
}

// -------------------------------------------------------------- datapoints

private void processDatapoint(int dp, int type, int length, List<Integer> bytes) {
    long raw = rawValue(bytes)
    logDebug "DP ${dp} type=${type} len=${length} raw=${raw} bytes=${hexOf(bytes)}"

    switch (dp) {
        case 1:    // probe temperature, /10
            BigDecimal pt = scaled(raw, 10, 1)
            sendNumeric("probeTemperature", convertTemp(pt), tempUnit(), "water probe temperature")
            if ((temperatureSource ?: "probe") == "probe") {
                sendNumeric("temperature", convertTemp(pt), tempUnit(), "temperature")
            }
            break

        case 4:    // battery %
            sendNumeric("battery", Math.min(raw as Integer, 100), "%", "battery")
            break

        case 5:    // device body temperature, /100
            BigDecimal at = scaled(raw, 100, 2)
            sendNumeric("airTemperature", convertTemp(at), tempUnit(), "device temperature")
            if (temperatureSource == "device") {
                sendNumeric("temperature", convertTemp(at), tempUnit(), "temperature")
            }
            break

        case 101:  sendNumeric("samplingInterval", raw as Integer, "s", "sampling interval"); break

        case 118:  sendNumeric("humidity", scaled(raw, 100, 1), "%", "humidity"); break
        case 124:  sendNumeric("tds", raw as Integer, "ppm", "TDS"); break
        case 127:  sendNumeric("ec", raw as Integer, "uS/cm", "EC"); break
        case 131:  sendNumeric("salinity", scaled(raw, 10, 1), "ppt", "salinity"); break
        case 132:  sendNumeric("sg", scaled(raw, 1000, 3), "", "specific gravity"); break

        case 112:  sendEnumEvent("probeTemperatureWarning", WARN3, raw); break
        case 117:  sendEnumEvent("temperatureWarning", WARN3, raw); break
        case 122:  sendEnumEvent("humidityWarning", WARN3, raw); break
        case 126:  sendEnumEvent("tdsWarning", WARN2, raw); break
        case 130:  sendEnumEvent("ecWarning", WARN3, raw); break
        case 133:  sendEnumEvent("mode", MODES, raw); break

        // Calibration / threshold values the device reports back.
        // Kept in state rather than as attributes, to avoid ~25 attributes on the device page.
        case 108:  storeSetting("probeTemperatureCalibration", scaled(raw, 10, 1)); break
        case 109:  storeSetting("probeTemperatureV0", scaled(raw, 10, 1)); break
        case 110:  storeSetting("probeTemperatureV1", scaled(raw, 10, 1)); break
        case 114:  storeSetting("temperatureCalibration", scaled(raw, 100, 2)); break
        case 115:  storeSetting("temperatureV0", scaled(raw, 100, 2)); break
        case 116:  storeSetting("temperatureV1", scaled(raw, 100, 2)); break
        case 119:  storeSetting("humidityCalibration", scaled(raw, 100, 2)); break
        case 120:  storeSetting("humidityV0", scaled(raw, 100, 2)); break
        case 121:  storeSetting("humidityV1", scaled(raw, 100, 2)); break
        case 125:  storeSetting("tdsWarningThreshold", raw as Integer); break
        case 128:  storeSetting("ecV0", raw as Integer); break
        case 129:  storeSetting("ecV1", raw as Integer); break

        default:
            // Always logged - this is the diagnostic path, it must not be silenced.
            log.info "${device.displayName}: UNKNOWN Tuya DP ${dp} type=${type} len=${length} " +
                     "raw=${raw} bytes=${hexOf(bytes)} - please report this"
            break
    }
}

private BigDecimal scaled(long raw, int divisor, int decimals) {
    return (raw as BigDecimal).divide(divisor as BigDecimal).setScale(decimals, BigDecimal.ROUND_HALF_UP)
}

private String tempUnit() { return "°${location.temperatureScale}" }

private BigDecimal convertTemp(BigDecimal celsius) {
    if (location.temperatureScale == "F") {
        return ((celsius * 1.8) + 32).setScale(1, BigDecimal.ROUND_HALF_UP)
    }
    return celsius
}

private void storeSetting(String name, Object value) {
    if (state.settingsReported == null) { state.settingsReported = [:] }
    state.settingsReported[name] = value
    logDebug "device setting ${name} = ${value}"
}

private void sendNumeric(String name, Object value, String unit, String label) {
    def current = device.currentValue(name)
    if (current != null && (current as BigDecimal) == (value as BigDecimal)) {
        logDebug "${name} unchanged (${value})"
        return
    }
    String descr = "${device.displayName} ${label} is ${value}${unit ? ' ' + unit : ''}"
    if (txtEnable) { log.info descr }
    sendEvent(name: name, value: value, unit: unit, descriptionText: descr)
}

private void sendEnumEvent(String name, Map lookup, long raw) {
    String value = lookup[(raw as Integer)]
    if (value == null) {
        log.warn "${device.displayName}: ${name} unknown enum value ${raw}"
        return
    }
    if (device.currentValue(name) == value) { return }
    String descr = "${device.displayName} ${name} is ${value}"
    if (txtEnable) { log.info descr }
    sendEvent(name: name, value: value, descriptionText: descr)
}

// ---------------------------------------------------------------- commands

void setMode(String mode) {
    Integer v = MODES.find { it.value == mode }?.key
    if (v == null) { log.warn "setMode: invalid mode '${mode}'"; return }
    sendZigbee(tuyaWrite(133, DP_TYPE_ENUM, String.format("%02X", v)))
}

void setSamplingInterval(BigDecimal seconds) {
    int s = clampInt(seconds as int, 5, 1200)
    s = (int) (s / 5) * 5
    sendZigbee(tuyaWrite(101, DP_TYPE_VALUE, int32(s)))
}

void setProbeTemperatureCalibration(BigDecimal offset) {
    int v = Math.round(clampDec(offset, -2.0, 2.0) * 10) as int
    sendZigbee(tuyaWrite(108, DP_TYPE_VALUE, int32(v)))
}

void setTemperatureCalibration(BigDecimal offset) {
    int v = Math.round(clampDec(offset, -2.0, 2.0) * 100) as int
    sendZigbee(tuyaWrite(114, DP_TYPE_VALUE, int32(v)))
}

void setHumidityCalibration(BigDecimal offset) {
    int v = Math.round(clampDec(offset, -10.0, 10.0) * 100) as int
    sendZigbee(tuyaWrite(119, DP_TYPE_VALUE, int32(v)))
}

void setTdsWarningThreshold(BigDecimal ppm) {
    sendZigbee(tuyaWrite(125, DP_TYPE_VALUE, int32(clampInt(ppm as int, 0, 13000))))
}

// ------------------------------------------------------------ tuya helpers

private String int32(int v) { return String.format("%08X", v) }   // two's complement

private int clampInt(int v, int lo, int hi) { return Math.max(lo, Math.min(hi, v)) }

private BigDecimal clampDec(BigDecimal v, BigDecimal lo, BigDecimal hi) {
    return v < lo ? lo : (v > hi ? hi : v)
}

private String nextPacketId() {
    Integer pid = ((state.packetId ?: 0) as Integer) + 1
    if (pid > 65535) { pid = 0 }
    state.packetId = pid
    return zigbee.convertToHexString(pid, 4)
}

// Tuya SET_DATA (0x00): seq(2) + dp(1) + type(1) + len(2) + payload
private List<String> tuyaWrite(int dp, String dpType, String value) {
    String payload = nextPacketId() + String.format("%02X", dp) + dpType +
                     zigbee.convertToHexString((int) (value.length() / 2), 4) + value
    logDebug "tuyaWrite DP ${dp}: ${payload}"
    return zigbee.command(0xEF00, 0x00, [:], 200, payload)
}

// Tuya QUERY (0x03) - asks the device to dump every datapoint now
private List<String> tuyaQuery() {
    return zigbee.command(0xEF00, 0x03, [:], 200, "00")
}

private List<String> syncTuyaDateTime() {
    long nowMs = now()
    long offset = 0
    try { offset = location.timeZone.getOffset(nowMs) } catch (ignored) { offset = 0 }
    String payload = "0008" +
                     zigbee.convertToHexString((int) (nowMs / 1000), 8) +
                     zigbee.convertToHexString((int) ((nowMs + offset) / 1000), 8)
    logDebug "time sync: ${payload}"
    return zigbee.command(0xEF00, 0x24, [:], 200, payload)
}

private void sendZigbee(List<String> cmds) {
    if (cmds) {
        sendHubCommand(new hubitat.device.HubMultiAction(cmds, hubitat.device.Protocol.ZIGBEE))
    }
}

private void logDebug(String msg) { if (logEnable) { log.debug "${device.displayName}: ${msg}" } }

Good point about the two temperatures.

When I run Claude Code on my laptop, it can see my existing drivers, so it usually follows the conventions I already use. In this case, it chose a single driver with no child devices and added a preference for which of the two temperature readings gets published as the standard temperature attribute, while the other is exposed as a custom attribute.

That approach works, but I’d personally keep the standard TemperatureMeasurement capability for room or air temperature only. If it’s anything else, like a water probe, soil probe, or pipe sensor, I’d publish it as a custom attribute instead. Otherwise, a dashboard tile or a Google or Alexa integration can end up showing the water temperature as though it were the room temperature, and the app consuming that data has no way to tell the difference.

So for this device, I’d put the built-in sensor temperature and humidity on the standard attributes, and expose probe temperature, TDS, EC, salinity, and SG as custom attributes.

Here is result with your modified code. To me it looks like it should be.

Thanks a lot

Petteri

From the log.

UNKNOWN Tuya DP 2 type=2 len=4 raw=47 bytes=0000002F - please report this

I have no idea what value that is. Maybe claude can fix this?

Hi @petteri.joutseno ,

DP 2 is not defined in the Zigbee2MQTT converter from which this driver was ported. The driver appears to be decoding it correctly as a four-byte value (47), but there is not enough information to determine what it represents. So the best is to leave the debug message as it is.

Is everything else working as expected?

Debug log

[details="click to expand"]

2026-08-21 11:45:29.557

debug

(M) Vedenlaatumittari: sg unchanged (1.000)

**dev:1005**2026-08-21 11:45:29.554

debug

(M) Vedenlaatumittari: DP 132 type=2 len=4 raw=1000 bytes=000003E8

**dev:1005**2026-08-21 11:45:29.550

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 035284020004000003E8, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 52, 84, 02, 00, 04, 00, 00, 03, E8]]

**dev:1005**2026-08-21 11:45:29.548

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 035284020004000003E8

**dev:1005**2026-08-21 11:45:29.350

debug

(M) Vedenlaatumittari: salinity unchanged (0.0)

**dev:1005**2026-08-21 11:45:29.348

debug

(M) Vedenlaatumittari: DP 131 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:29.344

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03518302000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 51, 83, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:29.342

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03518302000400000000

**dev:1005**2026-08-21 11:45:29.142

debug

(M) Vedenlaatumittari: device setting ecV1 = 10000

**dev:1005**2026-08-21 11:45:29.140

debug

(M) Vedenlaatumittari: DP 129 type=2 len=4 raw=10000 bytes=00002710

**dev:1005**2026-08-21 11:45:29.136

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03508102000400002710, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 50, 81, 02, 00, 04, 00, 00, 27, 10]]

**dev:1005**2026-08-21 11:45:29.134

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03508102000400002710

**dev:1005**2026-08-21 11:45:28.933

debug

(M) Vedenlaatumittari: ec unchanged (0)

**dev:1005**2026-08-21 11:45:28.931

debug

(M) Vedenlaatumittari: DP 127 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:28.927

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034F7F02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 4F, 7F, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:28.925

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034F7F02000400000000

**dev:1005**2026-08-21 11:45:28.722

debug

(M) Vedenlaatumittari: DP 126 type=4 len=1 raw=0 bytes=00

**dev:1005**2026-08-21 11:45:28.719

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034E7E04000100, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 4E, 7E, 04, 00, 01, 00]]

**dev:1005**2026-08-21 11:45:28.717

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034E7E04000100

**dev:1005**2026-08-21 11:45:28.515

debug

(M) Vedenlaatumittari: tds unchanged (0)

**dev:1005**2026-08-21 11:45:28.513

debug

(M) Vedenlaatumittari: DP 124 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:28.509

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034D7C02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 4D, 7C, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:28.507

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034D7C02000400000000

**dev:1005**2026-08-21 11:45:28.304

debug

(M) Vedenlaatumittari: DP 122 type=4 len=1 raw=0 bytes=00

**dev:1005**2026-08-21 11:45:28.301

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034C7A04000100, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 4C, 7A, 04, 00, 01, 00]]

**dev:1005**2026-08-21 11:45:28.299

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034C7A04000100

**dev:1005**2026-08-21 11:45:28.195

debug

(M) Vedenlaatumittari: device setting humidityV0 = 10.00

**dev:1005**2026-08-21 11:45:28.102

debug

(M) Vedenlaatumittari: DP 120 type=2 len=4 raw=1000 bytes=000003E8

**dev:1005**2026-08-21 11:45:28.098

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034B78020004000003E8, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 4B, 78, 02, 00, 04, 00, 00, 03, E8]]

**dev:1005**2026-08-21 11:45:28.096

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034B78020004000003E8

**dev:1005**2026-08-21 11:45:27.689

debug

(M) Vedenlaatumittari: unhandled cluster 0405

**dev:1005**2026-08-21 11:45:27.687

debug

(M) Vedenlaatumittari: descMap: [raw:91C901040514000021EF12FEFE218600, dni:91C9, endpoint:01, cluster:0405, size:14, attrId:0000, encoding:21, command:0A, value:12EF, clusterInt:1029, attrInt:0, additionalAttrs:[[value:0086, encoding:21, attrId:FEFE, consumedBytes:5, attrInt:65278]]]

**dev:1005**2026-08-21 11:45:27.683

debug

(M) Vedenlaatumittari: parse: read attr - raw: 91C901040514000021EF12FEFE218600, dni: 91C9, endpoint: 01, cluster: 0405, size: 14, attrId: 0000, encoding: 21, command: 0A, value: EF12FEFE218600

**dev:1005**2026-08-21 11:45:27.484

debug

(M) Vedenlaatumittari: device setting temperatureV1 = 40.00

**dev:1005**2026-08-21 11:45:27.481

debug

(M) Vedenlaatumittari: DP 116 type=2 len=4 raw=4000 bytes=00000FA0

**dev:1005**2026-08-21 11:45:27.477

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03497402000400000FA0, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 49, 74, 02, 00, 04, 00, 00, 0F, A0]]

**dev:1005**2026-08-21 11:45:27.475

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03497402000400000FA0

**dev:1005**2026-08-21 11:45:27.281

debug

(M) Vedenlaatumittari: device setting temperatureCalibration = 0.00

**dev:1005**2026-08-21 11:45:27.278

debug

(M) Vedenlaatumittari: DP 114 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:27.270

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03487202000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 48, 72, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:27.268

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03487202000400000000

**dev:1005**2026-08-21 11:45:26.858

debug

(M) Vedenlaatumittari: device setting probeTemperatureCalibration = 0.0

**dev:1005**2026-08-21 11:45:26.856

debug

(M) Vedenlaatumittari: DP 108 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:26.851

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03476C02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 47, 6C, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:26.849

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03476C02000400000000

**dev:1005**2026-08-21 11:45:26.650

debug

(M) Vedenlaatumittari: device setting probeTemperatureV0 = 0.0

**dev:1005**2026-08-21 11:45:26.647

debug

(M) Vedenlaatumittari: DP 109 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:45:26.641

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03466D02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 46, 6D, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:45:26.639

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03466D02000400000000

**dev:1005**2026-08-21 11:45:26.440

debug

(M) Vedenlaatumittari: unhandled cluster 0402

**dev:1005**2026-08-21 11:45:26.438

debug

(M) Vedenlaatumittari: descMap: [raw:91C9010402140000292E09FEFE298600, dni:91C9, endpoint:01, cluster:0402, size:14, attrId:0000, encoding:29, command:0A, value:092E, clusterInt:1026, attrInt:0, additionalAttrs:[[value:0086, encoding:29, attrId:FEFE, consumedBytes:5, attrInt:65278]]]

**dev:1005**2026-08-21 11:45:26.434

debug

(M) Vedenlaatumittari: parse: read attr - raw: 91C9010402140000292E09FEFE298600, dni: 91C9, endpoint: 01, cluster: 0402, size: 14, attrId: 0000, encoding: 29, command: 0A, value: 2E09FEFE298600

**dev:1005**2026-08-21 11:45:26.065

debug

(M) Vedenlaatumittari: battery unchanged (66)

**dev:1005**2026-08-21 11:45:26.062

debug

(M) Vedenlaatumittari: DP 4 type=2 len=4 raw=66 bytes=00000042

**dev:1005**2026-08-21 11:45:26.041

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03450402000400000042, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 45, 04, 02, 00, 04, 00, 00, 00, 42]]

**dev:1005**2026-08-21 11:45:26.039

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03450402000400000042

**dev:1005**2026-08-21 11:35:29.242

info

(M) Vedenlaatumittari humidity is 48.2 %

**dev:1005**2026-08-21 11:35:29.239

debug

(M) Vedenlaatumittari: DP 118 type=2 len=4 raw=4815 bytes=000012CF

**dev:1005**2026-08-21 11:35:29.235

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034476020004000012CF, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 44, 76, 02, 00, 04, 00, 00, 12, CF]]

**dev:1005**2026-08-21 11:35:29.233

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 034476020004000012CF

**dev:1005**2026-08-21 11:35:29.092

debug

(M) Vedenlaatumittari: unhandled cluster 0405

**dev:1005**2026-08-21 11:35:29.089

debug

(M) Vedenlaatumittari: descMap: [raw:91C901040514000021CF12FEFE218600, dni:91C9, endpoint:01, cluster:0405, size:14, attrId:0000, encoding:21, command:0A, value:12CF, clusterInt:1029, attrInt:0, additionalAttrs:[[value:0086, encoding:21, attrId:FEFE, consumedBytes:5, attrInt:65278]]]

**dev:1005**2026-08-21 11:35:29.085

debug

(M) Vedenlaatumittari: parse: read attr - raw: 91C901040514000021CF12FEFE218600, dni: 91C9, endpoint: 01, cluster: 0405, size: 14, attrId: 0000, encoding: 21, command: 0A, value: CF12FEFE218600

**dev:1005**2026-08-21 11:35:28.832

debug

(M) Vedenlaatumittari: device setting temperatureV1 = 40.00

**dev:1005**2026-08-21 11:35:28.829

debug

(M) Vedenlaatumittari: DP 116 type=2 len=4 raw=4000 bytes=00000FA0

**dev:1005**2026-08-21 11:35:28.824

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03437402000400000FA0, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 43, 74, 02, 00, 04, 00, 00, 0F, A0]]

**dev:1005**2026-08-21 11:35:28.822

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03437402000400000FA0

**dev:1005**2026-08-21 11:35:28.625

debug

(M) Vedenlaatumittari: device setting temperatureCalibration = 0.00

**dev:1005**2026-08-21 11:35:28.623

debug

(M) Vedenlaatumittari: DP 114 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:35:28.618

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03427202000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 42, 72, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:35:28.616

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03427202000400000000

**dev:1005**2026-08-21 11:35:28.205

debug

(M) Vedenlaatumittari: device setting probeTemperatureCalibration = 0.0

**dev:1005**2026-08-21 11:35:28.203

debug

(M) Vedenlaatumittari: DP 108 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:35:28.198

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03416C02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 41, 6C, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:35:28.196

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03416C02000400000000

**dev:1005**2026-08-21 11:35:27.998

debug

(M) Vedenlaatumittari: device setting probeTemperatureV0 = 0.0

**dev:1005**2026-08-21 11:35:27.995

debug

(M) Vedenlaatumittari: DP 109 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:35:27.991

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03406D02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 40, 6D, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:35:27.989

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03406D02000400000000

**dev:1005**2026-08-21 11:35:27.787

debug

(M) Vedenlaatumittari: unhandled cluster 0402

**dev:1005**2026-08-21 11:35:27.785

debug

(M) Vedenlaatumittari: descMap: [raw:91C9010402140000292E09FEFE298600, dni:91C9, endpoint:01, cluster:0402, size:14, attrId:0000, encoding:29, command:0A, value:092E, clusterInt:1026, attrInt:0, additionalAttrs:[[value:0086, encoding:29, attrId:FEFE, consumedBytes:5, attrInt:65278]]]

**dev:1005**2026-08-21 11:35:27.781

debug

(M) Vedenlaatumittari: parse: read attr - raw: 91C9010402140000292E09FEFE298600, dni: 91C9, endpoint: 01, cluster: 0402, size: 14, attrId: 0000, encoding: 29, command: 0A, value: 2E09FEFE298600

**dev:1005**2026-08-21 11:35:27.629

info

(M) Vedenlaatumittari battery is 66 %

**dev:1005**2026-08-21 11:35:27.627

debug

(M) Vedenlaatumittari: DP 4 type=2 len=4 raw=66 bytes=00000042

**dev:1005**2026-08-21 11:35:27.622

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033F0402000400000042, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3F, 04, 02, 00, 04, 00, 00, 00, 42]]

**dev:1005**2026-08-21 11:35:27.620

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033F0402000400000042

**dev:1005**2026-08-21 11:25:31.447

debug

(M) Vedenlaatumittari: sg unchanged (1.000)

**dev:1005**2026-08-21 11:25:31.444

debug

(M) Vedenlaatumittari: DP 132 type=2 len=4 raw=1000 bytes=000003E8

**dev:1005**2026-08-21 11:25:31.440

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033E84020004000003E8, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3E, 84, 02, 00, 04, 00, 00, 03, E8]]

**dev:1005**2026-08-21 11:25:31.438

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033E84020004000003E8

**dev:1005**2026-08-21 11:25:31.238

debug

(M) Vedenlaatumittari: salinity unchanged (0.0)

**dev:1005**2026-08-21 11:25:31.236

debug

(M) Vedenlaatumittari: DP 131 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:31.232

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033D8302000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3D, 83, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:31.230

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033D8302000400000000

**dev:1005**2026-08-21 11:25:31.031

debug

(M) Vedenlaatumittari: device setting ecV1 = 10000

**dev:1005**2026-08-21 11:25:31.028

debug

(M) Vedenlaatumittari: DP 129 type=2 len=4 raw=10000 bytes=00002710

**dev:1005**2026-08-21 11:25:31.024

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033C8102000400002710, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3C, 81, 02, 00, 04, 00, 00, 27, 10]]

**dev:1005**2026-08-21 11:25:31.022

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033C8102000400002710

**dev:1005**2026-08-21 11:25:30.823

debug

(M) Vedenlaatumittari: ec unchanged (0)

**dev:1005**2026-08-21 11:25:30.821

debug

(M) Vedenlaatumittari: DP 127 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:30.817

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033B7F02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3B, 7F, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:30.815

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033B7F02000400000000

**dev:1005**2026-08-21 11:25:30.614

debug

(M) Vedenlaatumittari: DP 126 type=4 len=1 raw=0 bytes=00

**dev:1005**2026-08-21 11:25:30.610

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033A7E04000100, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 3A, 7E, 04, 00, 01, 00]]

**dev:1005**2026-08-21 11:25:30.608

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033A7E04000100

**dev:1005**2026-08-21 11:25:30.489

debug

(M) Vedenlaatumittari: tds unchanged (0)

**dev:1005**2026-08-21 11:25:30.487

debug

(M) Vedenlaatumittari: DP 124 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:30.483

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03397C02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 39, 7C, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:30.481

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03397C02000400000000

**dev:1005**2026-08-21 11:25:30.249

debug

(M) Vedenlaatumittari: device setting humidityV1 = 90.00

**dev:1005**2026-08-21 11:25:30.246

debug

(M) Vedenlaatumittari: DP 121 type=2 len=4 raw=9000 bytes=00002328

**dev:1005**2026-08-21 11:25:30.241

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03387902000400002328, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 38, 79, 02, 00, 04, 00, 00, 23, 28]]

**dev:1005**2026-08-21 11:25:30.239

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03387902000400002328

**dev:1005**2026-08-21 11:25:29.998

debug

(M) Vedenlaatumittari: device setting humidityCalibration = 0.00

**dev:1005**2026-08-21 11:25:29.996

debug

(M) Vedenlaatumittari: DP 119 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:29.991

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03377702000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 37, 77, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:29.989

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03377702000400000000

**dev:1005**2026-08-21 11:25:29.791

info

(M) Vedenlaatumittari: UNKNOWN Tuya DP 2 type=2 len=4 raw=48 bytes=00000030 - please report this

**dev:1005**2026-08-21 11:25:29.789

debug

(M) Vedenlaatumittari: DP 2 type=2 len=4 raw=48 bytes=00000030

**dev:1005**2026-08-21 11:25:29.785

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03360202000400000030, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 36, 02, 02, 00, 04, 00, 00, 00, 30]]

**dev:1005**2026-08-21 11:25:29.783

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03360202000400000030

**dev:1005**2026-08-21 11:25:29.663

debug

(M) Vedenlaatumittari: DP 117 type=4 len=1 raw=0 bytes=00

**dev:1005**2026-08-21 11:25:29.577

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03357504000100, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 35, 75, 04, 00, 01, 00]]

**dev:1005**2026-08-21 11:25:29.574

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03357504000100

**dev:1005**2026-08-21 11:25:29.375

debug

(M) Vedenlaatumittari: device setting temperatureV0 = 0.00

**dev:1005**2026-08-21 11:25:29.372

debug

(M) Vedenlaatumittari: DP 115 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:29.367

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03347302000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 34, 73, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:29.365

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03347302000400000000

**dev:1005**2026-08-21 11:25:29.166

info

(M) Vedenlaatumittari device temperature is 24.93 °C

**dev:1005**2026-08-21 11:25:29.163

debug

(M) Vedenlaatumittari: DP 5 type=2 len=4 raw=2493 bytes=000009BD

**dev:1005**2026-08-21 11:25:29.159

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033305020004000009BD, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 33, 05, 02, 00, 04, 00, 00, 09, BD]]

**dev:1005**2026-08-21 11:25:29.157

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 033305020004000009BD

**dev:1005**2026-08-21 11:25:28.748

debug

(M) Vedenlaatumittari: device setting probeTemperatureCalibration = 0.0

**dev:1005**2026-08-21 11:25:28.746

debug

(M) Vedenlaatumittari: DP 108 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:28.741

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03326C02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 32, 6C, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:28.739

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03326C02000400000000

**dev:1005**2026-08-21 11:25:28.541

debug

(M) Vedenlaatumittari: device setting probeTemperatureV0 = 0.0

**dev:1005**2026-08-21 11:25:28.538

debug

(M) Vedenlaatumittari: DP 109 type=2 len=4 raw=0 bytes=00000000

**dev:1005**2026-08-21 11:25:28.534

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03316D02000400000000, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 31, 6D, 02, 00, 04, 00, 00, 00, 00]]

**dev:1005**2026-08-21 11:25:28.532

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03316D02000400000000

**dev:1005**2026-08-21 11:25:28.329

debug

(M) Vedenlaatumittari: unhandled cluster 0402

**dev:1005**2026-08-21 11:25:28.326

debug

(M) Vedenlaatumittari: descMap: [raw:91C9010402140000292E09FEFE298600, dni:91C9, endpoint:01, cluster:0402, size:14, attrId:0000, encoding:29, command:0A, value:092E, clusterInt:1026, attrInt:0, additionalAttrs:[[value:0086, encoding:29, attrId:FEFE, consumedBytes:5, attrInt:65278]]]

**dev:1005**2026-08-21 11:25:28.322

debug

(M) Vedenlaatumittari: parse: read attr - raw: 91C9010402140000292E09FEFE298600, dni: 91C9, endpoint: 01, cluster: 0402, size: 14, attrId: 0000, encoding: 29, command: 0A, value: 2E09FEFE298600

**dev:1005**2026-08-21 11:25:27.934

debug

(M) Vedenlaatumittari: battery unchanged (67)

**dev:1005**2026-08-21 11:25:27.932

debug

(M) Vedenlaatumittari: DP 4 type=2 len=4 raw=67 bytes=00000043

**dev:1005**2026-08-21 11:25:27.927

debug

(M) Vedenlaatumittari: descMap: [raw:catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03300402000400000043, profileId:0104, clusterId:EF00, clusterInt:61184, sourceEndpoint:01, destinationEndpoint:01, options:0040, messageType:00, dni:91C9, isClusterSpecific:true, isManufacturerSpecific:true, manufacturerId:0001, command:02, direction:01, data:[03, 30, 04, 02, 00, 04, 00, 00, 00, 43]]

**dev:1005**2026-08-21 11:25:27.925

debug

(M) Vedenlaatumittari: parse: catchall: 0104 EF00 01 01 0040 00 91C9 01 01 0001 02 01 03300402000400000043

[/details]

Everything else works fine

Cheers

Petteri

Thanks, the log confirms that everything else is working correctly.

The device also sends standard ZCL temperature (0x0402) and humidity (0x0405) reports, but both Zigbee2MQTT and ZHA use the Tuya EF00 DPs instead: DP 5 for temperature and DP 118 for humidity. I will therefore ignore those duplicate ZCL reports in the driver.

DP 2 is not defined in either converter. It may be a rounded duplicate humidity value, but there is not enough evidence to add it to the driver yet.

If you want to hide long logs, you can put them inside a spoiler so they do not make the post very long:

Tried to use

[details="unhide"]

Text to be hidden

[/details]