Refactoring of DIY light panel - using latch relays and UART connection via ESPhome


This is the actual POC I have made, and for visible reasons, I want to remake this.

A bit of context:

  1. The panel is managing the wired lights and switches in my house
  2. I’m using dummy buttons on the wall connected directly to some 12v latch relays
  3. 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:

  1. Independent DIN mountable boards
  2. Need to handle 8 lights each
  3. Additional 8 inputs for other switches that are not connected to the relays
  4. Use solid relays
  5. The lights need to work if the MCU dies (happened before)
  6. Individual terminal blocks for each wall switch and NO contacts
  7. 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:

  1. 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)
  2. 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!

1 Like

Isn’t UART good enough? Work a bit in the protocols and you shouldn’t be able to notice the interval.

From the moment I trigger the button in HA and the moment the relay is triggered it takes 1.4 to 1.6 seconds. Is really annoying :smiley:

I couldn’t get why you have an Arduino on this? Wouldn’t the ESP32 be enough?

I need to decouple the “latch relay” part from the esp. I want the lights to work even if the HA or the ESP fails for some reason. Having an Arduino (or any other MCU) is one of the options and in this case, will simulate a latch relay. So short answer, no.