add home assistant integration
This commit is contained in:
parent
2a575c456c
commit
dece26ef3d
55
vendors/home_assistant_integration/__init__.py
vendored
Normal file
55
vendors/home_assistant_integration/__init__.py
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
"""The Immersive Home integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
|
from . import hub, websocket_api
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
|
"""Set up the ImmersiveHome component."""
|
||||||
|
|
||||||
|
hass.data[DOMAIN] = {
|
||||||
|
"hub": hub.Hub(hass),
|
||||||
|
}
|
||||||
|
|
||||||
|
websocket_api.async_setup_commands(hass)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Set up ImmersiveHome from a config entry."""
|
||||||
|
registration = entry.data
|
||||||
|
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, registration["device_id"])},
|
||||||
|
manufacturer="Someone",
|
||||||
|
model=registration["platform"],
|
||||||
|
name=registration["name"],
|
||||||
|
sw_version=registration["version"],
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
|
"""Unload a config entry."""
|
||||||
|
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||||
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
|
return unload_ok
|
29
vendors/home_assistant_integration/config_flow.py
vendored
Normal file
29
vendors/home_assistant_integration/config_flow.py
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
"""Config flow for Immersive Home."""
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigFlow
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
class ImmersiveHomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Handle a Mobile App config flow."""
|
||||||
|
|
||||||
|
VERSION = 1
|
||||||
|
|
||||||
|
async def async_step_user(self, user_input=None):
|
||||||
|
"""Handle a flow initialized by the user."""
|
||||||
|
placeholders = {
|
||||||
|
"apps_url": "https://www.home-assistant.io/integrations/immersive_home/#apps"
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.async_abort(
|
||||||
|
reason="install_app", description_placeholders=placeholders
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_registration(self, user_input=None):
|
||||||
|
"""Handle a flow initialized during registration."""
|
||||||
|
|
||||||
|
if "device_id" in user_input:
|
||||||
|
await self.async_set_unique_id(f"{user_input['device_id']}")
|
||||||
|
|
||||||
|
return self.async_create_entry(title=user_input["name"], data=user_input)
|
3
vendors/home_assistant_integration/const.py
vendored
Normal file
3
vendors/home_assistant_integration/const.py
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
"""Constants for the Immersive Home integration."""
|
||||||
|
|
||||||
|
DOMAIN = "immersive_home"
|
48
vendors/home_assistant_integration/hub.py
vendored
Normal file
48
vendors/home_assistant_integration/hub.py
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
|
||||||
|
class Hub:
|
||||||
|
manufacturer = "Immersive Home"
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant) -> None:
|
||||||
|
self._hass = hass
|
||||||
|
self.devices = {}
|
||||||
|
|
||||||
|
def add_device(self, device: Device) -> None:
|
||||||
|
self.devices[device.id] = device
|
||||||
|
|
||||||
|
def get_device(self, device_id: str) -> Device:
|
||||||
|
return self.devices.get(device_id)
|
||||||
|
|
||||||
|
|
||||||
|
class Device:
|
||||||
|
def __init__(self, device_id: str, name: str, version: str, platform: str) -> None:
|
||||||
|
self.id = device_id
|
||||||
|
self.name = name
|
||||||
|
self.version = version
|
||||||
|
self.platform = platform
|
||||||
|
self.room = None
|
||||||
|
|
||||||
|
self._callbacks = set()
|
||||||
|
|
||||||
|
def set_room(self, room: str) -> None:
|
||||||
|
self.room = room
|
||||||
|
|
||||||
|
asyncio.create_task(self.publish_updates())
|
||||||
|
|
||||||
|
def add_callback(self, callback: callable[[], None]) -> None:
|
||||||
|
"""Register callback, called when Roller changes state."""
|
||||||
|
self._callbacks.add(callback)
|
||||||
|
|
||||||
|
def remove_callback(self, callback: callable[[], None]) -> None:
|
||||||
|
"""Remove previously registered callback."""
|
||||||
|
self._callbacks.discard(callback)
|
||||||
|
|
||||||
|
async def publish_updates(self) -> None:
|
||||||
|
"""Schedule call all registered callbacks."""
|
||||||
|
for callback in self._callbacks:
|
||||||
|
callback()
|
14
vendors/home_assistant_integration/manifest.json
vendored
Normal file
14
vendors/home_assistant_integration/manifest.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"domain": "immersive_home",
|
||||||
|
"name": "ImmersiveHome",
|
||||||
|
"codeowners": ["@nitwel"],
|
||||||
|
"config_flow": true,
|
||||||
|
"dependencies": ["http", "websocket_api"],
|
||||||
|
"documentation": "https://www.home-assistant.io/integrations/immersive_home",
|
||||||
|
"homekit": {},
|
||||||
|
"iot_class": "local_push",
|
||||||
|
"requirements": [],
|
||||||
|
"ssdp": [],
|
||||||
|
"zeroconf": [],
|
||||||
|
"version": "0.0.1"
|
||||||
|
}
|
59
vendors/home_assistant_integration/sensor.py
vendored
Normal file
59
vendors/home_assistant_integration/sensor.py
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
"""Platform for sensor integration."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.sensor import SensorEntity
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .hub import Device, Hub
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config: ConfigType,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
discovery_info: DiscoveryInfoType | None = None,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the sensor platform."""
|
||||||
|
|
||||||
|
hub: Hub = hass.data[DOMAIN]["hub"]
|
||||||
|
|
||||||
|
for device in hub.devices.values():
|
||||||
|
async_add_entities([RoomSensor(device)])
|
||||||
|
|
||||||
|
|
||||||
|
class RoomSensor(SensorEntity):
|
||||||
|
"""Representation of a Sensor."""
|
||||||
|
|
||||||
|
def __init__(self, device: Device) -> None:
|
||||||
|
"""Initialize the sensor."""
|
||||||
|
self._attr_name = f"{device.name} Room"
|
||||||
|
self._attr_unique_id = f"{device.id}_room"
|
||||||
|
self._device = device
|
||||||
|
self._attr_should_poll = False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._device.id)},
|
||||||
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
return self._device.room
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Run when this Entity has been added to HA."""
|
||||||
|
# Sensors should also register callbacks to HA when their state changes
|
||||||
|
self._device.add_callback(self.async_write_ha_state)
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self):
|
||||||
|
"""Entity being removed from hass."""
|
||||||
|
# The opposite of async_added_to_hass. Remove any registered call backs here.
|
||||||
|
self._device.remove_callback(self.async_write_ha_state)
|
13
vendors/home_assistant_integration/strings.json
vendored
Normal file
13
vendors/home_assistant_integration/strings.json
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"confirm": {
|
||||||
|
"description": "[%key:common::config_flow::description::confirm_setup%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"abort": {
|
||||||
|
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||||
|
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
vendors/home_assistant_integration/websocket_api.py
vendored
Normal file
86
vendors/home_assistant_integration/websocket_api.py
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
"""Home Assistant websocket API."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components import websocket_api
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .hub import Device, Hub
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_setup_commands(hass):
|
||||||
|
"""Set up the mobile app websocket API."""
|
||||||
|
websocket_api.async_register_command(hass, handle_register)
|
||||||
|
websocket_api.async_register_command(hass, handle_update)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required("type"): "immersive_home/register",
|
||||||
|
vol.Required("device_id"): str,
|
||||||
|
vol.Required("name"): str,
|
||||||
|
vol.Required("version"): str,
|
||||||
|
vol.Required("platform"): str,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@websocket_api.async_response
|
||||||
|
async def handle_register(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
connection: websocket_api.ActiveConnection,
|
||||||
|
msg: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Set up a new Immersive Home Device."""
|
||||||
|
|
||||||
|
hub: Hub = hass.data[DOMAIN]["hub"]
|
||||||
|
|
||||||
|
hub.add_device(
|
||||||
|
Device(
|
||||||
|
msg["device_id"],
|
||||||
|
msg["name"],
|
||||||
|
msg["version"],
|
||||||
|
msg["platform"],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_create_task(
|
||||||
|
hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, data=msg, context={"source": "registration"}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
connection.send_result(msg["id"], {"result": "success"})
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required("type"): "immersive_home/update",
|
||||||
|
vol.Required("device_id"): str,
|
||||||
|
vol.Optional("room"): str,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
def handle_update(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
connection: websocket_api.ActiveConnection,
|
||||||
|
msg: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
"""Update data of a Immersive Home Device."""
|
||||||
|
|
||||||
|
hub: Hub = hass.data[DOMAIN]["hub"]
|
||||||
|
device = hub.get_device(msg["device_id"])
|
||||||
|
|
||||||
|
if device is None:
|
||||||
|
connection.send_error(msg["id"], "device_not_found", "Device not found")
|
||||||
|
return
|
||||||
|
|
||||||
|
if "room" in msg:
|
||||||
|
device.set_room(msg["room"])
|
||||||
|
|
||||||
|
connection.send_result(msg["id"], {"result": "success"})
|
Loading…
Reference in New Issue
Block a user