Hello i’m not so good developing in cpp but maybe i don’t need.
i have an uart text sensor that return me a string where the value in bold is the temperature i want to make an entity.
INFO Starting log output from fpg-home-calefactor-1.local using esphome API
WARNING Can't connect to ESPHome API for fpg-home-calefactor-1.local: Timeout while connecting to ('192.168.11.142', 6053)
INFO Trying to reconnect to fpg-home-calefactor-1.local in the background
@mulcmu all is hexa yes, byte separator “:” required temperature value is always at that position yes and more as it can not be > 100C° (or i would be dead), in hexa it will never occupy the 00:00:00 value is so at byte 68.
55:AA: header
03: version
07: command
00:05: length total
01: sensor/actor id
01: type here bool
00:01: length sensor/actor value
00: value (switch off)
11: checksum
next sensor is type string and 4bytes
55:AA:03:07:00:08:02:02:00:04:00:00:00:16:2F:55:AA:03:07:00:08:03:02:00:04:00:00:00:48:62:55:AA:03:07:00:05:04:01:00:01:00:14:55:AA:03:07:00:08:05:02:00:04:00:00:00:12:2E:55:AA:03:07:00:08:06:02:00:04:00:00:00:3F:5C:55:AA:03:07:00:08:07:02:00:04:00:00:00:00:1E:55:AA:03:07:00:05:08:01:00:01:00:18
So I would change the example code to be a sensor directly and just return the value for the 68th byte. I didn’t test this code but should get you close
#include "esphome.h"
class UartReadLineSensor : public Component, public UARTDevice, public /*Make this just a sensor and not a TextSenor*/Sensor {
public:
UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {}
void setup() override {
// nothing to do here
}
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
void loop() override {
const int max_line_length = 180; //increase this to make sure everything gets read in until newline
static char buffer[max_line_length];
while (available()) {
if(readline(read(), buffer, max_line_length) > 0) {
//only return the temperature value
publish_state( (float) buffer[67]); //array index start at 0, return 68 byte with the temperature value casted to a floating point value
}
}
}
};
And the yaml would get changed for no text sensor and a custom sensor:
If you go this route the lambda for the one data value becomes pretty simple. No messing with other code to process reading the data. interval can be used to write the bytes to request uart data.
esphome:
name: xxxxxxx
includes:
- my_uart_read_line_sensor.h
esp8266:
board: esp01_1m
# Enable logging
logger:
level: DEBUG #makes uart stream available in esphome logstream
baud_rate: 0 #disable logging over uart
# Enable Home Assistant API
api:
encryption:
key: "---------------------"
ota:
password: "*******************"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "xxxxxxx"
password: "*********"
captive_portal:
uart:
id: uart_bus
rx_pin: GPIO13
tx_pin: GPIO15
baud_rate: 9600
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: |-
UARTDebug::log_string(direction, bytes);
if(bytes.size() > 68)
id(temp_room1).publish_state( (float) bytes[67] );
else
ESP_LOGD("main", "Response data only had %d bytes!!", bytes.size() );
interval:
- interval: 1min
then:
- uart.write: [0x55, 0xAA, 0x00, 0x08, 0x00, 0x00, 0x07]
sensor:
- platform: custom
id: "temp"
lambda: |-
auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
App.register_component(my_custom_sensor);
ESP_LOGD("main", "Value of my sensor: %f", my_custom_sensor);
return {my_custom_sensor};
sensors:
id: "temp_room1"
unit_of_measurement: "°C"
name: "Temperatura dormitorio"
and
#include "esphome.h"
class UartReadLineSensor : public Component, public UARTDevice, public /*Make this just a sensor and not a TextSenor*/Sensor {
public:
UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {}
void setup() override {
// nothing to do here
}
int readline(int readch, char *buffer, int len)
{
static int pos = 0;
int rpos;
if (readch > 0) {
switch (readch) {
case '\n': // Ignore new-lines
// break;
case '\r': // Return on CR
rpos = pos;
pos = 0; // Reset position index ready for next time
return rpos;
default:
if (pos < len-1) {
buffer[pos++] = readch;
buffer[pos] = 0;
}
}
}
// No end of line has been found, so return -1.
return -1;
}
void loop() override {
const int max_line_length = 180; //increase this to make sure everything gets read in until newline
static char buffer[max_line_length];
while (available()) {
if(readline(read(), buffer, max_line_length) > 0) {
//only return the temperature value
publish_state( (float) buffer[67]); //array index start at 0, return 68 byte with the temperature value casted to a floating point value
}
}
}
};
now i will try to include other information from the same buffer
You should use either the lambda in the uart debug for processing or the custom component. Right now it looks like you have implemented both and both are duplicating the effort to update the temp sensor.
I’d recommend just going the route of using the uart debug to process the data. Adding multiple sensors in a custom component gets even more complex. For each value you want to send back create another sensor template with a different id. Then in the lambda use the publish_state() to set the value.
Is there a message in the log with size of the response data. I might have counted wrong for the 111. If some of the data has a dynamic length then that check might need to change.
i count 111 too but I have no message in log. i set direction to RX well, and when i put BOTH, i receive the error from my 7 byte short query message.
let me check the dummy receiver to true