Service call response data

Edit: I’ve rephrased this question

Original question:
within an automation I want to send data to an esphome device, do a calculation on the device and have a return value be processed in the rest of the automation.

im unsure how to set this up. could someone post an example of what I would need to have in my esphome device yaml?

1 Like

What kind of automation? Is this on another esp node? Is this a HA automation? I think you need to explain this better or post some code. Send a value from one automation to then be processed in another automation and then sent back to the original automation doesnt make much sense. Theres probably a better or more efficient way to do what you want.

No, no one can post an example of the train wreck you’ve requested because it doesnt make sense.

Post your own code or whatever you’ve got and then maybe someone can make sense of what you are trying to do here.

hey, thanks for the feedback.
didn’t mean for it to be a train wreck.

i have an espHome switch that controls my domestic warm water circulation pump.

when it’s on, warm water gets pumped through the pipes.
when It’s been on for at least 5-6minutes the the past 10 minutes im pretty sure I’ll get warm water off the tap furthest away from the warm water heater.

at the closest water tap that may only be 1-2minutes.

the switches I have close to the water tap allow for a visualization of an 8 speed fan that I’d like to use to visualize how “warm” the warm water will likely be if I turn it on right now.

to calculate this, my esphome switch has a circular buffer of the last 20 times its been toggled on or off:

globals:
  - id: switch_state_changes
    type: std::vector<std::pair<int, bool>>
    initial_value: 'std::vector<std::pair<int, bool>>()'


script:
  - id: record_switch_state_change
    then:
      - lambda: |-
          // Record a switch state change (on/off) with the current timestamp.
          auto now = id(ha_time).now().timestamp;
          bool state = id(relay).state;
          // Ensure the buffer doesn't exceed 20 entries.
          if (id(switch_state_changes).size() >= 20) {
            id(switch_state_changes).erase(id(switch_state_changes).begin());
          }
          id(switch_state_changes).push_back(std::make_pair(now, state));
          id(visualization_sensor).update();


switch:
  - platform: gpio
    name: "${friendly_name}"
    pin: GPIO12
    id: relay
    on_turn_on:
      then:
        - script.execute: record_switch_state_change
    on_turn_off:
      then:
        - script.execute: record_switch_state_change

now to calculate how Long the pump has been running with in the las lookback_window I cycle through the buffer, and add up the amount of time the switch has been in the “on” state within that lookback window:

sensor:
  - platform: template
    id: visualization_sensor
    disabled_by_default: true
    lambda: |-
      long current_time = id(ha_time).now().timestamp;
      long duration_on = 0;
      long lookback_window = 600;
      long last_change_time = 0;
      bool was_on = false;


      // Iterate through all state changes to find the relevant ones.
      for (auto &change : id(switch_state_changes)) {
        long change_time = change.first;
        bool is_on = change.second;

        //check if change is within lookback window
        if(change_time < (current_time - lookback_window)){
          last_change_time = current_time - lookback_window;
          was_on = is_on;
        }else{
          if(!is_on && was_on){
            duration_on += (change_time - last_change_time);
          }
          if(is_on != was_on){
            last_change_time = change_time;
            was_on = is_on;
          }
        }
      }


      float percent_on = (static_cast<float>(duration_on) / static_cast<float>(lookback_window));

      ESP_LOGD("custom", "duration_on: %i", duration_on);
      ESP_LOGD("custom", "as percentage %f", percent_on*100);
      return (percent_on * 8);  // To return the visualization integer.

as you can see this is currently hardcoded as a loopback window of 600 seconds (10minutes) and is published as a sensor.

to display at different values at different taps and avoid having multiple sensors that only exist to be forwarded as visualization, I’d rather create a service

api:
  services:
    - service: percent_on_in_window
      variables:
         window: int
      then:
        - script.execute: <lambda from above that takes window parameter and returns percent_on>

that I’d call with a script in home assistant, take the result value and assign it to the visualization entity

maybe there’s a better way to do it. currently I just have a single calculation for the tap furthest away from the hot water heater that updates all displays to the same value. it gets updated via espsensor on_value: then homeassistant.service: number.set_value on all visualization entities.

but thats because I don’t know how to return a value from an api: service call

oh my… That is the definition of a train wreck! I won’t waste your time. I’m not in the position to sit here and try to visualize your setup and focus on this.

I will admit, I jumped to conclusion and assumed you were just over complicating something simple and this clearly isn’t the case.

For something like this, I would suggest you go to the esphome Discord server and ask them. That’s where a lot of the developers and guys who eat “train wrecks” for breakfast hang out.

This is interesting though. Could you update the post if you get it figured out?

With your questions for code I though this is exactly what you had asked. Calling it a train wreck isn’t exactly the conduct I’m used to in this community. There seems to be a misunderstanding sorry about that.

I‘ve since rephrased the question. See below and edited first post.

—-

Service call docs mention service call response data:

This feature was introduced with 2023.7: 2023.7: Responding services - Home Assistant

I’m asking: How to I use this service call response data feature from 2023.7 with esp Homes user-defined services of the native API

Igrnore the rest. Maybe it’s not even implemented?