I have an esphome setup that returns this string as a sensor value (103.0 53.61 14.82 07.65 07.17 0798 +044 43.39 -002 0000 11000000).
The bolded 53.61 represents a voltage reading.
How can I use template withing ESPHOME yaml to return 53.61 as a sensor.
I have this done using Home Assistant template. However, I wish I can just get ESPHOME to output it without having to mess with Home Assistant Templating.
Thanks in Advance.
This is the esphome yaml that produce the sensor if it helps.
I think you’ll need to use a lambda filter to step through each character of the “before” sensor value (x in the lambda), discard everything up to the first space, build a string from the subsequent characters until you hit the second space then stop and return what you’ve found.
It’s interesting, I actually developed what seemed to be a fully working and tested solution to this based on @Troon s suggested approach and with help from They Who Shall Not Be Named (who has been helping me write some pretty advanced and quite similar Lambda’s lately) , but then double checked the forum rules and it was a no-go.
Please show it if it is working. I think what the moderators frown upon is dumping untested AI generated codes that may not work.
And yes, I also turned to ChatGPT for help and after several hours of failed suggestions, it pointed me to a working solution and I now have the yaml working perfectly.
For anyone interested, this is the code that worked.
sensor:
- platform: template
name: "fcc1 battvoltage"
update_interval: 1s
unit_of_measurement: V
icon: "mdi:sine-wave"
device_class: "voltage"
state_class: "measurement"
accuracy_decimals: 2
lambda: |-
auto str = id(fcce1_qpigs).state.c_str();
int startPos = strcspn(str, " ") + 1; // Find the position of the first space and add 1
int endPos = strcspn(str + startPos, " "); // Find the position of the next space
if (endPos > 0) {
std::string figureStr(str + startPos, endPos);
float fcc1battvoltage = std::stof(figureStr);
return fcc1battvoltage;
} else {
return NAN;
}
I was able to modify this for other sensors from the string.
Like your experience I usually find I have to re-prompt and iterate a bit to get to a working solution. But I get there and the speed of the iterations you can do means you can get there independently quite fast.
Often I ask it for smaller steps/chunks of logic, and build it up (like you would with your own code builds)
Sometimes I request a review of the end code from someone on Discord who knows what they’re doing, and they often suggest tweeks.
Might not be worth it if you’ve got a working solution, but if you need to parse out all values, you can actually do it all in one lambda in a single parse, loop over each split/delimiter, and publish the new values to the relevant sensor.
My example below does something a bit similar (but you’d need to adjust). It does a “double split” of the string. First it splits on ‘,’ and then it splits again on ‘M’ or ‘m’.
- platform: template
name: "test String Splits"
id: test_string_split
icon: mdi:format-text-rotation-none
update_interval: never
#x is like "1M-10,2M-700,3M-100,4M-10,3M70,8M170"
on_raw_value:
then:
- lambda: |-
ESP_LOGD("custom", "text sensor received new value");
std::string item;
std::size_t start = 0, end; // Initialize "start" variable to 0
// Loop until no ',' character is found in "x"
while ((end = x.find(",", start)) != std::string::npos)
{
// Extract substring from "x" starting at "start" and ending at "end"
item = x.substr(start, end - start);
// Split item by "M" to get motor number and movement amount
std::size_t motor_number_pos = item.find_first_of("Mm");
std::string motor_number_str = item.substr(0, motor_number_pos);
std::string movement_amount_str = item.substr(motor_number_pos + 1);
// If motor number and movement amount are not empty, process them
if (!motor_number_str.empty() && !movement_amount_str.empty())
{
int motor_number = std::stoi(motor_number_str);
int movement_amount = std::stoi(movement_amount_str);
ESP_LOGD("custom", "Motor Number: %d, Movement Amount: %d", motor_number, movement_amount);
// Publish movement amount to corresponding template based on motor number
switch (motor_number)
{
case 1: id(m1_last_movement_amount).publish_state(movement_amount); break;
case 2: id(m2_last_movement_amount).publish_state(movement_amount); break;
case 3: id(m3_last_movement_amount).publish_state(movement_amount); break;
case 4: id(m4_last_movement_amount).publish_state(movement_amount); break;
case 5: id(m5_last_movement_amount).publish_state(movement_amount); break;
case 6: id(m6_last_movement_amount).publish_state(movement_amount); break;
case 7: id(m7_last_movement_amount).publish_state(movement_amount); break;
case 8: id(m8_last_movement_amount).publish_state(movement_amount); break;
default: break;
}
}
// Set "start" to position after ',' character found
start = end + 1;
}