Calling hass.service from inside a custom component?

Can one call hass.service from inside a custom component? My custom component code below fails when attempting to do so.

from homeassistant.helpers.entity import Entity
import numpy as np
import time
from PIL import Image
import logging
from collections import namedtuple
from datetime import timedelta

from homeassistant.util import Throttle

_LOGGER = logging.getLogger(__name__)


MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
CAMERA_ENTITY_ID = 'camera.garage'



def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the sensor platform."""
    add_entities([GarageDoorClosedSensor()])


class GarageDoorClosedSensor(Entity):
    """Representation of a Sensor."""
    def getPicArray(self,file):#
        '''Return Array from image file'''
        return np.array(Image.open(file).crop(self.cropBox)).astype(np.int)

    def checkIfGrey(self,picArr):#
        '''Return bool if grey'''
        return np.max(np.sum(np.diff(picArr),2))<self.greyRGBthresh

    def __init__(self):
        """Initialize the sensor."""
        self.greyRGBthresh = 10
        self.diffScoreThresh = 8

        self.current_garage_pic_file = "/config/tmp/snapshotGarage.jpg"
        self.closed_garage_pic_file = "/config/custom_components/garage_door_closed/snapshotGarageClosed.jpg"
        self.cropBox=(550,100,1300,300)
        im=Image.open(self.closed_garage_pic_file)
        im=im.crop(self.cropBox)
        im=np.array(im)
        self.cloGarArr=im.astype(np.int)
        #self.cloGarArr=self.getPicArray(self.closed_garage_pic_file)
        self.cloGarGrey=np.max(np.sum(np.diff(self.cloGarArr),2))<self.greyRGBthresh#self.checkIfGrey(self.cloGarArr)#bool

        self._state = None

    @property
    def name(self):
        """Return the name of the sensor."""
        return 'Garage Door Closed Sensor'

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state


    @Throttle(MIN_TIME_BETWEEN_SCANS)
    def update(self):
        """Fetch new state data for the sensor.
        
        This is the only method that should fetch new data for Home Assistant.
        """
        #this no work#hass.services.call('camera', 'snapshot',{'entity_id': CAMERA_ENTITY_ID,'filename': self.current_garage_pic_file})
        #time.sleep(3)
        self.curGarArr=np.array(Image.open(self.current_garage_pic_file).crop(self.cropBox)).astype(np.int)#self.getPicArray(self.current_garage_pic_file)

        if (np.max(np.sum(np.diff(self.cloGarArr),2))<self.greyRGBthresh)!=self.cloGarGrey:
            self._state = False
        else:
            self.diffScore = np.sum(np.sqrt((self.curGarArr-self.cloGarArr-np.mean(self.curGarArr-self.cloGarArr))**2))/(np.prod(self.cloGarArr.shape))
            if self.diffScore<self.diffScoreThresh:
                self._state = True
            else:
                self._state = False

I think that should work. But you’re not calling it correctly. (You’re missing “self.”.) Also, I’d suggest adding blocking=True to the call and then you shouldn’t need the time.sleep(3). So:

        self.hass.services.call(
            "camera",
            "snapshot",
            {"entity_id": CAMERA_ENTITY_ID, "filename": self.current_garage_pic_file},
            blocking=True,
        )
1 Like

I have yet to suceed in this. The above call just straight up freezes my HA web instance, and no call seems to be made. The logs just end at the logger just before the call is made. Isn’t this supposed to work?

Can you show the code you’re using, including the call and its context? If the calling context is a coroutine, then it shouldn’t be calling call, but rather it should be awaiting async_call.

1,2,3 noob-misstakes, mostly in the python language itself.
It works now! Thanks a lot sensei!

i got the same issue when trying to run service from my custom component with hass.services.call
my hass is getting stuck/freeze for few minutes :frowning:
what was your solution? thanks!

Please show your code or provide a link to it (it it’s in github or something.) The root cause in your case could be completely different.

thanks, managed to make it work now using “await hass.services.async_call(…)” instead of “hass.services.call(…)” which caused the system to freeze.

I’m working on a ESP32 component and needed to send a service call from cpp code. Here is what I used as of 6/24/2024:

      esphome::api::HomeassistantServiceResponse resp;
      resp.service = "media_player.turn_on";
      esphome::api::HomeassistantServiceMap kv1;
      kv1.key = "entity_id";
      kv1.value = entity;
      resp.data.push_back(kv1);
      esphome::api::global_api_server->send_homeassistant_service_call(resp);

Thanks to the info here, I’ve successfully added this to an integration:

    async def complete_startup(event=None) -> None:
        # pylint: disable=unused-argument
        """Run final tasks after startup."""
        _LOGGER.debug("Completing remaining startup tasks...")
        await asyncio.sleep(1)
        if hass.data[DATA_ALEXAMEDIA].get("notify_service"):
            notify = hass.data[DATA_ALEXAMEDIA].get("notify_service")
            _LOGGER.debug("Refreshing notify targets for: %s", notify)
            try: 
                await notify.async_register_services() 
            except:
                await hass.services.async_call("input_boolean", "turn_off", {"entity_id": "input_boolean.alexa_media_notify_service_registered" }, False)
                _LOGGER.warn("%s notify servicees failed to register", DATA_ALEXAMEDIA)
            else:
                await hass.services.async_call("input_boolean", "turn_on", {"entity_id": "input_boolean.alexa_media_notify_service_registered" }, False)