This interface was specifically developed and tested for the Tylö Sense Pure heater. Other Sauna360 heaters may also work, but compatibility is not guaranteed. This device does not emulate a panel and, therefore, cannot serve as a replacement.
This project utilizes an ESP32-S3 (ESP32-S3-WROOM-1) paired with an external RS485-to-UART interface based on the MAX485. Although the ESP32-C6 is theoretically capable of handling the task, ESPHome currently lacks support for suitable UART hardware interrupts.
The door sensor used in this project is an ABUS FU7350W.
The external switch with LED feedback used in this project can be found here.
![]() |
---|
Mikrocontroller: PIC32 MX150F128D |
Differential Bus Transceivers: TI SN65176B |
![]() |
---|
Pin | Signal | |
---|---|---|
1 | A | ![]() |
2 | B | |
3 | 12V DC | |
4 | GND |
Pos | Unit | Use pin | Comment | Pin 1 | Pin 2 | Pin 3 | Pin 4 |
---|---|---|---|---|---|---|---|
1 - NTC | Temp. sensor in the room | 2, 3 | 10kΩ. May also be connected at Pos 4 - SEC/NTC. | - | 10kΩ | 10kΩ | - |
2 - EXT SWITCH | External switch | 3, 4 | Start/Stop. Momentary or latching switch | - | - | Switch | Switch |
External switch with LED indication | 2, 3, 4 | Start/stop operation. 12VDC max. 40mA | - | LED GND | Switch | Switch / LED 12V | |
3 - DOOR SWITCH | Door contact (NO) | 3, 4 | - | - | Switch | Switch | |
Door contact (NO) with LED indication | 2, 3, 4 | 12VDC max. 40mA. | - | LED GND | Switch | Switch / LED 12V | |
4 - SEC/NTC | Combined temperature sensor/cut-out in the room | 2, 3 | Only used for certain products. | Sec | 10kΩ | 10kΩ | Sec |
5-8 - RS485 | Control panels | 1, 2, 3, 4 | Tylö Pure control panel, ESP32 (RS485) | A | B | 12V | GND |
![]() |
---|
Baud | Bits | Parity | Stopbit |
---|---|---|---|
19200 | 8 | Even | 1 |
These details have been reverse-engineered by analyzing intercepted communication between a heater and its control panel. As such, the list may not be complete or fully accurate. Further testing and validation may be required to confirm all behaviors and formats.
Start of Frame (SOF) | Address ID | Message Type / Origin | Data | CRC | End of Frame (EOF) |
---|---|---|---|---|---|
0x98 |
0x40 |
0x06 |
0 Bytes | 2 Bytes | 0x9C |
0x07 |
|||||
Explanation:0x06: Sent by the heater as a Keep-Alive request.0x07: Sent by the control panel as a Keep-Alive acknowledgment.
|
Start of Frame (SOF) | Address ID | Message Type / Origin | Code | Data | CRC | End of Frame (EOF) |
---|---|---|---|---|---|---|
0x98 |
0x40 |
0x06 (Heater Request) |
2 Bytes | 0–4 Bytes | 2 Bytes | 0x9C |
0x07 (Panel Command) |
2 Bytes | |||||
0x08 (Heater Data) |
2 Bytes | |||||
0x09 (Panel Data / ACK?) |
2 Bytes |
Code | Description |
---|---|
0x3400 |
Light and Heater Status |
0x4002 |
Bath Time and Maximum Temperature |
0x4003 |
Overheating PCB Limit |
0x6000 |
Temperature Data: Encodes current and target sauna temperature. |
0x7000 |
Request Heater Status Changes: Panel -> Heater |
0x7180 |
Light and Heater Status: Heater -> Panel |
0x9400 |
Total Uptime |
0x9401 |
Remaining Time: Indicates the remaining time of the current sauna session. |
0xB000 |
Error Codes |
0xB600 |
Sensor Errors |
Required timing to send 0x07
(Panel Command) to heater.
![]() |
---|
substitutions:
device_name: "tylo"
external_components:
- source:
type: git
url: https://github.com/f-io/esphome-tylo/
ref: main
refresh: 1s
components: [ sauna360 ]
esphome:
name: ${device_name}
friendly_name: ${device_name}
comment: ${device_name} sauna controller
area: Sauna
esp32:
board: esp32-s3-devkitc-1
logger:
level: WARN
baud_rate: 0
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
power_save_mode: NONE
ssid: !secret wifi_ssid
password: !secret wifi_password
uart:
tx_pin: GPIO41
rx_pin: GPIO42
baud_rate: 19200
data_bits: 8
parity: EVEN
stop_bits: 1
sauna360:
id: sauna360_component
binary_sensor:
- platform: sauna360
heater_status:
name: "Heater State"
- platform: sauna360
light_status:
name: "Light State"
- platform: sauna360
ready_status:
name: "Ready State"
sensor:
- platform: wifi_signal
name: "${device_name} WiFi Signal"
update_interval: 60s
icon: "mdi:wifi"
- platform: sauna360
id: current_temperature_sensor
current_temperature:
name: "Current Temperature"
- platform: sauna360
setting_temperature:
name: "Setting Temperature"
- platform: sauna360
remaining_time:
name: "Remaining Time"
- platform: sauna360
setting_bath_time:
name: "Setting Bath Time"
- platform: sauna360
total_uptime:
name: "Total Uptime"
- platform: sauna360
max_bath_temperature:
name: "Max Bath Temperature"
- platform: sauna360
overheating_pcb_limit:
name: "Overheating PCB Limit"
number:
- platform: sauna360
bath_temperature:
name: "Bath Temperature"
id: bath_temperature
mode: box
bath_temperature_default: 90 # default value
- platform: sauna360
bath_time:
name: "Bath Time"
mode: box
bath_time_default: 300 # default value
- platform: sauna360
max_bath_temperature:
name: "Max Bath Temperature"
mode: box
max_bath_temperature_default: 110 # default value
switch:
- platform: sauna360
light_relay:
name: "Light"
- platform: sauna360
heater_relay:
name: "Heater"
id: heater_relay_switch
text_sensor:
- platform: sauna360
heater_state:
name: "Heating Element"
time:
- platform: homeassistant
climate:
- platform: sauna360
id: sauna_climate
name: "Sauna Climate"
sauna360_id: sauna360_component
bath_temperature_number_id: bath_temperature
heater_relay_id: heater_relay_switch
visual:
min_temperature: 40
max_temperature: 110
temperature_step: 1.0