Koenkk / Koenkk/zigbee2mqtt

SWV-ZF2 (Hydro Duo): irrigation_plan_* properties stay null after pairing, /set validation errors reference wrong field, /get has no converter

Open
#32,632 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

problem
Dominant language
TypeScript
Stars
15.7k
Forks
2k
Avg merge
18h 55m
Merged PRs (30d)
35

Description

What happened?

After pairing/re-pairing a SONOFF SWV-ZF2 (Hydro Duo), all irrigation_plan_* properties for both endpoints remain permanently null in the published state, even right after a successful device interview. This was also observed with update.installed_version/latest_version showing -1 until a manual OTA check was triggered from the frontend, after which those specific fields populated correctly, suggesting some attributes are not read proactively after interview.

Attempting to write any single irrigation_plan_*_1/_2 property (e.g. irrigation_plan_enable_date_1) via /set is rejected with a validation error -but the error frequently references a different field than the one that was actually sent, and persists even with a correctly formatted value (tested with realistic dates and a date near the Zigbee epoch to rule out clock-sync causes).

What did you expect to happen?

Writing a single irrigation_plan_* property should either succeed, or fail with an error referencing the actual invalid field.

How to reproduce it (minimal and precise)
  1. Pair a SONOFF SWV-ZF2 (Hydro Duo) fresh in Zigbee2MQTT.
  2. Confirm irrigation_plan_enable_date_1, irrigation_plan_start_time_1, etc. are all null in the published state.
  3. Publish to zigbee2mqtt/<friendly_name>/set: {"irrigation_plan_enable_date_1": "2026-07-23"}
  4. Observe log output: zhc:sonoff: irrigation_plan_settings invalid enable_date, expected local date in YYYY-MM-DD format. (despite the value matching the documented format exactly)
  5. Publish instead: {"irrigation_plan_start_time_1": "05:00"}
  6. Observe a different error: zhc:sonoff: irrigation_plan_settings invalid start_time, expected HH:mm. (again despite matching the documented format)
  7. Sending a complete payload with all plan fields for one zone at once produces the same class of errors, with the specific field named in the error varying between attempts.
Zigbee2MQTT version

2.12.1

Adapter firmware version

8.0.2 (EmberZNet)

Adapter

SLZB-06MU, firmware v3.3.1

Setup

Running Z2M in a Docker Container

Device database.db entry

{"id":7,"type":"EndDevice","ieeeAddr":"0xa4c138aa7da2a27c","nwkAddr":6535,"manufId":4742,"manufName":"SONOFF","powerSource":"Battery","modelId":"SWV-ZF2","epList":[1,2],"endpoints":{"1":{"profId":260,"epId":1,"devId":2,"inClusterList":[0,1,3,6,32,64599,64529],"outClusterList":[3,25],"clusters":{"genBasic":{"attributes":{"hwVersion":0,"dateCode":"20260428","swBuildId":"1.0.7"}},"genPollCtrl":{"attributes":{"checkinInterval":14400}},"genOnOff":{"attributes":{"onOff":0}},"customClusterEwelink":{"attributes":{"20504":[0,0,0,0],"valveAbnormalState":0,"childLock":0,"realTimeIrrigationDuration":0,"realTimeIrrigationVolume":0,"hourIrrigationDuration":0,"hourIrrigationVolume":0,"manualDefaultSettings":[0,0,10,0,0,0,0,1,0,0,0,0],"rainDelayEndDatetime":0,"valveAlarmSettings":[7,5,1,5],"seasonalWateringAdjustment":[10,10,10,10,10,10,10,10,10,10,10,10]}},"genPowerCfg":{"attributes":{"batteryPercentageRemaining":200}}},"binds":[{"cluster":32,"type":"endpoint","deviceIeeeAddress":"0x70d07efffece30a1","endpointID":1},{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x70d07efffece30a1","endpointID":1},{"cluster":1,"type":"endpoint","deviceIeeeAddress":"0x70d07efffece30a1","endpointID":1}],"configuredReportings":[{"cluster":1,"attrId":33,"minRepIntval":3600,"maxRepIntval":65000,"repChange":10}],"meta":{}},"2":{"profId":260,"epId":2,"devId":2,"inClusterList":[0,6],"outClusterList":[],"clusters":{"genBasic":{"attributes":{"hwVersion":0}},"genOnOff":{"attributes":{"onOff":0}},"customClusterEwelink":{"attributes":{"realTimeIrrigationDuration":0,"hourIrrigationDuration":0}}},"binds":[{"cluster":6,"type":"endpoint","deviceIeeeAddress":"0x70d07efffece30a1","endpointID":1}],"configuredReportings":[],"meta":{}}},"appVersion":16,"hwVersion":0,"dateCode":"20260428","swBuildId":"1.0.7","zclVersion":8,"interviewCompleted":true,"interviewState":"SUCCESSFUL","meta":{"configured":"0.0.0"},"lastSeen":1784723431979,"checkinInterval":3600}

Debug log

z2m-debug-excerpt.log

Notes

Full published state after fresh pairing shows all irrigation_plan_*_1/_2 fields as null. The same device model's single-zone sibling (SWV-ZFE, "Hydro ONE") behaves correctly with the equivalent nested irrigation_plan_settings composite. This issue appears specific to the SWV-ZF2's flattened per-endpoint property structure. Furthermore, attempting to read a plan property via /get also fails: publishing {"irrigation_plan_enable_date_1": ""} to the /get topic returns "No converter available for 'get' 'irrigation_plan_enable_date' (undefined)" in the logs, indicating the read path for this property group is not implemented, in addition to the write-path validation issues described above.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the SWV-ZFE irrigation_plan_settings handling with the SWV-ZF2 flattened irrigation_plan_*_1/_2 properties, then reproduce the /set validation and /get converter failures described above. Done means irrigation plan fields populate after pairing, writes validate the field actually sent, and reads have a converter.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, embedded-iot
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.