Smartify a dumb bedwarmer
I have a Perfect Fit SoftHeat heated mattress pad with dumb controls that I wanted to make smarter, mainly so I could turn it on with a timer. This model has a pair of controllers, one for each side of the bed, with a rotary dial for the heat setting and a on/off toggle button.
(with my addition)
You can’t just plug this thing into a smart plug, because the controller always starts up Off when first plugged in. You actually need to toggle the button to get it to turn on, ever.
Parts List
- Perfect Fit SoftHeat heated mattress pad. There are some bad reviews there; do your due diligence. I bought mine in 2013, it lasted 5 years before one side stopped working. The company sent me a replacement, for free, and let me keep my old one. New one is working fine.
- ESP-01S. Like a buck from AliExpress
- ESP-01S Relay Board. These are cool, ESP-01S just plugs right in. Mine cost $1.55 from AliExpress.
- If you have a 3D printer, you can print a little case like mine.
Power
The relay boards have a power regulator on them that steps down to the 5v required for the relay itself, and to 3.3v for the ESP01. I looked up the part, and it’s rated up to 15v input. The output voltage of my bedwarmer power supply is 16v; I called this close enough and just plugged it right in. If you’re more concerned about it, you should regulate it down with some additional parts.
Wiring
Wiring this up is easy, but not quite trivial. GPIO0 runs the relay. But we need one other pin to use as an input to see if the heater output is on or off. I used GPIO3, and bent the pin out so that it did not plug into the yellow riser on the relay board. I connected this pin to a 1Mohm resistor, and from there to the positive side of the wires going to the mattress pad.
There’s a total of 5 wires you need to attach to the controller:
- Power supply in (+16v) to the relay board power connector (+). I just soldered my wire onto where the wires came in from the power supply.
- Power supply ground to the relay board power connector gnd.
- Mattress pad power out (+16v, pwm’ed at a slow rate to adjust output temperature) to the 1Mohm resistor above. The resistor prevents the relatively high voltage from over-saturating the input pin on the esp. Attached at the wires going out the mattress pad. (There are 4 total wires connecting the controller; the grounds are common.)
- SW1: Run a wire from one side of the switch to the relay common (center pin).
- SW2: Run a wire from the other side of the switch to the normally open (NO) pin.
Powering the relay will then close the circuit, acting like a button push. The GPIO3 input will let us determine if the controller is currently heating the pad or not.
Code
There’s a few failsafes I wanted to build in, since it is a heater after all. First, if we get disconnected from Home Assistant for some reason, I don’t want to leave the heater on. So:
api:
# failsafe
on_client_disconnected:
- switch.turn_off: heater
Second, when we’re first booting, make sure that the relay is the “off” position, and, again, make sure the heater is off.
# Make sure relay isn't stuck on, and heater is off at boot
esphome:
on_boot:
- priority: 300
then:
# a script runs asynchronously
- script.execute: force_off
- number.set:
id: brightness
value: 10
script:
- id: force_off
then:
- switch.turn_off: relay
- delay: 300ms
- switch.turn_off: heater
And then the meat: two switches and a sensor. The first switch is hidden from Home Assistant (internal: true
), this toggles the relay momentarily. When we turn on this switch, it connects the relay, and then the switch turns itself off after 300ms, releasing the button. So this looks like a short press and release of the button to the bedwarmer controller. A toggle, but it is blind to whether we toggled on or off. That’s what the second switch is for: it checks the state of the heating element, and if it’s powered, it checks the “is heating” sensor, and acts appropriately: if heating, and you want to turn it off, it toggles. If not heating, and you want to turn it on, it toggles. But if it’s already in the state you want, it doesn’t do anything.
switch:
# Relay shield board
- platform: gpio
pin: GPIO0
name: relay
id: relay
inverted: True
internal: True
restore_mode: ALWAYS_OFF
# Momentary push toggle button at "turn on"
on_turn_on:
- delay: 300ms
- switch.turn_off: relay
# rate limit
- delay: 1s
# Heater on/off switch
- platform: template
name: heater
id: heater
device_class: switch
icon: mdi:bed
restore_mode: ALWAYS_OFF
lambda: |-
return (id(heating).state);
turn_on_action:
- if:
condition:
binary_sensor.is_off: heating
then:
- switch.turn_on: relay
turn_off_action:
- if:
condition:
binary_sensor.is_on: heating
then:
- switch.turn_on: relay
For the sensor, we have a 4 second delayed_off filter. This is because the way the heater works is by turning full on and full off intermittently, with a frequency depending on the warmness dial setting. The longest interval between on and off is 3 seconds, so adding this filter prevents the sensor from just flipping on and off every 3 seconds. Oh, and it turns on the LED when it senses heating, for a visual indicator that the sensor is working.
# Detect heating on gpio3
binary_sensor:
- platform: gpio
name: heating
id: heating
device_class: heat
internal: true
pin:
number: GPIO3
mode:
input: True
pullup: False
inverted: True
filters:
# heating is pwm'ed at a low rate
- delayed_off: 4s
on_press:
then:
- light.turn_on: ledlight
on_release:
then:
- light.turn_off: ledlight
My ledlight is much more complicated than most people care about, but for completeness I’ll include it here. You can adjust the brightness; full brightness was keeping me up.
globals:
- id: blueled_brightness
type: int
restore_value: no
initial_value: '90'
output:
- id: blueled
platform: esp8266_pwm
pin: GPIO02
frequency: 200 Hz
inverted: true
light:
- platform: status_led
name: "led"
id: ledlight
icon: mdi:led-variant-on
output: blueled
restore_mode: ALWAYS_OFF
on_turn_on:
# apparently lambda races turn on, so delay
- delay: 10ms
- lambda: id(blueled).set_level(id(blueled_brightness)/100.0);
Automations
Ok, great, now you’ve got a wifi bed heater, what do you do with it?
- Set up an automation that automatically turns it off 30 minutes after it is turned on. No more waking up overheated.
- Set up an automation to automatically turn it on at 10:00pm, if the temperature is below 45 degrees and if you’re home (e.g. phone connected to wifi). Now your bed is warm and toasty before getting in.
That’s it. All I wanted.