Просмотр исходного кода

Add Shrivee dual RF water timer (#5738)

## Device

Shrivee dual-valve sub-GHz watering computer, connected through a Tuya
Sub-GHz gateway as a sub-device (`cid` = node id). Verified working
locally at protocol 3.5.

- Product id: `zjqxgxxesv29cpkn`
- Category: `sfkzq`

This is the **dual-valve sibling of the existing
`shrivee_triple_rf_water_timer`** and follows it closely. The shared dps
layout is identical — valves on 1/2, durations on 17/18, weather on
42/43/44/45, battery on 47, signal strength on 118, per-valve state on
119/120 — so it reuses the same `valve_x`, `timer_x`, `status` and
`timer` translation keys and the same mappings.

The model number is not in the Tuya cloud record for this unit (the
triple lists HCT-638). Happy to add it if you would like it filled in.

## Additional dps on this variant

Beyond the triple's set, this firmware also reports:

| dps | function |
|---|---|
| 38 / 113 | per-valve schedule (attached to the state sensors) |
| 53 | fault bitfield (`low_battery`) |
| 101 / 102 | per-valve irrigation on/off log |
| 117 | signal boost switch |
| 123 | upgrade status |
| 131 / 132 | per-valve last runtime |

All 19 dps the device reports are covered. Ids were taken from the Query
Things Data Model API and cross-checked against a live local read.

## Two deliberate differences from the triple

1. **Battery (dps 47).** The triple treats this as an integer with
`scale: 20`. On this variant the thing model declares it an enum of
discrete charge states (`6` = 3.05V down to `1` = 2.60V, `0` = empty)
and the device returns them as strings, so it is mapped evenly across
the seven states instead. Documented in a comment.
2. **Durations (dps 17/18).** Exposed in minutes via `scale: 60`,
matching `HCT-626_dual_water_timer`, rather than the triple's raw
seconds — 43200 seconds is unwieldy in the UI. Happy to switch to
seconds for consistency with the triple if you prefer.

`uv run duplicates` reports no matches.

## Checks

- `uv run yamllint custom_components/tuya_local/devices` — clean
- `uv run pytest tests/test_device_config.py` — 32 passed
- `uv run ruff check .` / `ruff format --check .` — clean

---------

Co-authored-by: Jason Rumney <make-all@users.noreply.github.com>
Maurice Faber 1 день назад
Родитель
Сommit
d096050d11
2 измененных файлов с 283 добавлено и 0 удалено
  1. 1 0
      DEVICES.md
  2. 282 0
      custom_components/tuya_local/devices/shrivee_dualrf_watertimer.yaml

+ 1 - 0
DEVICES.md

@@ -1401,6 +1401,7 @@ port and password.
 - Ryakka 7-in-1 smart pool monitor
 - Ryakka 7-in-1 smart pool monitor
 - Satisure power outage alarm
 - Satisure power outage alarm
 - SD123 HPR01 human presence radar
 - SD123 HPR01 human presence radar
+- Shrivee dual water timer
 - Shrivee triple water timer
 - Shrivee triple water timer
 - SNT957W-TDE temperature sensor
 - SNT957W-TDE temperature sensor
 - SNT957W-DE CBU temperature and humidity sensor
 - SNT957W-DE CBU temperature and humidity sensor

+ 282 - 0
custom_components/tuya_local/devices/shrivee_dualrf_watertimer.yaml

@@ -0,0 +1,282 @@
+name: Dual water timer
+products:
+  - id: zjqxgxxesv29cpkn
+    manufacturer: Shrivee
+entities:
+  - entity: valve
+    translation_key: valve_x
+    translation_placeholders:
+      x: "1"
+    class: water
+    dps:
+      - id: 1
+        type: boolean
+        name: valve
+  - entity: valve
+    translation_key: valve_x
+    translation_placeholders:
+      x: "2"
+    class: water
+    dps:
+      - id: 2
+        type: boolean
+        name: valve
+  - entity: number
+    translation_key: timer_x
+    translation_placeholders:
+      x: "1"
+    class: duration
+    category: config
+    dps:
+      - id: 17
+        type: integer
+        name: value
+        range:
+          min: 0
+          max: 43200
+        mapping:
+          - scale: 60
+            step: 60
+        unit: min
+  - entity: number
+    translation_key: timer_x
+    translation_placeholders:
+      x: "2"
+    class: duration
+    category: config
+    dps:
+      - id: 18
+        type: integer
+        name: value
+        range:
+          min: 0
+          max: 43200
+        mapping:
+          - scale: 60
+            step: 60
+        unit: min
+  - entity: sensor
+    name: Weather delay remaining
+    class: duration
+    category: diagnostic
+    icon: "mdi:weather-cloudy-clock"
+    dps:
+      - id: 42
+        type: integer
+        name: sensor
+        unit: h
+  - entity: switch
+    name: Smart weather delay
+    icon: "mdi:weather-cloudy-clock"
+    category: config
+    dps:
+      - id: 43
+        type: boolean
+        name: switch
+  - entity: sensor
+    name: Weather
+    class: enum
+    category: diagnostic
+    dps:
+      - id: 44
+        type: string
+        name: sensor
+        optional: true
+        mapping:
+          - dps_val: sunny
+            value: sunny
+            icon: "mdi:weather-sunny"
+          - dps_val: cloudy
+            value: cloudy
+            icon: "mdi:weather-cloudy"
+          - dps_val: rainy
+            value: rainy
+            icon: "mdi:weather-rainy"
+          - dps_val: snowy
+            value: snowy
+            icon: "mdi:weather-snowy"
+          - dps_val: null
+            icon: "mdi:weather-sunny-off"
+            hidden: true
+  - entity: select
+    name: Weather delay
+    icon: "mdi:weather-cloudy-clock"
+    translation_key: timer
+    category: config
+    dps:
+      - id: 45
+        type: string
+        name: option
+        mapping:
+          - dps_val: cancel
+            value: cancel
+          - dps_val: "1"
+            value: "1d"
+          - dps_val: "2"
+            value: "2d"
+          - dps_val: "3"
+            value: "3d"
+          - dps_val: "4"
+            value: "4d"
+          - dps_val: "5"
+            value: "5d"
+          - dps_val: "6"
+            value: "6d"
+          - dps_val: "7"
+            value: "7d"
+  # This variant reports battery as a discrete charge state rather than a
+  # percentage: 6 = 3.05V, 5 = 2.95V, 4 = 2.85V, 3 = 2.75V, 2 = 2.65V,
+  # 1 = 2.60V, 0 = empty. Mapped evenly across the seven states.
+  - entity: sensor
+    class: battery
+    category: diagnostic
+    dps:
+      - id: 47
+        type: string
+        name: sensor
+        unit: "%"
+        mapping:
+          - dps_val: "6"
+            value: 100
+          - dps_val: "5"
+            value: 83
+          - dps_val: "4"
+            value: 67
+          - dps_val: "3"
+            value: 50
+          - dps_val: "2"
+            value: 33
+          - dps_val: "1"
+            value: 17
+          - dps_val: "0"
+            value: 0
+  - entity: binary_sensor
+    class: problem
+    category: diagnostic
+    dps:
+      - id: 53
+        type: bitfield
+        name: sensor
+        mapping:
+          - dps_val: 0
+            value: false
+          - value: true
+      - id: 53
+        type: bitfield
+        name: fault_code
+      - id: 53
+        type: bitfield
+        name: description
+        mapping:
+          - dps_val: 0
+            value: OK
+          - dps_val: 1
+            value: low_battery
+  - entity: binary_sensor
+    name: Valve 1 irrigating
+    class: running
+    category: diagnostic
+    dps:
+      - id: 101
+        type: boolean
+        name: sensor
+  - entity: binary_sensor
+    name: Valve 2 irrigating
+    class: running
+    category: diagnostic
+    dps:
+      - id: 102
+        type: boolean
+        name: sensor
+  - entity: switch
+    name: Signal boost
+    icon: "mdi:signal-variant"
+    category: config
+    dps:
+      - id: 117
+        type: boolean
+        name: switch
+  - entity: sensor
+    class: signal_strength
+    category: diagnostic
+    dps:
+      - id: 118
+        type: integer
+        name: sensor
+        unit: dBm
+  - entity: sensor
+    name: Valve 1 state
+    translation_key: status
+    category: diagnostic
+    class: enum
+    dps:
+      - id: 119
+        type: string
+        name: sensor
+        mapping:
+          - dps_val: idle
+            value: idle
+          - dps_val: manual
+            value: manual
+          - dps_val: spray
+            value: working
+          - dps_val: timing
+            value: scheduled
+      - id: 38
+        type: string
+        name: schedule
+        optional: true
+  - entity: sensor
+    name: Valve 2 state
+    translation_key: status
+    category: diagnostic
+    class: enum
+    dps:
+      - id: 120
+        type: string
+        name: sensor
+        mapping:
+          - dps_val: idle
+            value: idle
+          - dps_val: manual
+            value: manual
+          - dps_val: spray
+            value: working
+          - dps_val: timing
+            value: scheduled
+      - id: 113
+        type: string
+        name: schedule
+        optional: true
+  - entity: sensor
+    name: Upgrade status
+    class: enum
+    category: diagnostic
+    icon: "mdi:package-down"
+    dps:
+      - id: 123
+        type: string
+        name: sensor
+        mapping:
+          - dps_val: upgrade_complete
+            value: complete
+          - dps_val: upgrade_begin
+            value: in_progress
+  - entity: sensor
+    name: Valve 1 last runtime
+    class: duration
+    category: diagnostic
+    dps:
+      - id: 131
+        type: integer
+        name: sensor
+        unit: s
+  - entity: sensor
+    name: Valve 2 last runtime
+    class: duration
+    category: diagnostic
+    dps:
+      - id: 132
+        type: integer
+        name: sensor
+        unit: s