This is the actual POC I have made, and for visible reasons, I want to remake this.
A bit of context:
- The panel is managing the wired lights and switches in my house
- I’m using dummy buttons on the wall connected directly to some 12v latch relays
- To be able to sync the state and also to be able to trigger the lights from HA I added some transistors on the latch relay and connected to some esp32 running ESPhome. Details can be found here: How to create a light entity that takes state from an input pin
Now what I’d like to do is this:
- Independent DIN mountable boards
- Need to handle 8 lights each
- Additional 8 inputs for other switches that are not connected to the relays
- Use solid relays
- The lights need to work if the MCU dies (happened before)
- Individual terminal blocks for each wall switch and NO contacts
- 5 or 12VDC power input
This is an idea of the size and look of each board:
I did some research, and have 2 main options how to achieve this:
- Remake the initial latch relay logic on the board and send / receive signal via I/O pins to the ESP (replicating what I have atm just using solid relays)
- Using a 2nd MCU (I used an Arduino nano for commodity) simulate the “latch” logic in the code and comunicate with the ESP via UART
Pros and cons:
First option (solid state replica on a board)
I tested this schematic, the issue is that the relay is HIGH after power cycle, and I need to add the part for connection with the ESP
PROS:
- tested for more than 1 year, my wife has nothing to complain
- really fast both on getting statuses sync and triggering the lights from HA
CONS:
- some relay modules need to be changed (cheap parts) but this should be fixed by the solid relay
- I need to use 24 I?O ports. 2 I/O ports for each relay (one for status, one for trigger) also 1 for each additional switch input (This can be solved with ESP32-S3)
Second option (2 MCUs and UART comms)
Arduino code:
#include <Arduino.h>
#include <SoftwareSerial.h>
const int relayPin = 8; // Pin connected to the relay
const int buttonPin = 9; // Pin connected to the button
const int ledPin = LED_BUILTIN; // Onboard LED
bool relayState = false; // Current state of the relay
bool lastButtonState = HIGH; // Last button state
bool lastRelayState = false; // Last relay state for change detection
// SoftwareSerial for communication with ESP32
SoftwareSerial espSerial(10, 11); // RX, TX (choose appropriate pins)
void setup()
{
pinMode(relayPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP); // Use internal pull-up resistor
pinMode(ledPin, OUTPUT); // Set onboard LED as output
digitalWrite(relayPin, HIGH); // Ensure relay is off on boot (reversed logic)
digitalWrite(ledPin, LOW); // Ensure LED is off on boot (reversed logic)
Serial.begin(9600); // Serial for debugging
espSerial.begin(9600); // Serial for ESP32 communication
}
void loop()
{
// Read the current button state
bool buttonState = digitalRead(buttonPin);
// Check for button press (LOW state when pressed)
if (buttonState == LOW && lastButtonState == HIGH)
{
// Toggle relay state
relayState = !relayState;
digitalWrite(relayPin, relayState ? LOW : HIGH); // Reverse output for relay
digitalWrite(ledPin, relayState ? HIGH : LOW); // Reverse output for LED
// Send the state via Serial when it changes
if (relayState != lastRelayState)
{
Serial.println(relayState ? "ON" : "OFF"); // Send "ON" or "OFF" for debugging
espSerial.println(relayState ? "ON" : "OFF"); // Send state to ESP32
lastRelayState = relayState; // Update last state
}
delay(200); // Debounce delay
}
// Read from ESP32
if (espSerial.available())
{
String command = espSerial.readStringUntil('\n');
if (command == "TOGGLE") {
relayState = !relayState;
digitalWrite(relayPin, relayState ? LOW : HIGH);
digitalWrite(ledPin, relayState ? HIGH : LOW);
Serial.println(relayState ? "ON" : "OFF");
espSerial.println(relayState ? "ON" : "OFF"); // Confirm state back to ESP32
}
}
// Update last button state
lastButtonState = buttonState;
}
ESP code:
uart:
id: uart_bus
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 9600
debug:
direction: BOTH
dummy_receiver: true
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
button:
- platform: uart
name: "Button"
data: "TOG"
on_press:
- uart.write: "GLE"
PROS:
- Only 10 I/O pins needed, 2 for UART communication, 8 for the addition switches
CONS:
- UART communication between Arduino and ESP is very slow. 1.4 to 1.6 seconds to trigger the light from the HA (probably my code is not well written)
I’d really like to get some feedback, maybe someone have seen similar implementations before. Also I’ll need some help with the ESPhome code for the UART communication option. Is there a faster way to communicate between MCUs? maybe I2C?
Thank you!