[ST Edge] SONOFF Hydro ONE / DUO family (SWV-ZFE / SWV-ZFU / SWV-ZNE / SWV-ZNU / SWV-ZF2E / SWV-ZF2U)

Excellent, thanks for that update, and thank you to @Pajacyk0v for providing you those logs.

I just couldn’t get to testing for you today, sorry about that. Due to bad weather in our area of the US, it caused so many flight delays that we didn’t get home until 2am this morning.

No worries. Take your time!


New logs, new version: 2026-07-09T17:19

Old:
0x501D write = mfg frame + standard/ZHA Array
→ rejected

New:
0x501D write = mfg frame + Sonoff private array shape
→ outer type Array 0x48
→ inner marker 0x48
→ one-byte length
→ payload

I had a moment, so I tested this version remotely. The same scenario: re-add device > change the manual watering limiter to 15 minutes > refresh > manually activate the valve.

Unfortunately, the valve still closes automatically after 10 minutes.

Thanks for testing. Even without logs, this confirms that this version does not yet change the valve’s internal 10-minute limit. Since the driver writes the selected duration again immediately before opening, the remaining problem is almost certainly the exact private Zigbee write format rather than the SmartThings preference or timer itself.

I’ll ask in the eWeLink/Sonoff forums if they can provide the exact raw write format. As I said before, it’s quite complicated on SmartThings to format the correct Zigbee frame.


New version: 2026-07-12T12:14

Different payload, more debug logging.

Hi @Andreas_Roedl, I had to focus the last few days on some big projects we had at work so I hadn’t done much testing for you. I’ll be able to do quite a bit on Tuesday and post logs for you on what I’m seeing.

First of all, thank you for continuing to test these builds. I know that repeatedly installing a new driver and then waiting more than ten minutes to see whether anything changed is becoming frustrating.

The important point is that the driver is working correctly: the valve can be opened and closed, water consumption is reported, and the SmartThings timer works. The remaining problem is the valve’s own internal manual-watering limit, which is stored in SONOFF’s private Zigbee attribute 0x501D.

Unfortunately, this is not a normal numeric Zigbee setting. It is part of a complete 12-byte manual_default_settings configuration containing the watering mode, duration, interval, volume unit, volume and fail-safe timeout. The valve appears to reject the entire write when even the framing or array serialization differs slightly from what its firmware expects.

The repeated test versions have therefore not been random changes. Each one tested a different interpretation of the private protocol:

test11  standard Zigbee frame, simplified array
test12  manufacturer-specific frame, simplified array
test13  manufacturer-specific frame, private SONOFF-style array
test14  manufacturer-specific frame, complete Z2M-style configuration
test15  standard Zigbee frame, complete Z2M-style configuration

The logs from the earlier versions showed that the normal On command was accepted, while the 0x501D configuration write was rejected. That is why the valve opened normally but still closed itself after approximately ten minutes.

SmartThings is not the only integration having trouble. Zigbee2MQTT currently has an open issue specifically about the SWV-ZFE because its documented timed-control methods are unreliable on real hardware. Users there report that on_time may not open the valve at all, which is the same behaviour we observed when testing OnWithTimedOff on SmartThings. The only repeatedly successful Zigbee2MQTT sequence reported there was to write the complete manual settings first and then send a normal On command.

Zigbee2MQTT also recently had to revert changes to these settings after it became clear that fields such as the duration and fail-safe cannot safely be written independently. The complete configuration has to be sent atomically in one transaction, which confirms that this device protocol is more complicated than it initially appears.

ZHA support for the Hydro ONE and Hydro DUO family is also still being developed in an open pull request. It adds device identification and sensor support, but it does not currently provide a hardware-verified solution for changing this internal manual-watering limit.

A Home Assistant user did confirm that changing the Manual Default Settings through Zigbee2MQTT raised the valve’s limit from around 10 minutes to 15 minutes. That proves that 0x501D is the correct setting, but it does not tell us exactly how SmartThings must serialize the write on the Zigbee wire.

Test15 is currently the most evidence-based implementation. It mirrors the current Zigbee2MQTT code as closely as SmartThings Edge allows:

standard, non-manufacturer-specific Write Attributes frame
standard Zigbee Array with Uint8 elements
complete 12-byte manual_default_settings configuration
normal On command after the settings write

It is therefore not simply another speculative variation. It tests the combination that the current Zigbee2MQTT source appears to use.

I do not intend to keep asking for endless tests of versions that merely rearrange bytes. If test15 is also rejected, the next meaningful step will be to capture a known-working raw Zigbee2MQTT transaction and compare it byte for byte with the SmartThings packet. That would require to buy a device and test it on a different platform. At that point the problem is most likely SmartThings’ low-level array serialization rather than the logical values being sent.

One final test15 test, preferably with logs, would therefore give me a clear answer about whether this approach works or whether we need to move to a raw packet comparison. :hot_face:

Thank you again for the time and patience you have already invested. Even the unsuccessful tests have narrowed the problem considerably and prevented unverified behaviour from being released as a finished solution.

CC: @Pajacyk0v

Okay…

Please test the device with the driver from the PR for the official SmartThings Zigbee Valve Edge Driver.

Channel link.

CC: @Pajacyk0v @jbellarmada

Update the firmware via Bluetooth and the eWeLink/SONOFF app from 1.0.7 to 1.0.8! This works while the device is connected to ST.

CC: @Pajacyk0v

Oh wow, ok. I had to leave town again for a family matter, but I’ll do all that as soon as I get home.

If you only have limited time to do some tests, just update the firmware and test it with my driver.

The PR for the official driver only adds the fingerprints and the stock driver does pretty much the same as my driver, but without the special features. As long as it doesn’t set the timer limit, it will stop after 10 minutes.

That’s probably the reason why the PR is lingering for a month now. My guess: they are waiting for a firmware update.

A device that has an internal limit should make it easy and predictable to configure this limit. It shouldn’t require a magic spell or hidden message.

I’ve added a comment on the PR, asking what firmware they were using for the WWST certification and how they are planning to change the preset on-device limit of 10 minutes.


For those interested, this is the relevant code to create and send the payload:

local cluster_base = require "st.zigbee.cluster_base"
local data_types = require "st.zigbee.data_types"

local EWELINK_CLUSTER_ID = 0xFC11
local ATTR_MANUAL_DEFAULT_SETTINGS = 0x501D

local function standard_write_attribute_data(device, cluster_id, attr_id, data)
  return cluster_base.write_attribute(
    device,
    data_types.ClusterId(cluster_id),
    data_types.AttributeId(attr_id),
    data
  )
end

local function write_manual_default_duration(device, minutes)
  local value = math.max(1, math.min(719, math.floor(tonumber(minutes) or 10)))

  local high = (value >> 8) & 0xFF
  local low = value & 0xFF

  local irrigation_interval = 10
  local interval_high = (irrigation_interval >> 8) & 0xFF
  local interval_low = irrigation_interval & 0xFF

  local payload = {
    0x00,          -- irrigation mode: duration

    high,
    low,           -- total irrigation duration

    high,
    low,           -- irrigation duration

    interval_high,
    interval_low,  -- irrigation interval = 10

    0x01,          -- irrigation amount unit: litre

    0x00,
    0x00,          -- irrigation amount = 0

    high,
    low,           -- fail-safe timeout
  }

  local array_data = data_types.validate_or_build_type(
    {
      data_types.Uint8(payload[1]),
      data_types.Uint8(payload[2]),
      data_types.Uint8(payload[3]),
      data_types.Uint8(payload[4]),
      data_types.Uint8(payload[5]),
      data_types.Uint8(payload[6]),
      data_types.Uint8(payload[7]),
      data_types.Uint8(payload[8]),
      data_types.Uint8(payload[9]),
      data_types.Uint8(payload[10]),
      data_types.Uint8(payload[11]),
      data_types.Uint8(payload[12]),
    },
    data_types.Array
  )

  local message = standard_write_attribute_data(
    device,
    EWELINK_CLUSTER_ID,
    ATTR_MANUAL_DEFAULT_SETTINGS,
    array_data
  )

  device:send(message)
end

local function send_on(device, component_id)
  write_manual_default_duration(
    device,
    device.preferences.manualDuration
  )

  send_zcl_to_component(
    device,
    component_id,
    OnOff.server.commands.On(device)
  )
end

Payload for 15 minutes: 00 00 0F 00 0F 00 0A 01 00 00 00 0F

New version: 2026-07-17T00:44:49

Minor change to the payload: fail-safe = duration + 1