Browse Source

Add Breville BAD358 All Climate 2-in-1 Dehumidifier (#5760)

# Breville All Climate 2-in-1 Dehumidifier & Purifier (BAD358)
## Intro
I've had this device set up with an ad-hoc
[localtuya](https://github.com/rospogrigio/localtuya) configuration for
almost a year now, but after a recent re-install I decided to give
**tuya-local** a go.

At the moment, the `alecoair_d12_dehumidifier` is the suggested
configuration for this device, and it supports only *basic*
functionality, and the temp+humidity is the reported with the wrong
scale. I've used it as a base for this configuration.

Since I'm contributing upstream, I've tried to be thorough with
identifying all of the DPs to the best of the ability, and I've verified
that all of the values currently exposed through the official Tuya app
are reflected in this configuration.

There are a number of DPs which report values which I haven't been able
to observe. Its not clear to me what these are, or how I could get the
values to change through any device functionality documented in the
manual.

## Device Details
**Product page**: https://www.breville.com/en-au/product/bad358
**Product ID**: `lcjqatjseirq4msl`

## Device DPs
### Identified
| DP | Type | Function | Values |
|----|------|----------|--------|
| 1 | boolean | Power switch | on / off |
| 2 | integer | Target humidity | 30–80, step 5 |
| 4 | string | Fan speed | low / mid / high |
| 5 | string | Mode | Auto, Dehumi (→ Continuous), Drying (→ Laundry),
AirPurification (→ Purify) |
| 6 | integer | Current humidity | raw ÷ 10 = % |
| 7 | integer | Temperature | raw ÷ 10 = °C |
| 11 | boolean | All lights | on / off |
| 16 | boolean | Child lock | on / off |
| 101 | integer | Filter days remaining | days |
| 102 | string | Oscillation | stop (→ Fixed), 80angle (→ Open), swing
(→ Swing) |
| 103 | integer | Timer | 0–12 hours |
| 104 | boolean | Button sound | on / off |
| 105 | boolean | Humidity light | on / off |
| 106 | boolean | Tank light | on / off |
| 108 | boolean | Tank OK | true = present & not full, false = needs
attention |

### Unidentified
| DP | Type | Observed values |
|----|------|-----------------|
| 14 | boolean | false |
| 18 | integer | 0 |
| 19 | bitfield | 0 |
| 23 | integer | 0 |
| 109 | boolean | false |
| 110 | boolean | false |
| 111 | boolean | false |

## Testing
I have run the following tests locally before creating the PR:
- `pytest tests/test_device_config.py`
- `yamllint` over my yaml file

## AI Use
I've used **OpenCode** to code these changes, using the **DeepSeek V4
Flash** model over **OpenRouter** with **high** reasoning.

I have read and understood this code, which was necessary as I've been
manually going through and verifying the functionality for each DP that
I've documented above.

The tables above are generated by my agent, but all of the prose written
in this PR is my own.

---------

Co-authored-by: Jason Rumney <make-all@users.noreply.github.com>
Denis Milanović 1 day ago
parent
commit
ee5b93bdf4

+ 166 - 0
custom_components/tuya_local/devices/breville_bad358_dehumidifier.yaml

@@ -0,0 +1,166 @@
+name: Dehumidifier
+products:
+  - id: lcjqatjseirq4msl
+    manufacturer: Breville
+    model: the All Climate 2-in-1 Dehumidifier & Purifier
+    model_id: BAD358
+entities:
+  - entity: humidifier
+    class: dehumidifier
+    translation_only_key: extended
+    dps:
+      - id: 1
+        name: switch
+        type: boolean
+      - id: 2
+        name: humidity
+        type: integer
+        range:
+          min: 30
+          max: 80
+        mapping:
+          - step: 5
+      - id: 5
+        name: mode
+        type: string
+        mapping:
+          - dps_val: Auto
+            value: auto
+          - dps_val: Dehumi
+            value: continuous
+          - dps_val: Drying
+            value: laundry
+          - dps_val: AirPurification
+            value: purify
+      - id: 6
+        name: current_humidity
+        type: integer
+        mapping:
+          - scale: 10
+  - entity: fan
+    dps:
+      - id: 1
+        type: boolean
+        name: switch
+      - id: 4
+        type: string
+        name: speed
+        mapping:
+          - dps_val: low
+            value: 33
+          - dps_val: mid
+            value: 66
+          - dps_val: high
+            value: 100
+  - entity: sensor
+    class: temperature
+    dps:
+      - id: 7
+        type: integer
+        name: sensor
+        unit: C
+        class: measurement
+        mapping:
+          - scale: 10
+  - entity: sensor
+    translation_key: filter_life
+    class: duration
+    dps:
+      - id: 101
+        type: integer
+        name: sensor
+        unit: d
+  - entity: select
+    name: Oscillation
+    dps:
+      - id: 102
+        type: string
+        name: option
+        mapping:
+          - dps_val: stop
+            value: "Fixed"
+          - dps_val: 80angle
+            value: "Open"
+          - dps_val: swing
+            value: "Swing"
+  - entity: select
+    translation_key: timer
+    category: config
+    dps:
+      - id: 103
+        type: integer
+        name: option
+        optional: true
+        mapping:
+          - dps_val: 0
+            value: cancel
+          - dps_val: 1
+            value: "1h"
+          - dps_val: 2
+            value: "2h"
+          - dps_val: 3
+            value: "3h"
+          - dps_val: 4
+            value: "4h"
+          - dps_val: 5
+            value: "5h"
+          - dps_val: 6
+            value: "6h"
+          - dps_val: 7
+            value: "7h"
+          - dps_val: 8
+            value: "8h"
+          - dps_val: 9
+            value: "9h"
+          - dps_val: 10
+            value: "10h"
+          - dps_val: 11
+            value: "11h"
+          - dps_val: 12
+            value: "12h"
+  - entity: lock
+    translation_key: child_lock
+    category: config
+    dps:
+      - id: 16
+        type: boolean
+        name: lock
+  - entity: switch
+    translation_key: sleep
+    category: config
+    dps:
+      - id: 11
+        type: boolean
+        name: switch
+        mapping:
+          - dps_val: true
+            value: false
+          - dps_val: false
+            value: true
+  - entity: switch
+    translation_key: keytone
+    category: config
+    dps:
+      - id: 104
+        type: boolean
+        name: switch
+  - entity: light
+    name: Humidity light
+    category: config
+    dps:
+      - id: 105
+        type: boolean
+        name: switch
+  - entity: light
+    name: Tank light
+    category: config
+    dps:
+      - id: 106
+        type: boolean
+        name: switch
+  - entity: binary_sensor
+    translation_key: tank_full
+    dps:
+      - id: 108
+        type: boolean
+        name: sensor