Integration with Sunbean WIFI Heated Mattress Pad

Hey all!
It would be pretty cool to control this heated mattress pad with Home Assistant. You could do so much with it to improve these chilly winters! I do not see public API documents but they may be available. I will try reaching out to the company.

I’ve figured out that is has port 6668 open and the iPhone app can talk to this directly.

The iPhone app first tries Bluetooth, then using the local LAN and then finally the cloud. In order to observe it I has to disable Bluetooth, enable airplane mode, disable WiFi and use an Ethernet connector for the iPhone to go into a cable where I have a packet capture device connected into PC running wireshark.

It seems each command causes 4-6 round trip messages. The messages are binary. If I use the iPhone to turn it on twice, the two packers sent have several differences.

For the cloud interface, they appear to be encrypting or encoding the JSON within the API calls.

I may try replaying the packets to the IRC port to see if they work a second time.

So far it’s not looking very easy.

Based on their DNS hosts, I believe Sunbeam is using this: https://www.tuya.com/

Hence there is likely documentation for the APIs since they are using and hosted by Tuya. It should also be well implemented and highly secure.

This looks like a good start

and it appears there is an HA integration that is officially supported by Tuya.

So i think the approach is to see if the Sunbeam device that is using Tuya is accessible from the broader Tuya ecosystem

I have a king size Sunbeam heated mattress pad that I was able to set up in Home Assistant with full control after a few hours of experimentation. I would expect the queen size pad with dual heat zones to require the same setup. Here are the high level steps I went through to get it working:

  1. Sunbeam uses Tuya so you need to register the mattress pad in the Smart Life app instead of the Sunbeam app. If you already registered in the Sunbeam app just re-register in the Smart Life app and it will work fine (that is what I did). To register in Smart Life: (+) → Small Home Appliance → Electric Blanket (Wi-Fi). Long press the “check” button on the controller to enter pairing mode. Follow the app prompts. Verify you can control it from Smart Life. The device control screen in Smart Life should look identical to the screen in the Sunbeam app. You can uninstall the Sunbeam app at this point.
  2. Install LocalTuya in HA if you do not already have it.
  3. Add a new integration for LocalTuya and choose the ID of your heated mattress. Use the GUI to input the entity control mappings shown below. For a single zone heated mattress, you probably only need the master controls and can exclude the side A/B mappings. Or maybe use Side A only. I am not sure since I do not have a single zone heated mattress pad to test with.
  4. Test that it works then add the controls to Lovelace. It should provide full control with real-time updates to switch status, heat levels, etc.

Device entity mappings for Sunbeam king size dual zone heated mattress pad:
1: switch - Master Power
14: switch - Side A Power
15: switch - Side B Power

8: switch - Master Preheat Power
24: switch - Side A Preheat
25: switch - Side B Preheat

4: select - Master Heat Level (level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10) (1;2;3;4;5;6;7;8;9;10)
20: select - Side A Heat Level (level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10) (1;2;3;4;5;6;7;8;9;10)
21: select - Side B Heat Level (level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10) (1;2;3;4;5;6;7;8;9;10)

26: select - Side A Set Timer (30m;1h;1h30m;2h;2h30m;3h;3h30m;4h;4h30m;5h;5h30m;6h;6h30m;7h;7h30m;8h;8h30m;9h;9h30m;10h;Stay_On) (.5 hours;1 hour;1.5 hours;2 hours;2.5 hours;3 hours;3.5 hours;4 hours;4.5 hours;5 hours;5.5 hours;6 hours;6.5 hours;7 hours;7.5 hours;8 hours;8.5 hours;9 hours;9.5 hours;10 hours;24 hours)
27: select - Side B Set Timer (30m;1h;1h30m;2h;2h30m;3h;3h30m;4h;4h30m;5h;5h30m;6h;6h30m;7h;7h30m;8h;8h30m;9h;9h30m;10h;Stay_On) (.5 hours;1 hour;1.5 hours;2 hours;2.5 hours;3 hours;3.5 hours;4 hours;4.5 hours;5 hours;5.5 hours;6 hours;6.5 hours;7 hours;7.5 hours;8 hours;8.5 hours;9 hours;9.5 hours;10 hours;24 hours)

28: sensor - Side A Auto Off Timer (Unit: Seconds)
29: sensor - Side B Auto Off Timer (Unit: Seconds)

5 Likes

Thank you for your instructions! What entity type did you choose when adding the blanket to Local Tuya?

1 Like

You will have to set each one of the settings. I started from the top and copy and pasted for each value.

Hero! Thanks for sharing this. I just added my heated blanket to home assistant, but I found adding the entities in the localtuya integration configuration to be a PITA so I added them via configuration.yaml. Posting this here in case someone else finds it useful.

localtuya:
  - host: 192.168.x.x
    device_id: !secret localtuya_bed_id
    local_key: !secret localtuya_bed_key
    friendly_name: Heated Mattress Pad
    protocol_version: "3.3"
    entities:
      - platform: switch
        friendly_name: Master Power
        id: 1
      - platform: switch
        friendly_name: Side A Power
        id: 14
      - platform: switch
        friendly_name: Side B Power
        id: 15
      - platform: switch
        friendly_name: Master Preheat Power
        id: 8
      - platform: switch
        friendly_name: Side A Preheat
        id: 24
      - platform: switch
        friendly_name: Side B Preheat
        id: 25
      - platform: select
        friendly_name: Master Heat Level
        id: 4
        select_options: level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10
        select_options_friendly: 1;2;3;4;5;6;7;8;9;10
      - platform: select
        friendly_name: Side A Heat Level
        id: 20
        select_options: level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10
        select_options_friendly: 1;2;3;4;5;6;7;8;9;10
      - platform: select
        friendly_name: Side B Heat Level
        id: 21
        select_options: level_1;level_2;level_3;level_4;level_5;level_6;level_7;level_8;level_9;level_10
        select_options_friendly: 1;2;3;4;5;6;7;8;9;10
      - platform: select
        friendly_name: Side A Set Timer
        id: 26
        select_options: (30m;1h;1h30m;2h;2h30m;3h;3h30m;4h;4h30m;5h;5h30m;6h;6h30m;7h;7h30m;8h;8h30m;9h;9h30m;10h;Stay_On)
        select_options_friendly: (.5 hours;1 hour;1.5 hours;2 hours;2.5 hours;3 hours;3.5 hours;4 hours;4.5 hours;5 hours;5.5 hours;6 hours;6.5 hours;7 hours;7.5 hours;8 hours;8.5 hours;9 hours;9.5 hours;10 hours;24 hours)
      - platform: select
        friendly_name: Side B Set Timer
        id: 27
        select_options: (30m;1h;1h30m;2h;2h30m;3h;3h30m;4h;4h30m;5h;5h30m;6h;6h30m;7h;7h30m;8h;8h30m;9h;9h30m;10h;Stay_On)
        select_options_friendly: (.5 hours;1 hour;1.5 hours;2 hours;2.5 hours;3 hours;3.5 hours;4 hours;4.5 hours;5 hours;5.5 hours;6 hours;6.5 hours;7 hours;7.5 hours;8 hours;8.5 hours;9 hours;9.5 hours;10 hours;24 hours)
      - platform: sensor
        friendly_name: Side A Auto Off Timer
        id: 28
        unit_of_measurement: "seconds"
      - platform: sensor
        friendly_name: Side B Auto Off Timer
        id: 29
        unit_of_measurement: "seconds"
3 Likes

I spent some more time making this nice for my dashboard!

image

I didn’t like having the heat level as a drop down and prefer using numberbox-card since it has +/- signs and allows for a smaller footprint in the card. In order to do this, I added an input number helper called input_number.side_a_heat_level with a min of 1 and a max of 10. I then created the following two automations:

alias: BED_Set heat level for Side A
description: ''
trigger:
  - platform: state
    entity_id: input_number.side_a_heat_level
condition: []
action:
  - service: select.select_option
    data:
      option: '{{ (states.input_number.side_A_heat_level.state | int) }}'
    target:
      entity_id: select.side_a_heat_level
mode: single
alias: BED_Set Side A input number to match manual heat level change
description: ''
trigger:
  - platform: device
    domain: select
    entity_id: select.side_a_heat_level
    type: current_option_changed
condition: []
action:
  - service: input_number.set_value
    data:
      value: '{{ (states.select.side_a_heat_level.state | int) }}'
    target:
      entity_id: input_number.side_a_heat_level
mode: single

Repeat for Side B.

I also noticed that preheat wasn’t working as it should (it was just setting level to 10/H and not going back down after 30 minutes) so I added an automation that fixes this and also allows me to manually set the preheat time. This will require an input boolean (e.g. input_boolean.preheat_side_a). Automation below.

alias: BED_Preheat Side A
description: ''
trigger:
  - platform: state
    entity_id: input_boolean.preheat_side_a
    to: 'on'
condition: []
action:
  - service: scene.create
    data:
      scene_id: side_a_before
      snapshot_entities: select.side_a_heat_level
  - device_id: xxxxxxx
    domain: select
    entity_id: select.side_a_heat_level
    type: select_option
    option: '10'
  - delay:
      hours: 0
      minutes: 30
      seconds: 0
      milliseconds: 0
  - service: scene.turn_on
    data: {}
    target:
      entity_id: scene.side_a_before
  - service: input_boolean.turn_off
    data: {}
    target:
      entity_id: input_boolean.preheat_side_a
mode: single

Lastly, I added a horizontal-stack card in Lovelace, as follows:

type: horizontal-stack
title: Heated Mattress Pad
cards:
  - type: entities
    title: Side A
    entities:
      - entity: switch.side_a_power
        name: Power
      - entity: input_number.side_a_heat_level
        name: Heat Level
        type: custom:numberbox-card
      - entity: input_boolean.preheat_side_a
        name: Preheat
      - entity: select.side_a_set_timer
        name: Timer
  - type: entities
    title: Side B
    entities:
      - entity: switch.side_b_power
        name: Power
      - entity: input_number.side_b_heat_level
        name: Heat Level
        type: custom:numberbox-card
      - entity: input_boolean.preheat_side_B
        name: Preheat
      - entity: select.side_b_set_timer
        name: Timer

Hopefully this comes in handy for someone in the future :slight_smile:

3 Likes

I’m still experimenting on a guest bed, there are some Home Automations the significant other will not accept without 100% reliability, and I’m not there yet. Local Tuya control is still perplexing to get solid. The gold standard for this device will be for the automation below to work all the time, I’m only at about 70% currently… :upside_down_face:

- alias: Sunbeam Heated Mattress Pad Preheat Complete
  trigger:
  - platform: state
    entity_id: sensor.small_bedroom_sunbeam_bedding_preheat
    from: 'True'
    to: 'False'
  action:
  - service: tts.cloud_say
    entity_id: group.all_googles
    data:
      message: Your Majesty, the Royal Mattress is preheated and ready for your Royal derriere
      language: en-US
      options:
        gender: female

Really great info. Used your configuration,yaml and it just works. Thanks for sharing!! There is a lot of outdated information on how to get the device key as Tuya keeps changing stuff. Best reference is here, which is also linked from the integration home page

I’m probably limiting myself here, but I am not using the LocalTuya integration currently, but rather coding my own MQTT devices using this fantastic python library by Jason Cox, TinyTuya, link below. If for not for any other use, try it to help you get your brain around the Tuya data points, types and ranges. Tuya devices are real wild west, IMHO. However, this space is where many/most of the interesting/useful home automation devices are running. Case in point, this electric heating pad, not going to find that in the zigbee world!

I’m not sure the Tuya world is going to get anymore ‘friendly/standardized/consistent’ to the Home Assistant world. However, if there is software like the HA LocalTuya integration and LocalTuya that gives us opportunities to control some of these devices completely locally, that is good progress.

Good hunting!

ellaizee, your yaml config has worked great and I can control my mattress pad via HA, but I’m running into one problem that I can’t get past. On the second automation you listed, “BED_Set Side A input number to match manual heat level change”, I get the following error when trying to save that automation:

Message malformed: required key not provided @ data[‘device_id’]

I also tried going to developer tools >> services and calling this service via YAML mode:

service: input_number.set_value
data:
value: ‘{{ (states.select.side_a_heat_level.state | int) }}’
target:
entity_id: input_number.side_a_heat_level

And when doing that I get this error:

Failed to call service input_number.set_value. required key not provided @ data[‘value’]. Got None

I tried putting your template value into Developer tools >> template and I get back ‘1’.

I’m not sure what I’m doing wrong. Any ideas?

Thanks!

Got it figured out. Had to add device_id to the trigger section and dug that out of core.entity_registry.

Fantastic instructions — thank you.

There appears to be a “safety feature” that reduces the temperature down to 5 (if previously higher) when turned on remotely (Alexa, or LocalTuya API). This can be dismissed only be pressing the checkmark on the physical mattress controller within an hour of turning on the pad (the checkmark slow blinks to remind you). Is there any way around this aside from an automation that turns the bed off at 59min and back on to (for example) level 8 a minute later?

FYI: As of LocalTuya v4.0.0, configuration using YAML files is no longer supported. Unfortunately the tip from ellaizee no longer works and configuration from the UI is necessary.

I created a workaround for this issue using a Home Assistant scheduled automation. I found that by changing the mattress pad timer value every hour, it is possible to avoid the auto-off feature indefinitely. Changing the timer value will not turn the heater on if it is off. I have mine scheduled to run all the time. This is the automation configuration I use:

platform: time_pattern
hours: '*'

device_id: {device_id_here}
domain: select
entity_id: select.side_a_set_timer
type: select_option
option: 10 hours

device_id: {device_id_here}
domain: select
entity_id: select.side_b_set_timer
type: select_option
option: 10 hours

delay:
  hours: 0
  minutes: 0
  seconds: 0
  milliseconds: 100

device_id: {device_id_here}
domain: select
entity_id: select.side_a_set_timer
type: select_option
option: 24 hours

device_id: {device_id_here}
domain: select
entity_id: select.side_b_set_timer
type: select_option
option: 24 hours