Calling HA services from within esphome lambda functions

Hi,

Can anyone advise how to call HA services from within lambda functions? I’ve had a hunt around and couldn’t find any examples (and the Native API component page is fairly sparse about the what globals, objects, etc. are available within the lambda functions).

My use case is a rotary encoder modifying a global variable to move a cursor on a screen. I have a separate boolean_sensor which I’m looking to create a lambda action within the on_click trigger. I want to use a switch statement to fire different Home Assistant services depending on the value of the global variable.

Thanks!

I stand under correction, but I don’t think you can. I think you can read sensors from HA, but I don’t believe you can call HA services.

I’ve been mucking about with 2-gang light switches today, is why I think this. I ended up having to do it in Node-RED.

Yes, you can call HA services from ESPHome. See the documentation here:
https://esphome.io/components/api.html#homeassistant-service-action

It’s pretty straight forward. The only required key is the service: key. If you need to pass data like in the example to the service, then you include the data: key. Of course follow proper formatting of your YAML. This all goes in your ESPHome node, not in HA.

1 Like

Yeah you can. However OP is asking using lambdas ie. kind of c++ code directly.

It doesn’t seem straightforward. A look in the source is required.

I would try doing it with esphome automations entirely.

Thanks, yes - I know about being able to use the homeassistant.service action in automations and scripts, but my use case is significantly more simple in C++ rather than YAML.

I’d had a dig through the code and not seen anything obvious, but I’ll go back and see if I can figure something out.

I guess you’ll have to give api: an id, say api_server

  api: 
    id: api_server

then you should be able to do api_server->send_service_call(...);

This method requires a esphome::api::ServiceCallResponse so may be something like this:

   esphome::api::ServiceCallResponse r;
   r.set_service("light.turn_on");
   r.set_data({api::KeyValuePair("entity_id", "light.my_light")});
   api_server->send_service_call(r);

I did not test this code though.

1 Like

Thanks @glmnet - your code works pretty much perfectly and is much cleaner than the way I’d found earlier today.

For reference, the approach I got working earlier is as follows:

api::HomeAssistantServiceCallAction<> *ha_service;
ha_service = new api::HomeAssistantServiceCallAction<>(api_apiserver);
ha_service->set_service("light.toggle");
ha_service->set_data({api::KeyValuePair("entity_id", "light.my_light")});
ha_service->play();

Things to note - this relies on the default naming of the api (api_apiserver) - much better to explicitly set it as @glmnet suggests.

Ahhh yes. You’re using the action there. I went a bit deeper for simplicity.
Keep in mind Otto is a refactor ninja and this is not documented/supported api. So be ready to face a compilation error in future versions.

Thanks! I’ll bear that in mind!

In the current version set_service and set_data seems to be absent. Rather there is add_data, add_data_template, add_variable functions.

api::HomeAssistantServiceCallAction<> *ha_service;
ha_service = new api::HomeAssistantServiceCallAction<>(&*api_apiserver, true);
ha_service->add_data("entity_id", "input_boolean.cycle1_enable");
ha_service->play();

I made it this far but can’t figure out how to set the service to call. There seems to function called TEMPLATABLE_STRING_VALUE but I couldn’t get it to work. I would have set the service variable directly but it is private.
Also, I tried this in desperation, doesn’t work and makes it disconnect from HA and reconnect.

ha_service->add_data("service", "input_boolean.toggle");
ha_service->add_variable("entity_id", "input_boolean.cycle1_enable");