ProBreeze OmniDry 12L (PB-D-18W-WF) with localtuya

Hi everybody

I integrated the ProBreeze PB-D-18W-WF into Home Assistant and wanted to share the procedure and obstacles I stumbled across.

The ProBreeze PB-D-18W-WF is a “smart dehumidifier” using Wi-Fi and the Tuya protocol for communication. An important objective has been that the device shall still be accessible in case the cloud is not available which is why I decided to go with localtuya. Since Tuya is a secure protocol, the procedure to get it up and running within Home Assistant is a bit more complicated:

  1. Sign up to Tuya Smart on the mobile device using the Tuya Smart app (iOS / Android)
  2. Connect the ProBreeze to your home Wi-Fi using the Tuya Smart app (the device is now also in the Tuya cloud)
  3. Sign up to Tuya’s Developer Platform
  4. Create a Smart Home project in your Tuya developer account and link the Tuya Smart app account to it
  5. Retrieve Tuya client and ProBreeze device IDs and secrets/keys required to set up localtuya from Tuya’s Developer Platform

You’ll find comprehensive step-by-step instructions on how to set up Tuya devices in Home Assistant via localtuya in this YouTube tutorial.

Home Assistant will detect all data points supported by the device. The functionality and possible values behind those data points (which are addressed by respective IDs) can be queried via Tuya Developer Platform…

Query Properties:

{
  "result": {
    "properties": [
      {
        "code": "switch",
        "custom_name": "",
        "dp_id": 1,
        "type": "bool",
        "value": true
      },
      {
        "code": "dehumidify_set_value",
        "custom_name": "",
        "dp_id": 2,
        "type": "value",
        "value": 60
      },
      {
        "code": "fan_speed_enum",
        "custom_name": "",
        "dp_id": 4,
        "type": "enum",
        "value": "high"
      },
      {
        "code": "mode",
        "custom_name": "",
        "dp_id": 5,
        "type": "enum",
        "value": "Auto"
      },
      {
        "code": "humidity_indoor",
        "custom_name": "",
        "dp_id": 6,
        "type": "value",
        "value": 59
      },
      {
        "code": "temp_indoor",
        "custom_name": "",
        "dp_id": 7,
        "type": "value",
        "value": 21
      },
      {
        "code": "anion",
        "custom_name": "",
        "dp_id": 10,
        "type": "bool",
        "value": true
      },
      {
        "code": "child_lock",
        "custom_name": "",
        "dp_id": 16,
        "type": "bool",
        "value": false
      },
      {
        "code": "countdown_set",
        "custom_name": "",
        "dp_id": 17,
        "type": "enum",
        "value": "cancel"
      },
      {
        "code": "fault",
        "custom_name": "",
        "dp_id": 19,
        "type": "bitmap",
        "value": 0
      },
      {
        "code": "filter_reset",
        "custom_name": "",
        "dp_id": 20,
        "type": "bool",
        "value": true
      },
      {
        "code": "filter_life",
        "custom_name": "",
        "dp_id": 23,
        "type": "value",
        "value": 0
      },
      {
        "code": "temp_unit_convert",
        "custom_name": "",
        "dp_id": 24,
        "type": "enum",
        "value": "c"
      },
      {
        "code": "runtime_total_reset",
        "custom_name": "",
        "dp_id": 28,
        "type": "bool",
        "value": false
      },
      {
        "code": "client_id",
        "custom_name": "",
        "dp_id": 102,
        "type": "value",
        "value": 0
      },
      {
        "code": "type_of_equipment",
        "custom_name": "",
        "dp_id": 104,
        "type": "value",
        "value": 4
      }
    ]
  }
}

Get the specifications and properties of the device:

{
  "result": {
    "category": "cs",
    "functions": [
      {
        "code": "switch",
        "desc": "{}",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "dehumidify_set_value",
        "desc": "{\"unit\":\"%\",\"min\":30,\"max\":80,\"scale\":0,\"step\":5}",
        "type": "Integer",
        "values": "{\"unit\":\"%\",\"min\":30,\"max\":80,\"scale\":0,\"step\":5}"
      },
      {
        "code": "fan_speed_enum",
        "desc": "{\"range\":[\"low\",\"high\"]}",
        "type": "Enum",
        "values": "{\"range\":[\"low\",\"high\"]}"
      },
      {
        "code": "anion",
        "desc": "{}",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "child_lock",
        "desc": "{}",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "countdown_set",
        "desc": "{\"range\":[\"cancel\",\"1h\",\"2h\",\"3h\"]}",
        "type": "Enum",
        "values": "{\"range\":[\"cancel\",\"1h\",\"2h\",\"3h\"]}"
      },
      {
        "code": "filter_reset",
        "desc": "{}",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "temp_unit_convert",
        "desc": "{\"range\":[\"c\",\"f\"]}",
        "type": "Enum",
        "values": "{\"range\":[\"c\",\"f\"]}"
      },
      {
        "code": "runtime_total_reset",
        "desc": "{}",
        "type": "Boolean",
        "values": "{}"
      }
    ],
    "status": [
      {
        "code": "switch",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "dehumidify_set_value",
        "type": "Integer",
        "values": "{\"unit\":\"%\",\"min\":30,\"max\":80,\"scale\":0,\"step\":5}"
      },
      {
        "code": "fan_speed_enum",
        "type": "Enum",
        "values": "{\"range\":[\"low\",\"high\"]}"
      },
      {
        "code": "humidity_indoor",
        "type": "Integer",
        "values": "{\"unit\":\"%\",\"min\":20,\"max\":90,\"scale\":0,\"step\":1}"
      },
      {
        "code": "temp_indoor",
        "type": "Integer",
        "values": "{\"unit\":\"℃\",\"min\":5,\"max\":38,\"scale\":0,\"step\":1}"
      },
      {
        "code": "anion",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "child_lock",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "countdown_set",
        "type": "Enum",
        "values": "{\"range\":[\"cancel\",\"1h\",\"2h\",\"3h\"]}"
      },
      {
        "code": "fault",
        "type": "Bitmap",
        "values": "{\"label\":[\"FULL\",\"Cleaning\",\"E1\",\"CL\",\"CH\",\"LO\",\"COIL\",\"MOTOR\"]}"
      },
      {
        "code": "filter_reset",
        "type": "Boolean",
        "values": "{}"
      },
      {
        "code": "filter_life",
        "type": "Integer",
        "values": "{\"unit\":\"%\",\"min\":0,\"max\":100,\"scale\":0,\"step\":1}"
      },
      {
        "code": "temp_unit_convert",
        "type": "Enum",
        "values": "{\"range\":[\"c\",\"f\"]}"
      },
      {
        "code": "runtime_total_reset",
        "type": "Boolean",
        "values": "{}"
      }
    ]
  }
}

Home Assistant configuration and card look as follows (I only mapped data points relevant to me):

    "entries": [
      {
        "created_at": "2024-12-17T15:41:49.714074+00:00",
        "data": {
          "region": "eu",
          "username": "localtuya",
          "no_cloud": false,
          "client_id": "$ClientID",
          "client_secret": "$ClientSecret",
          "user_id": "$UID",
          "devices": {
            "$DeviceID": {
              "friendly_name": "Luftentfeuchter",
              "host": "10.0.0.14",
              "local_key": "$LocalKey",
              "protocol_version": "3.4",
              "enable_debug": false,
              "entities": [
                {
                  "friendly_name": "Power",
                  "current": 1,
                  "restore_on_reconnect": false,
                  "is_passive_entity": false,
                  "id": 1,
                  "platform": "switch"
                },
                {
                  "friendly_name": "Target Humidity",
                  "min_value": 30.0,
                  "max_value": 80.0,
                  "step_size": 5.0,
                  "restore_on_reconnect": false,
                  "is_passive_entity": false,
                  "id": 2,
                  "platform": "number"
                },
                {
                  "friendly_name": "Fan Speed",
                  "select_options": "low;high",
                  "select_options_friendly": "Low;High",
                  "restore_on_reconnect": false,
                  "is_passive_entity": false,
                  "id": 4,
                  "platform": "select"
                },
                {
                  "friendly_name": "Mode",
                  "select_options": "Auto;Continuities;Sleep",
                  "select_options_friendly": "Auto (Target);Dry (Continuous);Night",
                  "restore_on_reconnect": false,
                  "is_passive_entity": false,
                  "id": 5,
                  "platform": "select"
                },
                {
                  "friendly_name": "Current Humidity",
                  "unit_of_measurement": "%",
                  "device_class": "humidity",
                  "id": 6,
                  "platform": "sensor"
                },
                {
                  "friendly_name": "Current Temperatur",
                  "unit_of_measurement": "°C",
                  "device_class": "temperature",
                  "id": 7,
                  "platform": "sensor"
                },
                {
                  "friendly_name": "Fault",
                  "id": 19,
                  "platform": "sensor"
                }
              ],
              "add_entities": false,
              "model": "Pro Breeze 12L Compressor Dehumidifier",
              "device_id": "$DeviceID",
              "dps_strings": [
                "1 (value: True)",
                "2 (value: 60)",
                "4 (value: high)",
                "5 (value: Auto)",
                "6 (value: 60)",
                "7 (value: 20)",
                "10 (value: True)",
                "16 (value: False)",
                "17 (value: cancel)",
                "19 (value: 0)",
                "20 (value: True)",
                "24 (value: c)",
                "102 (value: 0)",
                "104 (value: 4)"
              ],
              "product_key": "$ProductID"
            }
          },
          "updated_at": "1734458280932"
        },
        "discovery_keys": {},
        "disabled_by": null,
        "domain": "localtuya",
        "entry_id": "$EntryID",
        "minor_version": 1,
        "modified_at": "2024-12-17T17:58:00.932129+00:00",
        "options": {},
        "pref_disable_new_entities": false,
        "pref_disable_polling": false,
        "source": "user",
        "title": "localtuya",
        "unique_id": "$UID",
        "version": 2
      }
    ]

(All IDs and secrets/keys have been replaced by placeholders.)


(The power consumption is coming from a smart socket. The device sips a bit under 1W in standby with it still being fully accessible over Wi-Fi and about 150W with the compressor running. The 12L device can easily handle a 20m² dry room with humidities up to 80%.)

I have yet to figure out how I can map the fault data point (Tuya type ‘Bitmap’)…

"code": "fault",
"type": "Bitmap",
"values": "{\"label\":[\"FULL\",\"Cleaning\",\"E1\",\"CL\",\"CH\",\"LO\",\"COIL\",\"MOTOR\"]}"

… to meaningful strings (e.g. “Tank full”) in the UI instead of a numeric value representing the error/fault bit field. Any hint would be appreciated. I may map everything >0 to “Tank full” which will probably be the only error I will get on a regular basis.

4 Likes

Did an automation for this now:

- id: '1734536485263'
  alias: Dehumidifier - notify on tank full
  description: ''
  triggers:
  - trigger: numeric_state
    entity_id:
    - sensor.fault
    above: 0
  conditions: []
  actions:
  - action: notify.mobile_app_idanny
    data:
      message: Dehumidifier tank full
  mode: single

A hint on how to map a Tuya ‘Bitmap’ would still be highly appreciated.

Thanks for taking the time to sort this out. I’ve just bought one of these and have done all the Tuya developer stuff and have just the Power button added as an entity (which works fine) Is there a simpler way of adding all the entities you show in your screen grab?


Figure it out, manually added them all.

To decode the fault bitmap, you can use helper. You can have a single helper that will display the list of Errors or one helper per type of error.

  1. if you want a single sensor with the list of errors, create an helper (Settings → Devices → Helpers)
    Choose a helper of type template, then choose sensor. Then use the following template
{% set value = states('sensor.omnidry_12l_one_fault') | int %}
{% set labels = ["FULL","Cleaning","E1","CL","CH","LO","COIL","MOTOR"] %}
{% set bits = [1,2,4,8,16,32,64,128] %}
{% set data = namespace(active=[]) %}

{% for i in range(labels | length) %}
  {% if (value | bitwise_and(bits[i])) > 0 %}
    {% set data.active = data.active + [labels[i]] %}
  {% endif %}
{% endfor %}

{{ data.active | join(', ') if data.active else "OK" }}

Remplace omnidry_12l_one_fault by the name of your sensor !
You can of course change labels to more meaningful names (ex: “Temperature to low” instead of CL)

  1. If you want one sensor by faults, create helpers (Settings → Devices → Helpers)
    Choose a helper of type template, select binary sensor, then use the following template
    {{ (states('sensor.omnidry_12l_one_fault') | int | bitwise_and(X)) > 0 }}

Remplace omnidry_12l_one_fault by the name of your sensor !
Remplace X by

  • 1 for a Tank Full sensor
  • 2 for the Cleaning error
  • 4 for the E1 error
  • 8 for CL (temperature is bellow 5°C)
  • 16 for CH (temperature is over 38°C)
  • 32 for LO (Humidity is bellow 25%)
  • 64 for COIL
  • 128 for MOTOR

See example bellow

1 Like