KG3RK3N / esphome-uart-p2p

ESPHome components to send/receive sensor values between two ESPHome devices over UART without WIFI.
Apache License 2.0
9 stars 1 forks source link

Non-esphome device communation #1

Closed kipwittchen closed 5 months ago

kipwittchen commented 5 months ago

Hello! I just stumbled across your repo and I think I'll be able to use it to communicate with a non-esphome esp device I'm going to have.

My use case is this, I have an esp32 which will be communicating with a proprietary device via a standalone wifi network. I then need to take that numeric sensor data (I'll have a couple sensors, all numeric) and want to pass them eventually into home assistant. If I use serial1 to TX/RX pins on that non-esphome device to an esphome device running your library with the two connected via those pins, I think I'll be all set.

My question is, how do I transmit the data via serial from a device that's just running arduino code? I think it's as simple as doing a Serial1.write() in the correct format. On the non-esphome device I'd just open the serial connection with: TX_1 = #; //# is pin # RX_1 = #; //# is pin # Serial1.begin(115200, SERIAL_8N1,RX_1,TX_2);

Thank you for any assistance you can provide!

KG3RK3N commented 5 months ago

Hi @kipwittchen

Here is a sample for sending data from a arduino to a esphome device with uart:


static unsigned long _ETimer;

unsigned long t = 1000;

void setup() {
  Serial.begin(115200); // debugging output

  Serial1.begin(115200); // Serial1
}

void loop() {
  if ( millis() - _ETimer >= (t)) {
    _ETimer += (t);
    static unsigned int i;
    i++;

    sendMySensorValue(); // here start sending my sensor value
  }
}

// sample to send sensor value
void sendMySensorValue() {
  uint8_t address = 0x05;  // <- thats the address from the esphome sensor
  float sensorValue = 42.5;
  uint8_t sensorType = 0; // 0 = number, 1 = binary, 2 = text
  sendUartData(address, &sensorValue, sizeof(sensorValue), sensorType);
}

// start of the code to generate & send uart message
static const int headerSize = 3;

void sendUartData(uint8_t address, const void *data, size_t dataLength, uint8_t sensorType) {
  uint8_t uartData[headerSize + dataLength];
  uartData[0] = address;
  uartData[1] = sensorType;
  uartData[2] = dataLength;

  memcpy(uartData + headerSize, data, dataLength);

  uint8_t checksum = calculateChecksum(uartData, headerSize + dataLength);
  uartData[headerSize + dataLength] = checksum;

  Serial1.write(uartData, headerSize + dataLength + sizeof(uint8_t));
}

uint8_t calculateChecksum(const uint8_t *data, size_t length) {
  uint8_t checksum = 0;
  for (size_t i = 0; i < length; i++) {
    checksum ^= data[i];
  }
  return checksum;
}

The timer stuff in the loop is not necessary, you can use delay or something else. I only added that to prevent flooding the uart bus.

On your esphome device, you need to configure the "uart_p2p_receiver" component like this:

uart_p2p_receiver:
  uart_id: uart_1
  sensors:
    - id: my_sensor_1
      name: "My Sensor 1"
      address: 0x05

I haven't tested this example. But if it works, it would be nice to get some feedback from you so I can add it to the docs/wiki as an sample use case.

kipwittchen commented 5 months ago

Excellent, thank you, that's a huge help! I'm waiting on a couple components to arrive early next week and will test it then. I should be able to do without the timer because the sensor I'm reading from is already rate limited and only sends when new data is received.

I'll report back with a repo once I can test.

KG3RK3N commented 5 months ago

Now I created some docs for the arduino -> esphome connection and added the sample code. Tested with arduino uno and esp32, works great.

https://github.com/KG3RK3N/esphome-uart-p2p/blob/main/arduino/ESP32_ARDUINO.md

kipwittchen commented 5 months ago

I had a chance to test this over the weekend and I'm getting the following error on the receiver: [17:39:49][W][uart_p2p_receiver:042]: Received UART data size does not match expected size. - Current: 24, Expected: 8

The current and expected numbers sometimes change but that's the most common one. I simplified my script down to the following and it was still throwing the same error:

#define RX1 2
#define TX1 4

bool sendSonarData()
{
  float depthToSend = random(0,100);
  float vBatt = random(11,14);
  float temp = random(65,80);
  uint8_t address1 = 0x01;  // <- thats the address from the esphome sensor
  uint8_t sensorType = 0; // 0 = number, 1 = binary, 2 = text
  sendUartData(address1, &depthToSend, sizeof(depthToSend), sensorType);
  uint8_t address2 = 0x02;  // <- thats the address from the esphome sensor
  sendUartData(address2, &vBatt, sizeof(vBatt), sensorType);
  uint8_t address3 = 0x03;  // <- thats the address from the esphome sensor
  sendUartData(address3, &temp, sizeof(temp), sensorType);
  return true;
}
// start of the code to generate & send uart message
static const int headerSize = 3;

void sendUartData(uint8_t address, const void *data, size_t dataLength, uint8_t sensorType) {
  uint8_t uartData[headerSize + dataLength];
  uartData[0] = address;
  uartData[1] = sensorType;
  uartData[2] = dataLength;

  memcpy(uartData + headerSize, data, dataLength);

  uint8_t checksum = calculateChecksum(uartData, headerSize + dataLength);
  uartData[headerSize + dataLength] = checksum;

  Serial1.write(uartData, headerSize + dataLength + sizeof(uint8_t));
}

uint8_t calculateChecksum(const uint8_t *data, size_t length) {
  uint8_t checksum = 0;
  for (size_t i = 0; i < length; i++) {
    checksum ^= data[i];
  }
  return checksum;
}

void setup()
{
    Serial.begin(115200);
    Serial1.begin(115200,SERIAL_8N1,RX1,TX1); //for UART to other arduino
}
void loop()
{
  sendSonarData();
  delay(1000);
}

And then here's my esphome code:

esphome:
  name: boatsonar32
  friendly_name: boatsonar32

esp32:
  board: node32s

external_components:
  - source:
      url: https://github.com/KG3RK3N/esphome-uart-p2p
      type: git
    components: [uart_p2p_receiver] 

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Boatsonar Fallback Hotspot"
    password: "xxxx"

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "xxxx"

ota:
  password: "xxxx"

captive_portal:

uart:
  id: uart_1
  tx_pin: GPIO2
  rx_pin: GPIO4
  baud_rate: 115200

uart_p2p_receiver:
  uart_id: uart_1
  sensors:
    - id: sonar_depth
      name: "Sonar Depth"
      #unit_of_measurement: "ft"
      address: 0x01
    - id: sonar_battery_voltage
      name: "Sonar Battery Voltage"
      #unit_of_measurement: "v"
      address: 0x02
    - id: sonar_temperature
      name: "Sonar Temperature"
      #unit_of_measurement: "°F"
      address: 0x03

Any idea what may be causing that error?

KG3RK3N commented 5 months ago

I have a idea why that's failed. I will check that today evening.

Is it working if you only have one sensor on the Arduino side?

kipwittchen commented 5 months ago

Okay, I have not tried only one sensor yet. I'll give that a try tonight as well.

KG3RK3N commented 5 months ago

I have fixed the issue, now its working. It was a issue on reading the uart if multiple messages are received.

Maybe you need to force esphome to update the external component with adding a lower refresh interval:

external_components:
  - source:
      url: https://github.com/KG3RK3N/esphome-uart-p2p
      type: git
    components: [uart_p2p_receiver] 
    refresh: 1min # force fetch external repo if local older than 1 minute
kipwittchen commented 5 months ago

Okay great, thanks for your help! I'll update tonight and let you know how it goes. Also changing the pins to 16/17 because 2/4 are strapping pins and that explains why I had to disconnect them to flash either device

kipwittchen commented 5 months ago

It's working now!! I'm getting numeric integral value values passing between the two esp32s! Is it possible to get them to share as float types? Decimals don't seem to be passed (I see them reported as decimals on the arduino coded side). Maybe I have something set wrong in configuration?

kipwittchen commented 5 months ago

Ah, nevermind! I forgot to include "accuracy_decimals" under my sensors. Working perfectly now!

Thanks so much for your work on this!

KG3RK3N commented 5 months ago

Great, I'll add the decimals to the samples for other users.

kipwittchen commented 5 months ago

Okay! Here's also my repo utilizing your code along with code for communicating with another device via wifi (hence why I needed another means of communication with an esphome device), just in case it helps anyone: https://github.com/kipwittchen/SP200A-Client-esphome-UART

Cheers, Kip