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.
Hassette: State Cache (recommended)
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.items():
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.items() |
Iterates all cached lights |
Use self.states for any read inside a handler or scheduled task. The cache is filled before on_initialize runs and kept current by state change events.
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. The cache is already populated when on_initialize runs, so startup reads don't need the API call. Use it to read the value straight from Home Assistant rather than the local copy. After a disconnect, for example, the cache is marked stale and keeps serving the last known values.
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).
Sending Notifications
AppDaemon's self.notify() defaults to the notify service. Hassette's notify() lives on
self.api and requires the notifier explicitly, so there is no implicit default target.
def my_callback(self, **kwargs):
self.notify("Garage door left open", name="mobile_app_phone", title="Alert")
from hassette import App
class MyApp(App):
async def my_callback(self):
await self.api.notify(
"Garage door left open",
"mobile_app_phone",
title="Alert",
)
The notifier accepts both "mobile_app_phone" and "notify.mobile_app_phone".
get_notify_services() lists the
notifiers registered on the connected instance.
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
- States, state cache and state models
- API Methods, reading state and calling services
- API Overview, full API reference