Heat & Glo RF Transmitter
ESPHome has everything you need to emulate your Heat & Glo RF fireplace remote with a very simple hardware setup - 1 pin on an ESP to a $2 433Mhz transmitter.
The hard part was figuring out the codes and the timings - so here you are!
What you need
- ESP with 1 GPIO pin. An ESP-01 should do.
- 433Mhz transmitter.
I got 5 sets of xmit/receivers with antennas for $10 from Amazon.
Wiring
Wiring is dead simple
‘-’ to GND
‘+’ to 3.3v
‘DAT’ to a GPIO pin on your ESP; I used GPIO12 on an ESP32.
‘EN’ not connected
‘TUO’ is “OUT” printed backward; solder the short antenna here. This works 30’ from my fireplace.
You don’t need to use the receivers for this project at all, but if you want to hook one up to decode other RF remotes, it also just takes 1 GPIO pin. (I used GPIO13.)
Receiver on left, transmitter on right.
Code
Once you hook this up, all you need is the appropriate ESPHome configuration yaml. I have one significant lambda in a script that calls remote_transmitter.transmit_raw to actually send out the various signals.
remote_receiver:
pin: GPIO13
# Uncomment below to view signals in debug logs
#dump:
# - raw
tolerance: 50%
filter: 250us
idle: 80ms
buffer_size: 2kb
remote_transmitter:
pin: GPIO12
# RF uses a 100% carrier signal
carrier_duty_percent: 100%
# Heat and Glo RF fireplace remote 2166-330 for RC300
# https://www.amazon.com/Universal-Fireplace-2166-330-Replacement-Transmitter/dp/B0DKTJ5KSK
# Thanks to initial hints from https://github.com/milksteakmatt/Ardufuego/blob/1d156b15717538e092160b09a3677fffbb59ce37/libraries/FireplaceRF/FireplaceRF.h
# 4-bit header pattern, then 6 bytes of data:
# F4E133015EA1 on
# F4E133025FA0 off
# F4E133318E71 flame1
# F4E133328F70 flame2
# F4E13333906F flame3
# F4E13334916E flame4
# F4E13335926D flame5
# F4E133409D62 fan0
# F4E133419E61 fan1
# F4E133429F60 fan2
# F4E13343A05F fan3
# F4E13350AD52 light 0
# F4E13351AE51 light 1
# F4E13352AF50 light 2
# F4E13353B04F light 3
# F4E13354B14E light 4
# F4E13361BE41 aux off
number:
- platform: template
name: Fan Level
icon: mdi:fan
min_value: 0
max_value: 3
step: 1
optimistic: True
restore_value: True
set_action:
- script.execute:
id: decode
code: !lambda |-
std::string codes[]={"409D62","419E61","429F60","43A05F"};
return codes[(int)x];
- platform: template
name: Flame Level
icon: mdi:fire
min_value: 1
max_value: 5
step: 1
optimistic: True
restore_value: True
set_action:
- script.execute:
id: decode
code: !lambda |-
std::string codes[]={"empty","318E71","328F70","33906F","34916E","35926D"};
return codes[(int)x];
- platform: template
name: Light Level
icon: mdi:candelabra-fire
min_value: 0
max_value: 3
step: 1
optimistic: True
restore_value: True
set_action:
- script.execute:
id: decode
code: !lambda |-
std::string codes[]={"50AD52","51AE51","52AF50","53B04F"};
return codes[(int)x];
switch:
- platform: template
name: Fireplace Switch
id: fireplace
icon: mdi:fireplace
optimistic: True
restore_mode: DISABLED
device_class: switch
turn_on_action:
then:
- script.execute:
id: decode
code: "015EA1"
turn_off_action:
then:
- script.execute:
id: decode
code: "025FA0"
button:
- platform: template
name: Fireplace On
icon: mdi:fireplace
on_press:
- switch.turn_on: fireplace
- platform: template
name: Fireplace Off
icon: mdi:fireplace-off
on_press:
- switch.turn_off: fireplace
script:
- id: decode
mode: single
parameters:
code: string
then:
- remote_transmitter.transmit_raw:
repeat:
times: 11
wait_time: 92ms
code: !lambda |-
// Add common prefix
std::string fullcode = "F4E133" + code;
std::vector<int> rawcodes;
// 4-bit header with distinct off times
std::vector<int> header = {900,-460,380,-460,900,-460,380,-1280};
for (int num : header) {
rawcodes.push_back(num);
}
// Decode hex to raw: bytes to bits to rawcode
// 1=900, 0=380, end-of-bit=-680 EndOfByte=-1500
for (size_t i = 0; i < fullcode.length(); i += 2) {
std::string byteString = fullcode.substr(i, 2);
char byteChar = (char)stoi(byteString, nullptr, 16);
for (int j = 7; j >= 0; --j) {
char bit = ((byteChar >> j) & 1);
if (bit == 1) {
rawcodes.push_back(900);
} else {
rawcodes.push_back(380);
}
if (j)
rawcodes.push_back(-680);
}
rawcodes.push_back(-1500);
}
ESP_LOGD("fireplace", "hexcode %s, opcode count %d", fullcode.c_str(), rawcodes.size());
std::string csv;
for (int num : rawcodes) {
csv += std::to_string(num) + " ";
}
ESP_LOGD("fireplace", "opcodes: %s", csv.c_str());
return rawcodes;