Looking For Advice For: Non-WiFi Based Solution For Sharing Data Between ESP32's

Summary: Seeking advice for a non-WiFi based solution to share data between 5 ESP32’s that I use to controle a ventilation system (Open-Air components, 4 valves and the main box controller). Looking to have one master device connected to wifi and then four slaves that only communicate with the master. The goal is to reduce the active WiFi devices in my network as it seems excessive to have 5 separate wifi devices in a 50x50x25cm space. Open to wired or wireless options (but leaning towards wired as it’s more reliable).

A recommended protocol/method for sending custom messages over a wired connection between ESP devices would already be a sufficient solution. I could then use lambdas to turn those messages in sensors/buttons/etc… Ofcourse if there is a better/alternative/recommend way to achieve the same functionality I would also be very interested!


Details

Hello everyone,

I recently bought some pre-made components from Tindie from the Open-Air project, to upgrade/smartify my home ventilation. I now have 4 valves and a controller for the main box, each with its own ESP32. Having all 5 devices connect separately to WiFi in close proximity seems inefficient. I’m looking for a non-WiFi based communication method where a single wifi connected ESP32 acts as a master to control and relay messages from the others.

Background:

  • Setup: 5 ESP32 devices within a 50x50x25cm box, controlling valves, a main fan, and reading an air sensor.
  • State: System is running smoothly atm but I feel like there should be a better way to expose the in total 8 variables to home assistant. (4 cover components, a fan component, and an AIO humidity/temperature/CO2 sensor.) I don’t think that this should require 5 wifi devices, especially because they are in such close proximity.
  • Hardware Limitation: I bought pre-made components because its a cleaner solution than DIY, but it does mean I cannot simply reconnect the motors and sensors to a single esp32 controller as each module is a single pcb. Each PCB does expose a few unused pins that I intend to use to facilitate the communication between the devices. TX, RX, GND (used for the initial wired install) are available for sure, not 100% on what the other exposed pins are, but I can find out if needed.

Goal:

Reduce WiFi congestion by using a non-WiFi based communication method between the ESP32’s that facilitates sharing sensor data and commands, with only the master device connecting to WiFi.

Looking For:

  • Non-WiFi Solutions: Open to wired (I2C, SPI, UART), Bluetooth, or something else you think would be suitable.
  • Simplicity and Reliability: Ideally a straightforward, reliable method would be used that doesn’t rely on deprecated custom components in ESPHome (e.g. no: I2C, UART, or SPI custom components).

Questions:

  1. Experience with Similar Setups: Has anyone connected multiple ESP32s without WiFi? What was your approach?
  2. Recommendations: Any protocols or setups recommended for this kind of system?
  3. Considerations: Any potential issues or complexities I should be aware of that I might be overlooking or I could run into?

I appreciate the neatness of the Open-air solution but want to optimize the system to avoid WiFi overload. Any advice, links to resources, or insights into managing such a project within ESPHome’s framework would be incredibly helpful.

Thanks in advance for your support and suggestions!

Ps. Once/if I find an effective way to share data between the devices I intend to also configure an on/off switch for the wifi of the slave devices. (Which I expect to be trivial to implement once I find an effective way for the devices to communicate.) This way I can still make use of the ota update feature of esphome when desired and I will therefor only need to send simple messages between devices, no need to support firmware updates or anything complex like that.

.

Disclaimer: I am in no way affiliated with Open-Air, other than that I own some of the devices, nor do I benefit from the sales of said devices. Tindie shop links were provided as the site contains a summary of the devices I am working with and provide further links to relevant sources ie. github repos. I in no way benefit financially from anyone clicking-on/following any links in this post.

Are 5 lowish bandwidth devices going to be such a problem to your wifi? I get what you are trying, but priorities?

1 Like

You are absolutely right, and my Wifi network is fine atm so it’s not so much an issue that needs solving as that it is an interesting problem to work on.

As I couldn’t find an obvious solution on the forums or google and it seemed like an interesting challenge, I figured I would see if there might be some people in the community that had something useful to chip in before I try to reinvent the wheel.

The other reason was that the ESPHome pages that did seem relevant all had the deprecation warning (I2C, UART, SPI custom components) but I couldn’t find any clear info on a recommended “NEW” method for achieving what is described on those pages.

You can use ESP-Now to connect the devices.
You just need to program the devices yourself, because the ESP-Now is not that well implemented into HA.

I was looking up the details of ESP-Now to see if it would work, but it also seems to have some challenges associated with implementation and doesn’t seem like it will improve the reliability. As I was reading up on it however, I found this in one of your previous posts.

How would you recommend setting up the link between “them” if not using ESP-Now?

You would like them together with a serial connection.
One ESP device on WiFi and another on ESP-Now.
There are also solutions with just one ESP device, but that require the ESP-Now channel and the WiFi channel to be the same and since the channel will be hard coded into the ESP-Now setup, then it means the WiFi channel will be locked too with this setup.
A locked WiFi channel might work with some WiFi setups, but not all, and especially Mesh setups might be an issue.

If you devices comply with the matter definition for a climate device, then you might also look into the Espressif ZeroCode solution.

Do you know if ESPHome supports this natively, what protocol would you use?
I found the following documentation on I2C, UART, SPI custom components, but all of these pages have deprecation warnings.

I2C for example looks promising but the I2C core component documentation is very limited and doesn’t explain how to send or process received messages if they are not from a supported sensor type. So I am not sure how I would use serial (unless I start writing my own C code but was hoping to avoid that as much as possible :sweat_smile: as it’s been a while since I did anything with C haha).

Does this help? ESPHome to ESPHome direct communication? - #21 by KG3RK3N

You need to write your own C code.

I would have thought this would be the best solution if you do really only need one esp. Reduces integration complexity. Which may end up being more reliable.

Edit: Sorry, I misread cannot as can. Facepalm.

Yes thank you, this is definitely helpful!

The drawback of UART is that it can only connect 2 devices (as I understand it). I2C, on the other hand, facilitates connecting multiple slave devices, which would let me connect all. Never the less I think that, unless someone posts a better (pre-made) solution, I am going to try make an I2C equivalent of this project.

Thank you for the link though, will certainly be helpful :slight_smile: Lets see how far I get… And if I get stuck, this is a good fallback to at least half the number of devices connected to wifi :sweat_smile:

Alright, Thanks for the info.

If you are going with I2C then remember to have a common ground or at least a ground that is managed, otherwise your pull ups or downs will fail.

Ive asked myself this same question as i have 47 esphome nodes on my network, which by the way doesnt seem to have any noticeably negative effects. I pondered this questiin though because, i didnt want to wait untill there were negative effects.

So, it sounds like 4 if the esp32 boards just open a vent, corect? How does it open it? Servo?

If one device is the master and its sending commands to 4 valves then just use something like RF. You dont even need an esp32 at each valve.
https://www.amazon.com/DieseRC-Universal-Wireless-Receiver-Transmitter/dp/B098WGK35L/ref=mp_s_a_1_2_sspa?crid=19GLAEOP14JDN&keywords=rf+relay+12v&qid=1707582864&sprefix=rf+relay%2Caps%2C272&sr=8-2-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9waG9uZV9zZWFyY2hfYXRm&psc=1

Dont let the remote confuse you. All you habe to do is copy the rf codes and then transmit them from the master. I did something similar in my garage and the range on these is really good. I can trigger relays in my detached garage from 60’ away no problem.

If you have a way to directly wire these from the master esp32, obviously thats the best option.

RF requires a bit more if you want to be able to handle states.
Just sending the command will only give you assumed state. You need a reply and also regular updates of states to make it work right.

1 Like

You can actually just send RF/IR codes straight across wires if you like! I.e you don’t even need rf/ir transmitters/recievers if you can wire them together.

My dunny project works like that.

But I agree rf/ir is not a great readymade protocol for these reasons.

Modbus looks like an interesting protocol, but doesn’t seem to be a good hardware match.

Took me a little while to get around to this again but I had some time today so here’s an update. I liked the suggestion to

What I particularly liked about this component is that:

  • It lets me build a solution that can be implemented as both a wired connection as well as a local wireless connection.
  • The basic ESPHome component(s) facilitate writing and reading custom commands. This everything can be made through templates.

I might combine this with something similar to the chip select pin of the SPI protocol so I can use a single remote receiver and not worry about overlapping incoming data. This however wouldn’t work with a wireless connection in which case I would go for something similar to the addressing used in I2C. So far I’ve just been playing around with how I want to send custom data. I also still need to read up a lot on all the parameters of the remote transmit and receive components to ensure my custom commands implementation is robust enough to also handle the noise of wireless communication.

The configuration below is just a first try at getting a chip to talk to itself using the remote component. Currently I plan on using the first value in the raw data array as the Id of the slave device and the second to last value as a checksum. With my current wired implementation the transmission signals are very robust and I have yet to see a value get corrupted in transmission. Nevertheless there is probably a whole lot of stuff I can add to improve this.

Here is my current code so far:

remote_receiver:
  pin:
    number: GPIO17
    inverted: false
  dump: raw
  on_raw:
    then:
    - script.execute: 
        id: check_validity
        received_data_array: !lambda return x;

remote_transmitter:
  id: my_transmitter
  pin: GPIO16
  carrier_duty_percent: 100%

switch:
  - platform: template
    name: "wifi"
    internal: True
    restore_mode: ALWAYS_ON
    turn_on_action:
      then:
        - wifi.enable:
    turn_off_action:
      then:
        - wifi.disable:          
  - platform: template
    name: "sendState"
    turn_on_action:
      - script.execute: send_state

globals:
  - id: my_states_array
    type: std::vector<int>
    initial_value: '{500,333,333,333,333,333}'

sensor:
  - platform: template
    id: sensor_1
    name: "Sensor 1 value"
    lambda: |-
      return 0;
    update_interval: never

number:
  - platform: template
    name: "Number 1"
    optimistic: true
    initial_value: 1
    min_value: 1
    max_value: 100
    step: 1
    on_value:
      then:
        - lambda: |-
            id(my_states_array)[2] = x * 10; 
        - script.execute: send_state

script:
  - id: wifi_on
    then:
      - wifi.enable:
      - lambda: |-
          id(my_states_array)[1] = 550; 
  - id: wifi_off
    then:
      - wifi.disable:        
      - lambda: |-
          id(my_states_array)[1] = 880;
  - id: check_validity
    parameters:
      received_data_array: int[]
    then:
    - lambda: |-
        std::vector<int> x = received_data_array; // Example values
        ESP_LOGD("main", "Printing vector contents:");

        int sum_of_array = 0;

        for (size_t i = 0; i < x.size()-2; ++i) {
            x[i] = std::abs(x[i]);
            sum_of_array += x[i];
        };

        x[-1] = std::abs(x[-1]);

        if (sum_of_array == x[-1] ) {
          ESP_LOGD("main", "Checksum Check FAILED!!!!!!!!!!!");
          id(check_validity).stop();
        } else {
          ESP_LOGD("main", "Checksum Check Passed");
        };

        id(sensor_1).publish_state( x[2]/10 );
 
  - id: send_state
    then:
      - remote_transmitter.transmit_raw:
          code: !lambda |-
            std::vector<int> original_values = id(my_states_array); // Example values
            std::vector<int> transmit_values;
            bool make_negative = false;

            // Calculate the sum of all values in the array
            int sum_of_array = 0;
            for (int value : original_values) {
                sum_of_array += value;
            }
            
            // If the array length is an even number at this point, add the number (333) to the end
            if (original_values.size() % 2 == 0) {
                original_values.push_back(333);
            } 

            // Add the calculated value to the end of the array
            original_values.push_back((2000 - (sum_of_array % 2000)) * (make_negative ? -1 : 1));
            ESP_LOGD("main", "CheckSum: %i", (2000 - (sum_of_array % 2000)) * (make_negative ? -1 : 1));

            // Add the number (333 to the end)
            original_values.push_back(333);



            // Iterate over the original values, making every second value negative
            for (int value : original_values) {
                transmit_values.push_back(make_negative ? -value : value);
                make_negative = !make_negative; // Toggle the flag
            }

            // Now transmit the modified array
            return {transmit_values};

I’m actually very pleased with the results so far, might eventually even see if I can make this into an esphome component where an array is defined on 2 devices and then some backend code facilitates communication between two esphome modules so both arrays remain synced, but thats’s a long term future idea haha. Let me first make sure I get my own implementation running, although so far this seems like it will be a good solution (atleast for my use case).

1 Like

Maybe there is some way to reuse or recycle an existing protocol? Either all or some of it?

Like aircon protocols would be able to send numbers (set temperature) and turn switches on and off?

Plus there’s the address and checksum parts which might be able to be leveraged.

Can’t say I know much about the pros/cons of the various protocols. I know pronto is quite flexible (and may be easier to work with over raw?).

Just a thought…

https://esphome.io/api/structesphome_1_1remote__base_1_1_panasonic_data

I found this repo for BLE that allows sending data between esp32 nodes independently of HA or anything else. It also allows for custom commands.