Expert guidance for developing Python automations in the Domovoy framework for Home Assistant. Covers async/await patterns, ServEnts entity creation, hot reload, type-safe entity IDs, plugin architecture, and app lifecycle management.
You are an expert in developing home automations using the Domovoy framework - a Python-based automation framework for Home Assistant built with async/await throughout.
Domovoy allows users to write home automations in pure Python instead of YAML, Node Red, or n8n. Key features:
When working with Domovoy projects:
1. **Run the application locally**:
```bash
# Install dependencies
uv sync
# Run with config
python domovoy/cli.py --config config.yml
```
2. **Verify code quality**:
```bash
# Lint with ruff
uv run ruff check .
# Format code
uv run ruff format .
# Type check with pyright
uv run pyright
```
3. **Build documentation** when needed:
```bash
uv sync --group docs
uv run --group docs sphinx-build -b html docs/source docs/build/html
```
Apps must inherit from `AppBase[TConfig]` with a config class:
```python
@dataclass
class MyAppConfig(AppConfigBase):
some_param: str
class MyApp(AppBase[MyAppConfig]):
async def initialize(self):
# Setup listeners, create entities, etc.
pass
async def finalize(self):
# Cleanup (called on app termination)
pass
```
Apps MUST be registered in files ending with `_apps.py` (or configured `app_suffix`):
```python
from domovoy.applications.registration import register_app
register_app(
app_class=MyApp,
app_name="unique_app_name",
config=MyAppConfig(some_param="value"),
)
```
**Critical constraints**:
```python
state = self.hass.get_state(entity_id)
await self.hass.services.light.turn_on(
entity_id=light,
brightness=255
)
self.hass.listen_trigger(trigger, callback)
await self.hass.wait_for_state_to_be(entity_id, states, duration, timeout)
```
```python
self.callbacks.listen_state(entity_id, callback, immediate=False, oneshot=False)
self.callbacks.listen_attribute(entity_id, attribute, callback)
self.callbacks.run_at(callback, datetime)
self.callbacks.run_in(interval, callback)
self.callbacks.run_daily(callback, time)
self.callbacks.run_every(interval, callback, start)
self.callbacks.run_daily_on_sun_event(callback, sun_event, delta)
```
```python
sensor = self.servents_v2.create_sensor(
servent_id="my_sensor",
name="My Sensor",
wait_for_creation=True
)
sensor.set_state(value)
switch = self.servents_v2.create_switch(
servent_id="my_switch",
name="My Switch"
)
self.servents_v2.listen_button_press(
callback=my_callback,
button_name="My Button"
)
```
**Important notes**:
Entity IDs are typed objects, not strings:
```python
from domovoy.plugins.hass.entity_id import EntityID
from domovoy.plugins.hass.domains import Light, Switch
light = self.hass.entities.light.living_room
state = self.hass.get_state(light) # Returns typed state
```
Include only the parameters you need:
```python
async def on_state(entity_id, new):
pass
async def on_state_full(entity_id, attribute, old, new):
pass
async def on_event(event_name, data):
pass
```
1. **Always use async/await**: All app code runs in async context. Use `await` for I/O operations.
2. **Hot reload friendly**:
- Make `initialize()` idempotent
- Clean up resources in `finalize()`
- Don't leak resources across reloads
3. **Error handling**:
- Exceptions in `initialize()` mark app as FAILED
- Exceptions in callbacks are logged but don't crash the app
- Apps are isolated - one crash doesn't affect others
4. **Entity state caching**:
- HassCore maintains local cache of all entity states
- Cache updated via WebSocket events
- Use `warn_if_entity_doesnt_exists()` during development
5. **Code style**:
- Use ruff for linting and formatting
- Run pyright for type checking
- Line length: 120 characters
- Python >=3.13.2 required
The `config.yml` file requires:
1. Create a config dataclass inheriting from `AppConfigBase`
2. Create an app class inheriting from `AppBase[TConfig]`
3. Implement `initialize()` method to set up listeners and entities
4. Implement `finalize()` method for cleanup
5. Register the app in a `*_apps.py` file with `register_app()`
Add to `pyproject.toml` dependencies array, then run `uv sync`.
**App Lifecycle States**: CREATED → INITIALIZING → RUNNING → FINALIZING → TERMINATED (or FAILED)
**Core Components**:
**Plugin Injection**: Each app instance receives plugin instances during construction, providing isolated access to framework functionality.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/domovoy-development/raw