That did it, thanks!
Thx for this - it’s really going to help me.
I have managed to extract text strings into a text sensor OK
I have managed to extract ascii integer values into a sensor
I am struggling to extract float values into a sensor
For example string “V1123.45\r\n” I want to extract as value for state “V1” as 123.45
This is my sensor code (I can’t get it to disply formatted)
- platform: uartex
id: test_sensor_1
name: “Test Sensor”
unit_of_measurement: “units”
state: “V1”
state_number:
offset: 2
length: 6 #If value received is shorter than this, decoding seems OK
precision: 2
decode: “ascii”
But the value I get in my HA sensor is 1.00
Or if I receive “V1123456\r\n” I get 1235.00
It’s almost as if precision is being interpreted as rounding not floating point precision.
I guess I could do my own parsing in a lambda to find the position of received decimal point and then convert from there, or force all values to be sent as integers and then convert afterwards
Yes, that’s correct — the precision value only controls how the decimal places are displayed.
If you want to properly handle float values, you should use the sensor’s accuracy_decimals option instead.
- platform: uartex
id: test_sensor_1
name: “Test Sensor”
unit_of_measurement: “units”
accuracy_decimals: 2
state: “V1”
state_number:
offset: 2
length: 6 #If value received is shorter than this, decoding seems OK
#precision: 0
decode: “ascii”
OK that works but it assumes a fixed (virtual) decimal point position in the received string.
I could sort of work around that by multiplying my values to transmit by say 100 and then use accuracy_decimals: 2 to scale them back down. but not very elegant
This works (but crashes my MQTT connection! (must be a string error)
platform: uartex
id: test_sensor_3
name: “Test Sensor 3”
unit_of_measurement: “units”
accuracy_decimals: 2
state: “V3”
lambda: |-
auto n = parse_number(std::string(reinterpret_cast<const char*>(data+2), len-2).c_str());
return n.has_value() ? n.value() : NAN;
Try setting the length: value in state_number: to the maximum possible length of the incoming data.
The length parameter cannot exceed the actual length of the parsed data.
Get invalid yaml errors if I try and have a lambda: and a state_number:
My only relaible method is to read the uart input into a text sensor, then use a template sensor to parse that into a floating point sensor value.
The parse_number helper function works well with all sorts of varying text numbers, varying sign, varying decimal point precision etc.
I didn’t know about the parse_number function, but now I do.
That seems like a good method as well.
Yes it just means I have to duplicate all my sensors as both text and a template (I will have around 100 sensors in the full implementation)
text_sensor:
- platform: uartex
id: test_text_sensor
name: "Test Text Sensor"
state: "T1"
lambda: |-
// return std::string(reinterpret_cast<const char*>(data), len); // Simply return the received string
return std::string(reinterpret_cast<const char*>(data+2), len-2); // Simply return the received string excluding first 2 chars
on_value:
then:
- sensor.template.publish:
id: num_from_text
state: !lambda |-
auto n = parse_number<float>(x);
return n.has_value() ? n.value() : NAN;
sensor:
- platform: template
id: num_from_text
name: "Number from text"
unit_of_measurement: "units"
accuracy_decimals: 2
It seems like it might be possible to integrate it as shown below. Have you tested this approach?
sensor:
- platform: uartex
name: "Test Sensor"
state: "T1"
unit_of_measurement: "units"
accuracy_decimals: 2
lambda: |-
std::string str = std::string(reinterpret_cast<const char*>(data+2), len-2); // Simply
auto n = parse_number<float>(str);
return n.has_value() ? n.value() : NAN;
It seems any of these three syntax versions work.
My MQTT crashes seem to have been unrelated (I had moved the aerial) although I am still getting occasional disconnects just after I parse soem serial input
- platform: uartex
id: test_sensor_3
name: "Test Sensor 3"
unit_of_measurement: "units"
accuracy_decimals: 2
state: "V3"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+2), len-2).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
id: test_sensor_4
name: "Test Sensor 4"
unit_of_measurement: "units"
accuracy_decimals: 3
state: "V4"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+2), len-2));
return n.has_value() ? n.value() : NAN;
- platform: uartex
id: test_sensor_5
name: "Test Sensor 5"
unit_of_measurement: "units"
accuracy_decimals: 3
state: "V5"
lambda: |-
std::string str = std::string(reinterpret_cast<const char*>(data+2), len-2); // Simply
auto n = parse_number<float>(str);
return n.has_value() ? n.value() : NAN;
This option prioritizes loop execution over serial data processing. By default, the system blocks the loop and processes incoming data first. Could you test whether this option is actually effective?
I suspect that the loop might be getting blocked by prioritizing data processing, which could be causing the MQTT connection to drop.
uartex:
...
rx_priority: loop
I’m not sure it’s that - even without that change I now cannot replicate the issue. I suspect something was off with my MQTT server as I just restarted everything.
I will try building a file of 100 or so sensor values to transmit in one go to stress test it. If necessary I could then try your rx_priority: loop setting
So stress testing with 100 or so sensor values to process just sent in one go as a text file worked without issues, all the values got processed correctly.
Thx for all your help
Now I have a new issue if I try and add uartex sensors.
I first started to get issues when I added my 10th sensor, I have cut out everything else in this example and now the issue occurs when I add the 15th sensor. Commenting out any of these uartex sensors the code runs fine.
I have tested on different model ESP8266 boards - same issue
After connecting to WiFi and then MQTT, the board crashes with a OOM crash dump.
[14:28:38]User exception (panic/abort/assert)
[14:28:38]--------------- CUT HERE FOR EXCEPTION DECODER ---------------
[14:28:38]
[14:28:38]Unhandled C++ exception: OOM
[14:28:38]
[14:28:38]>>>stack>>>
The program is really small (compresses down to 303018 bytes) devices have 4MB of flash
substitutions:
devicename: boat
# led_pin: GPIO14 #ATMega with ESP8266
# button_pin: GPIO13
# tx_pin: GPIO1
# rx_pin: GPIO3
led_pin: GPIO2 #D1 Mini Pro ESP8266 note LED is inverted logic
button_pin: GPIO0
tx_pin: GPIO15
rx_pin: GPIO13
sensor_update: 60s
led_strbuf_size: "16"
esphome:
name: $devicename
esp8266:
# board: esp07s #d1_mini_pro
# board: d1_mini_pro
board: nodemcuv2 #Actualy Node MCUV3
logger:
# baud_rate: 0 # disable uart logging (MQTT logging still happens) as we need to retain the serial port free for comms with AT Mega
level: DEBUG
uart:
baud_rate: 9600
data_bits: 8
parity: NONE
stop_bits: 1
tx_pin: $tx_pin
rx_pin: $rx_pin
rx_buffer_size: 512
wifi:
networks:
- ssid: !secret wifi_home_ssid
password: !secret wifi_home_password
mqtt:
broker: !secret mqtt_broker
port: 1883
username: !secret mqtt_username
password: !secret mqtt_password
#no clientid reqd
discovery: true # disable entity discovery
discover_ip: true # enable device discovery
discovery_retain: true #retain discovery messages
discovery_unique_id_generator: mac #Use Mac address to generate unique entity Ids
ota:
platform: esphome
light:
- platform: status_led #Built in LED to show status for SP8266
name: "ESP8266 LED"
id: devicename_led
pin:
number: $led_pin
# inverted: False #AT Mega with ESP8266
inverted: True #D1 Mini Pro ESP8266
restore_mode: RESTORE_DEFAULT_ON
binary_sensor:
- platform: gpio
pin:
number: $button_pin
inverted: True
name: "ESP8266 Button"
external_components:
- source: github://eigger/espcomponents@latest
components: [ uartex ]
refresh: always
uartex:
rx_timeout: 10ms
tx_delay: 50ms
tx_timeout: 500ms
tx_retry_cnt: 3
rx_priority: loop #Lower priority for Rx than main loop tasks
# rx_header: [0x02, 0x01]
rx_footer: [0x0D, 0x0A]
# tx_header: [0x02, 0x01]
tx_footer: [0x0D, 0x0A]
version:
name: "Uartex Version"
disabled: False
error:
name: "Uartex Error"
disabled: False
log:
name: "Uartex Log"
disabled: True #False
sensor:
- platform: uartex
name: "Sensor 1"
state: "XX01"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 2"
state: "XX02"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 3"
state: "XX03"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 4"
state: "XX04"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 5"
state: "XX05"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 6"
state: "XX06"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 7"
state: "XX07"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 8"
state: "XX08"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 9"
state: "XX09"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 10"
state: "XX10"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 11"
state: "XX11"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 12"
state: "XX12"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 13"
state: "XX13"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 14"
state: "XX14"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
- platform: uartex
name: "Sensor 15"
state: "XX15"
lambda: |-
auto n = parse_number<float>(std::string(reinterpret_cast<const char*>(data+4), len-4).c_str());
return n.has_value() ? n.value() : NAN;
Uartex data uses a vector, so it does allocate dynamic memory, but I don’t think it should be using that much. MQTT also seems to use some dynamic memory as well. If possible, could we take a look at the stack trace? You can download the ELF file from ESPHome and then add the stack trace information to this link.
Also, could you add a debug sensor here to monitor the heap status?