Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Home Assistant integration boilerplate #3

Merged
merged 2 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions custom_components/vinx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady

from custom_components.vinx.lw3 import LW3

PLATFORMS: list[Platform] = [Platform.MEDIA_PLAYER]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from a config entry."""
# Verify we can connect
try:
device = LW3(entry.data["host"], entry.data["port"])
await device.connect()
except ConnectionError as e:
raise ConfigEntryNotReady("Unable to connect") from e

# Store the device as runtime data in teh entry
entry.runtime_data = device

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."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
40 changes: 40 additions & 0 deletions custom_components/vinx/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import Any

import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult

from .const import CONF_HOST, CONF_PORT, DOMAIN
from .lw3 import LW3

STEP_USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=6107): int,
}
)


class VinxConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 1

async def async_step_user(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
"""Handle user initiated configuration"""
errors: dict[str, str] = {}
if user_input is not None:
try:
# Try to connect to the device
lw3_device = LW3(user_input["host"], user_input["port"])
await lw3_device.connect()

# Make a title for the entry
title = str(await lw3_device.get_property("/.ProductName"))

# Disconnect, this was just for validation
await lw3_device.disconnect()
except (ConnectionError, OSError):
errors["base"] = "cannot_connect"
else:
return self.async_create_entry(title=title, data=user_input)

return self.async_show_form(step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors)
6 changes: 6 additions & 0 deletions custom_components/vinx/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DOMAIN = "vinx"

CONF_HOST = "host"
CONF_PORT = "port"
CONF_PASSWORD = "password"
CONF_DEVICE_TYPE = "device_type"
13 changes: 4 additions & 9 deletions custom_components/vinx/lw3.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ async def _read_until(self, phrase: str) -> str | None:
async def connect(self):
self._reader, self._writer = await asyncio.open_connection(self._hostname, self._port)

async def disconnect(self):
self._writer.close()
await self._writer.wait_closed()

@staticmethod
def _is_error_response(response: str) -> bool:
return response[1] == "E"
Expand Down Expand Up @@ -95,12 +99,3 @@ async def get_property(self, path: str) -> PropertyResponse:

async def set_property(self, path: str, value: str) -> PropertyResponse:
return await asyncio.wait_for(self._run_set_property(path, value), self._timeout)

async def get_product_name(self):
return str(await self._run_get_property("/.ProductName"))

async def get_serial_number(self):
return str(await self._run_get_property("/.SerialNumber"))

async def get_mac_address(self):
return str(await self._run_get_property("/.MacAddress"))
17 changes: 17 additions & 0 deletions custom_components/vinx/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"domain": "vinx",
"name": "VINX",
"version": "0.0.1",
"codeowners": [
"@Jalle19"
],
"config_flow": true,
"integration_type": "device",
"dependencies": [],
"documentation": "https://www.home-assistant.io/integrations/vinx",
"homekit": {},
"iot_class": "local_polling",
"requirements": [],
"ssdp": [],
"zeroconf": []
}
21 changes: 21 additions & 0 deletions custom_components/vinx/media_player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import logging

from homeassistant.components.media_player import MediaPlayerEntity

from custom_components.vinx import LW3

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass, entry, async_add_entities):
# Extract stored runtime data
lw3_device: LW3 = entry.runtime_data
_LOGGER.info(lw3_device)


class VinxEncoder(MediaPlayerEntity):
pass


class VinxDecoder(MediaPlayerEntity):
pass
19 changes: 19 additions & 0 deletions custom_components/vinx/strings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"config": {
"step": {
"user": {
"data": {
"host": "[%key:common::config_flow::data::host%]",
"port": "[%key:common::config_flow::data::port%]"
}
}
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
}
}
19 changes: 19 additions & 0 deletions custom_components/vinx/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"config": {
"abort": {
"already_configured": "Device is already configured"
},
"error": {
"cannot_connect": "Failed to connect",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"host": "Host",
"port": "Port"
}
}
}
}
}