Home Assistant Community Hacks: Master Custom Integrations Fast
If you’ve ever stared at a wall of buttons in your Home Assistant dashboard and thought, “I wish this thing could talk to my toaster,” you’re not alone. The magic of Home Assistant lies in its community-driven custom integrations, which turn your humble Raspberry Pi into a supercharged smart hub. In this guide, we’ll dive deep into how the community ecosystem works, walk through a step‑by‑step tutorial to build your own integration, and share pro tips that will have you hacking like a seasoned developer in no time.
Why the Community Matters
The Home Assistant core team releases a solid baseline every few months, but the real power comes from over 2,000 custom components contributed by users worldwide. These add-ons can:
- Connect to niche hardware (think 3D printers, old thermostats)
- Extend existing services (e.g., adding a new sensor to your smart meter)
- Automate complex flows that the core UI can’t handle alone
- Bridge gaps between incompatible ecosystems (Alexa <-> Google Home)
Because every integration is open source, you can inspect the code, tweak it for your setup, or even contribute back to the repo. That’s why the community is essentially the living codebase of Home Assistant.
The Anatomy of a Custom Integration
Before we jump into building one, let’s break down the typical file structure of a custom component. Understanding this will make the later steps feel like second nature.
File / Folder | Description |
---|---|
manifest.json | Metadata (name, version, dependencies) |
__init__.py | Optional initialization code (runs on startup) |
sensor.py | Defines sensor entities (most common) |
binary_sensor.py | Defines binary sensor entities (on/off) |
climate.py | Defines climate entities (thermostats) |
services.yaml | Custom services exposed to Home Assistant |
config_flow.py | Wizard for UI configuration (optional) |
tests/ | Unit tests for your component |
translations/ | Localization files (.json) |
In most cases, you’ll only need manifest.json
, a sensor file, and maybe a service definition. The rest are for more complex integrations.
Step‑by‑Step: Building a Simple Weather Sensor
Let’s build a tiny integration that pulls data from the OpenWeatherMap API and exposes it as a sensor in Home Assistant. We’ll call it weather_simple
.
1️⃣ Create the Component Folder
Navigate to your Home Assistant custom_components/
directory and create a new folder:
cd ~/.homeassistant/custom_components
mkdir weather_simple
2️⃣ Add manifest.json
This file tells Home Assistant how to load your component.
{
"domain": "weather_simple",
"name": "Weather Simple",
"documentation": "https://github.com/yourusername/weather_simple",
"requirements": ["requests==2.31.0"],
"dependencies": [],
"codeowners": ["@yourgithubhandle"]
}
Notice the requirements
key: we’ll use requests
to hit the API.
3️⃣ Write sensor.py
This file defines the sensor entity. Keep it lean and readable.
import logging
import requests
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from homeassistant.components.sensor import SensorEntity
_LOGGER = logging.getLogger(__name__)
API_URL = "https://api.openweathermap.org/data/2.5/weather"
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Weather Simple sensor from a config entry."""
coordinator = WeatherCoordinator(hass, config_entry.data)
await coordinator.async_refresh()
async_add_entities([WeatherSensor(coordinator)], True)
class WeatherCoordinator(DataUpdateCoordinator):
"""Fetch weather data from OpenWeatherMap."""
def __init__(self, hass, config):
super().__init__(
hass,
_LOGGER,
name="Weather Simple",
update_interval=timedelta(minutes=10),
)
self.api_key = config["api_key"]
self.city_id = config["city_id"]
async def _async_update_data(self):
"""Fetch data from API."""
params = {"id": self.city_id, "appid": self.api_key, "units": "metric"}
try:
response = await self.hass.async_add_executor_job(
requests.get, API_URL, params=params
)
response.raise_for_status()
except Exception as err:
raise UpdateFailed(f"Error fetching data: {err}") from err
return response.json()
class WeatherSensor(SensorEntity):
"""Representation of a weather sensor."""
def __init__(self, coordinator):
self.coordinator = coordinator
self._attr_name = "Current Temperature"
self._attr_unique_id = f"weather_simple_{coordinator.city_id}"
self._attr_icon = "mdi:weather-cloudy"
@property
def state(self):
return self.coordinator.data.get("main", {}).get("temp")
@property
def extra_state_attributes(self):
return {
"humidity": self.coordinator.data.get("main", {}).get("humidity"),
"weather": self.coordinator.data.get("weather")[0].get("description")
}
We used DataUpdateCoordinator
to handle polling and caching. This is the recommended pattern for any sensor that requires periodic API calls.
4️⃣ Define configuration.yaml
Add the following to your Home Assistant config:
weather_simple:
api_key: YOUR_OPENWEATHERMAP_API_KEY
city_id: 2643743 # London, UK (example)
Restart Home Assistant, and you should see a new sensor called Current Temperature.
5️⃣ Add a Custom Service (Optional)
If you want to refresh the sensor on demand, create services.yaml
in the same folder:
refresh:
description: "Force a refresh of the weather data"
And modify sensor.py
to expose it:
async def async_setup_entry(hass, config_entry, async_add_entities):
...
hass.services.async_register(
"weather_simple",
"refresh",
coordinator.async_refresh
)
Now you can call homeassistant.services.call("weather_simple", "refresh")
from the Developer Tools.
Testing Your Integration
A solid integration includes unit tests. Create a tests/
folder and add:
import pytest
from homeassistant.core import HomeAssistant
@pytest.mark.asyncio
async def test_sensor_state(hass: HomeAssistant):
"""Test that the sensor returns a numeric state."""
await hass.async_block_till_done()
state = hass.states.get("sensor.current_temperature")
assert state is not None
assert float(state.state) == pytest.approx(0, abs=10)
Run pytest tests/
to verify your code. If it passes, you’re ready for production.
Deploying to the Community Store (HACS)
Once you’re confident, consider publishing your integration to the Home Assistant Community Store (HACS). Here’s a quick checklist:
- Push to GitHub – Public repo with a clear README.
- Tag a release – Semantic versioning (e.g.,
v1.0.0
). - Add a HACS manifest
Leave a Reply