Skip to content

API Calls

Coming from synchronous AppDaemon?

Every Hassette lifecycle method and handler is async def, and calls to self.api need await in front — await pauses the handler until the network call finishes. Reads from self.states (the local cache) are plain synchronous calls. Migration Concepts covers the model.

Getting Entity State

AppDaemon's self.get_state() reads from an internal cache and returns raw strings or dicts. Hassette provides two options. self.states is a local cache for most reads. self.api.get_state() forces a fresh read from Home Assistant when the cache is not enough.

AppDaemon

from appdaemon.plugins.hass import Hass


class StateGetter(Hass):
    def initialize(self):
        office_light_state = self.get_state("light.office_light_1", attribute="all")
        self.log(f"{office_light_state=}")

Returns a raw dict. No type information. No autocomplete.

self.states holds a local copy of all entity states, kept current via WebSocket events. No await needed. The returned object is typed to the entity domain.

from hassette import App, states


class StateGetter(App):
    async def on_initialize(self):
        # Access via domain-specific property (no await needed)
        office_light = self.states.light.get("light.office_light_1")

        if office_light:
            self.logger.info("Light state: %s", office_light.value)
            self.logger.info("Brightness: %s", office_light.attributes.brightness)

        # Iterate over all lights
        for entity_id, light in self.states.light:
            self.logger.info("%s: %s", entity_id, light.value)
        # Typed access for any domain
        my_light = self.states[states.LightState].get("light.office_light_1")

Three access patterns:

Pattern Returns
self.states.light.get("light.kitchen") LightState \| None
self.states[states.LightState].get("light.kitchen") LightState \| None, for any domain
for entity_id, state in self.states.light Iterates all cached lights

Use self.states for any read inside a handler or scheduled task. The cache is always up-to-date.

Hassette: Direct API Call

For a guaranteed fresh read from Home Assistant:

from hassette import App


class StateGetter(App):
    async def on_initialize(self):
        # Force fresh read from HA (requires await)
        office_light_state = await self.api.get_state("light.office_light_1")
        self.logger.info("office_light_state=%r", office_light_state)

self.api.get_state() hits the HA REST API and requires await. Use it when the cache is not reliable, such as during initialization before the first state change event.

Calling Services

AppDaemon uses a single domain/service string. Hassette splits them into two arguments.

def my_callback(self, **kwargs):
    self.call_service("light/turn_on", entity_id="light.kitchen", brightness=200)

    # or use the helper
    self.turn_on("light.kitchen", brightness=200)
from hassette import App


class MyApp(App):
    async def my_callback(self):
        await self.api.call_service(
            "light",
            "turn_on",
            target={"entity_id": "light.kitchen"},
            brightness=200,
        )
        # Or use the helper
        await self.api.turn_on("light.kitchen", brightness=200)

Don't forget await

Without await, the call appears to succeed but the service never runs — Python just hands back an unexecuted coroutine. If service calls have no effect, check that every call site has await.

Two signature differences from AppDaemon: the entity belongs in the target dict (target={"entity_id": "light.kitchen"}) rather than AppDaemon's bare entity_id= keyword, and Hassette handlers don't take **kwargs — event data arrives through typed parameters instead (see Bus & Events).

Setting States

self.set_state("sensor.custom", state="42", attributes={"unit": "widgets"})
from hassette import App


class MyApp(App):
    async def my_callback(self):
        await self.api.set_state("sensor.custom", state=42, attributes={"unit": "widgets"})

Firing Events

self.fire_event("custom_event", entity_id="sensor.test", value=42)
await self.api.fire_event("custom_event", {"entity_id": "sensor.test", "value": 42})

fire_event sends an event to Home Assistant's event bus. The event data is a dict in Hassette (AppDaemon accepts kwargs). For broadcasting between apps in the same Hassette process without leaving the framework, use self.bus.emit() instead.

Logging

AppDaemon provides self.log() and self.error(). Hassette uses Python's standard logging module via self.logger.

self.log("This is a log message")
self.log(f"Value: {value}")
self.error("Something went wrong")
from hassette import App


class MyApp(App):
    async def on_initialize(self):
        value = "example"

        self.logger.info("This is a log message")
        self.logger.info("Value: %s", value)
        self.logger.error("Something went wrong")

self.logger automatically includes the app instance name, calling method, and line number in every log line. Use %s-style formatting rather than f-strings. The string is only constructed if the log level is active.

See Also