I have a very basic question. I am creating a custom component. I have no problem creating entities. However, I am unable to create a device and attach entities to the device. Does anyone have a very simple example of this. For example, creating a device that has two sensors connected to it. I’m surprised but I can’t find a simple example anywhere. I must be very bad at searching as this seems so basic. Thank you very much.
Here is my code so far - so the question is how do I create a device that will contain the sensor, and appear in the UI as a device…
__init__.py:
"""Example Load Platform integration."""
from __future__ import annotations
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
DOMAIN = 'example_load_platform'
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Your controller/hub specific code."""
# Data that you want to share with your platforms
hass.data[DOMAIN] = {
'temperature': 23
}
hass.helpers.discovery.load_platform('sensor', DOMAIN, {}, config)
return True
sensor.py
"""Platform for sensor integration."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity
from homeassistant.const import TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.entity import generate_entity_id
from . import DOMAIN
import logging
LOGGER: logging.Logger = logging.getLogger(DOMAIN)
LOGGER.setLevel(logging.INFO)
LOGGER.warn('Loading, logging has been initiated')
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None
) -> None:
"""Set up the sensor platform."""
LOGGER.info('Setting up the Sensor Platform')
# We only want this platform to be set up via discovery.
if discovery_info is None:
return
add_entities([ExampleSensor()])
LOGGER.info('Entities have been added')
class ExampleSensor(SensorEntity):
"""Representation of a sensor."""
def __init__(self) -> None:
"""Initialize the sensor."""
self._state = None
@property
def name(self) -> str:
"""Return the name of the sensor."""
return 'Example Temperature Sensor'
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def unit_of_measurement(self) -> str:
"""Return the unit of measurement."""
return TEMP_CELSIUS
def update(self) -> None:
"""Fetch new state data for the sensor.
This is the only method that should fetch new data for Home Assistant.
"""
self._state = self.hass.data[DOMAIN]['temperature']
Have a look at other integrations?
It’s been a while since I wrote mine for my PelletStove
Or pick any other official integration → core/homeassistant/components at dev · home-assistant/core · GitHub
Have a look at this example integration i created. See device_info in sensor.py
Thank you - I have looked at code and examples but nothing I have tried has actually created the device. I see in your code that you are creating entities but not a containing device. My question is not about creating the entities, which my code does correctly, but adding the entities to a new device that I also want to create.
Does this help Device registry | Home Assistant Developer Docs
Thank you - it does help, but still code is not working: The entity for the sensor is created, but not the device. The device_info method for the sensor is never called.
__init__.py:
"""Example Load Platform integration."""
from __future__ import annotations
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.discovery import load_platform
from homeassistant.config_entries import ConfigEntry
DOMAIN = 'example_load_platform_v2'
import logging
LOGGER: logging.Logger = logging.getLogger(DOMAIN)
LOGGER.setLevel(logging.INFO)
LOGGER.warn('Loading, logging has been initiated')
async def async_setup(hass: HomeAssistant, config: dict) -> bool:
"""Set up the custom component from configuration.yaml."""
LOGGER.info('Setting up the SensorV2 platform from init...')
load_platform(hass, 'sensor', DOMAIN, {}, config)
# Data that you want to share with you__uir platforms
hass.data[DOMAIN] = {
'temperature': 23
}
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up custom component from a config entry."""
LOGGER.info('Setting up the entry from init...')
hass.data[DOMAIN][entry.entry_id] = entry.data
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, "sensor")
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
LOGGER.info('Unloading the entry from init')
await hass.config_entries.async_forward_entry_unload(entry, "sensor")
hass.data[DOMAIN].pop(entry.entry_id)
return True
sensor.py:
"""Platform for sensor integration."""
from __future__ import annotations
from homeassistant.components.sensor import SensorEntity
from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.device_registry import DeviceInfo
from . import DOMAIN
import logging
LOGGER: logging.Logger = logging.getLogger(DOMAIN)
LOGGER.setLevel(logging.INFO)
LOGGER.warn('Loading, logging has been initiated')
async def async_setup_platform(
hass: HomeAssistant,
config: ConfigType,
async_add_entities: AddEntitiesCallback,
discovery_info: Optgional[DiscoveryInfoType] = None
) -> None:
"""Set up the sensor platform."""
LOGGER.info('Setting up the SensorV2 Platform...')
async_add_entities([ExampleSensorV2()])
class ExampleSensorV2(SensorEntity):
"""Representation of a sensor."""
def __init__(self) -> None:
"""Initialize the sensor."""
LOGGER.warn('Running init for the entity...')
self._state = None
self._entry_id = "foobarbaz"
@property
def name(self) -> str:
"""Return the name of the sensor."""
LOGGER.warn('Generating sensor name...')
return 'Example Temperature Sensor V2'
@property
def unique_id(self) -> str:
"""Return a unique ID for the sensor."""
LOGGER.warn('Generating sensor id...')
return "foobarbaz123"
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def device_info(self) -> DeviceInfo:
"""Return device information."""
LOGGER.warn('Generating device info...')
return DeviceInfo(
name="Example Sensor Device V2",
manufacturer="Example Sensor Manufacturer V2",
model="Example Sensor Model V2",
identifiers={
(DOMAIN, self._entry_id)
},
)
def update(self) -> None:
"""Fetch new state data for the sensor.
This is the only method that should fetch new data for Home Assistant.
"""
LOGGER.warn('Fetching new data...')
self._state = self.hass.data[DOMAIN]['temperature']
Are you using config.yaml to set it up or a config flow? It will only create devices if using config flow. See the tip box in the link from @nickrout under Defining Devices.
Ah - that was the issue!!! Thank you. I was using yaml not config flow. Making that change solved the problem. Thank you very much.
Wait so does this mean that it is completely impossible for an integration to create a device if the integration is set up via config.yaml?
I understand the push towards config flows but to completely deprecate this function from the config.yaml is a bad idea. Why not allow for advanced users to keep using the config.yaml?
If developing, look at the MQTT integration, it is the only integration I know that can create devices in yaml.
AFAIK devices have never been able to be create devices (except mqtt as @francisp says)