A 6-ch 230V mains underfloor heater valve controller with 6 mains inputs, based on an ESP32S3.

- 6 AC inputs for reading the wall thermostates as fallback (no WiFi/HomeAssistant dies)
- 6 AC outputs using Optotriacs (max. 1,2A / channel)
- UART & I²C for extentions
- DS18S20 OneWire temperature sensor bus (e.g. for reading pipe temperatures)
- 3.3V brick power supply (total 0,4W idle power)

Beware that AC underfloor valves my consume up to 50W the first seconds after switching on. If you switch on multiple channel at a time, the AC input fuse may blow. I use a 1A fast type.

pinout:

#include <WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ArduinoOTA.h>

#define PIN_LED1 5
#define PIN_LED2 6
#define PIN_DS1820 21

#define PIN_THERMOSTATE_1 18
#define PIN_THERMOSTATE_2 17
#define PIN_THERMOSTATE_3 16
#define PIN_THERMOSTATE_4 15
#define PIN_THERMOSTATE_5 14
#define PIN_THERMOSTATE_6 13

#define PIN_VALVE_1 7
#define PIN_VALVE_2 8
#define PIN_VALVE_3 9
#define PIN_VALVE_4 10
#define PIN_VALVE_5 11
#define PIN_VALVE_6 12

#define CHANGE_TH 1500

#define NUM_CH 6
int ch [NUM_CH] = {0,0,0,0,0,0}; // output channel values
int th [NUM_CH] = {0,0,0,0,0,0}; // input channel values

int valve_pins [NUM_CH] = {PIN_VALVE_1, PIN_VALVE_2, PIN_VALVE_3, PIN_VALVE_4, PIN_VALVE_5, PIN_VALVE_6};
int thermostate_pins [NUM_CH] = {PIN_THERMOSTATE_1, PIN_THERMOSTATE_2,PIN_THERMOSTATE_3,PIN_THERMOSTATE_4,PIN_THERMOSTATE_5,PIN_THERMOSTATE_6};

OneWire oneWire(PIN_DS1820);
DallasTemperature sensors(&oneWire);

void setup(){

pinMode(PIN_LED1,OUTPUT);
pinMode(PIN_LED2,OUTPUT);

for( int i = 0; i< NUM_CH; i++){
  pinMode(valve_pins[i],OUTPUT);
  pinMode(thermostate_pins[i],INPUT_PULLUP);
}
}

// thermostate inputs are alternating high/low at mains frequency (~50Hz). You can add a capacitor to filter this out
// So if they are not HIGH within 1.5 sec we assume there is no AC = off
// Not useful if you need faster input response, but ok for this application
void read_inputs(){
static uint32_t last_on [NUM_CH] = {-CHANGE_TH,-CHANGE_TH,-CHANGE_TH,-CHANGE_TH,-CHANGE_TH,-CHANGE_TH}; 

for( int i = 0; i< NUM_CH; i++){
      if(!digitalRead(thermostate_pins[i])){last_on[i] = millis();}
      th[i] = ( (millis() - last_on[i]) < CHANGE_TH);
    }
}
BOM:
https://www.reichelt.de/wifi-ble-modul-802-11-2-4ghz-150mb-s-esp32-s3-mini1n8-p364566.html
https://www.reichelt.de/feinsicherung-5x20mm-flink-f-1a-eska-520-017-p278609.html
https://www.reichelt.de/wannenstecker-fuer-akl-349-2-pol-rm5-0-akl-330-02-p36679.html
https://www.reichelt.de/sicherungshalter-5x20mm-print-mit-abdeckkappe-mta-506000-p279476.html
https://www.reichelt.de/anschlussklemmensystem-6-pol-rm5-0-akl-349-06-p36669.html
https://www.reichelt.de/elko-radial-220-uf-16-v-105-c-low-esr-aec-q200-fc-a-220u-16-p199912.html
https://www.reichelt.de/anschlussklemmensystem-2-pol-rm5-0-akl-349-02-p36665.html
https://www.reichelt.de/wannenstecker-fuer-akl-349-6-pol-rm5-0-akl-330-06-p36683.html
https://www.reichelt.de/siov-s07k275-varistor-275-vrms-350-vdc-1200-a-rm-5-0-epc-b72207-s-27-p239907.html
https://www.reichelt.de/folienkondensator-47nf-630v-rm7-5-mkp4-630-47n-p173028.html
https://www.reichelt.de/1-fach-optokoppler-ac-5kv-35v-50ma-20-300-dip-4-ltv-814-p96806.html
https://www.reichelt.de/widerstand-metalloxyd-820-kohm-0207-1-0-w-5--1w-820k-p1847.html

HLK-PM03
AQH2213
12p/16p USB type-C
pushbuttons
leds
some 0402 smd resistors (10k, 100R)
some 0603 ceramic capacitors
LM1117 3,3V for USB power supply