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

New core integration for VegeHub #129598

Open
wants to merge 29 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fc601e1
Initial commit for VegeHub integration
GhoweVege Oct 31, 2024
22e35c6
Merge branch 'dev' into Vegetronix_VegeHub
GhoweVege Oct 31, 2024
87dd38e
Merge branch 'dev' into Vegetronix_VegeHub
GhoweVege Nov 4, 2024
0075948
Moved several pieces to library, continuing.
GhoweVege Nov 6, 2024
3056c3f
All device contact moved to library
GhoweVege Nov 6, 2024
0d92f46
Merge branch 'dev' into Vegetronix_VegeHub
GhoweVege Nov 6, 2024
38b38f7
Updated documentation link
GhoweVege Nov 7, 2024
44d93ff
Fixed an error in strings.json
GhoweVege Nov 8, 2024
e41e140
Removed commented out code and unused file
GhoweVege Nov 8, 2024
dd88401
Merge branch 'dev' into Vegetronix_VegeHub
GhoweVege Nov 8, 2024
765bc12
Removed unneeded info logging, and a few missed lines of commented code
GhoweVege Nov 8, 2024
9d2b0a7
Added/removed comments for clarity
GhoweVege Nov 8, 2024
355e04b
Converted integration to use webhooks.
GhoweVege Nov 15, 2024
ecba7ce
Update __init__.py to remove unnecessary code.
GhoweVege Nov 18, 2024
3995712
Remove unnecessary code from config_flow.py
GhoweVege Nov 18, 2024
fd18915
Simplify unique_id assertion.
GhoweVege Nov 18, 2024
7b9bb16
Switch to CONF_ constant for user input
GhoweVege Nov 18, 2024
c315da8
Added explanation for passing exception.
GhoweVege Nov 18, 2024
95483c1
Got rid of try-except, since I don't really handle the exceptions her…
GhoweVege Nov 18, 2024
b65a678
Moved data transform to vegehub library
GhoweVege Nov 18, 2024
8ad306c
Changed references to use HA constants.
GhoweVege Nov 18, 2024
166f2c9
Fixed assigning and returning _attr properties.
GhoweVege Nov 18, 2024
1e2eb1f
Moved temperature sensor transform to the library.
GhoweVege Nov 18, 2024
0d05cdb
Moved sensor names to strings.json
GhoweVege Nov 19, 2024
1adf094
Made webhook names unique to avoid collisions when multiple devices a…
GhoweVege Nov 19, 2024
4e2074a
Converted to using entry.runtime_data
GhoweVege Nov 20, 2024
f22adea
Removed options flow for first PR
GhoweVege Nov 20, 2024
984d0d0
Removed switch support to limit PR to one platform
GhoweVege Nov 20, 2024
cf0b8bd
Removed/updated outdated tests
GhoweVege Nov 20, 2024
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
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,8 @@ build.json @home-assistant/supervisor
/tests/components/vallox/ @andre-richter @slovdahl @viiru- @yozik04
/homeassistant/components/valve/ @home-assistant/core
/tests/components/valve/ @home-assistant/core
/homeassistant/components/vegehub/ @ghowevege
/tests/components/vegehub/ @ghowevege
/homeassistant/components/velbus/ @Cereal2nd @brefra
/tests/components/velbus/ @Cereal2nd @brefra
/homeassistant/components/velux/ @Julius2342 @DeerMaximum
Expand Down
160 changes: 160 additions & 0 deletions homeassistant/components/vegehub/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""The Vegetronix VegeHub integration."""

from collections.abc import Awaitable, Callable
from http import HTTPStatus
import logging
from typing import Any

from aiohttp.hdrs import METH_POST
from aiohttp.web import Request, Response

from homeassistant.components.http import HomeAssistantView
from homeassistant.components.webhook import (
async_register as webhook_register,
async_unregister as webhook_unregister,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_WEBHOOK_ID, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.typing import ConfigType

from .const import DOMAIN, NAME, PLATFORMS

_LOGGER = logging.getLogger(__name__)

# The integration is only set up through the UI (config flow)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the VegeHub integration."""
return True # For now, we are not using YAML config.
GhoweVege marked this conversation as resolved.
Show resolved Hide resolved


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up VegeHub from a config entry."""

# Register the device in the device registry
device_registry = dr.async_get(hass)

hass.data.setdefault(DOMAIN, {})
GhoweVege marked this conversation as resolved.
Show resolved Hide resolved
device_mac = str(entry.data.get("mac_address"))

if entry.unique_id is None:
new_data = entry.data.copy()
unique_id = device_mac
hass.config_entries.async_update_entry(
entry, data=new_data, unique_id=unique_id
)
GhoweVege marked this conversation as resolved.
Show resolved Hide resolved

if device_registry.async_get_device(identifiers={(DOMAIN, entry.entry_id)}):
_LOGGER.error("Device %s is already registered", entry.entry_id)
return False

# Register the device
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
connections={(dr.CONNECTION_NETWORK_MAC, device_mac)},
identifiers={(DOMAIN, device_mac)},
manufacturer="Vegetronix",
model="VegeHub",
name=entry.data.get("hostname"),
sw_version=entry.data.get("sw_ver"),
configuration_url=entry.data.get("config_url"),
Comment on lines +50 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can those actually be empty?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it's possible if something went dramatically wrong somewhere. I don't understand. Should I be checking them first?

)

async def unregister_webhook(_: Any) -> None:
webhook_unregister(hass, entry.data[CONF_WEBHOOK_ID])

async def register_webhook() -> None:
webhook_name = "VegeHub"
if entry.title != NAME:
webhook_name = f"{NAME} {entry.title}"

webhook_register(
hass,
DOMAIN,
webhook_name,
entry.data[CONF_WEBHOOK_ID],
get_webhook_handler(device_mac),
allowed_methods=[METH_POST],
)
_LOGGER.debug(
"Registered VegeHub webhook at hass: %s", entry.data.get("webhook_url")
)

entry.async_on_unload(
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, unregister_webhook)
)

entry.async_create_background_task(
hass, register_webhook(), "vegehub_register_webhook"
)
# Now add in all the entities for this 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 VegeHub config entry."""

# Unload platforms
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

# If successful, clean up resources
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id, None)

return unload_ok


def get_webhook_handler(
device_mac: str,
) -> Callable[[HomeAssistant, str, Request], Awaitable[Response | None]]:
"""Return webhook handler."""

async def async_webhook_handler(
hass: HomeAssistant, webhook_id: str, request: Request
) -> Response | None:
# Handle http post calls to the path.
if not request.body_exists:
return HomeAssistantView.json(
result="No Body", status_code=HTTPStatus.BAD_REQUEST
)
data = await request.json()

# Process sensor data
if "sensors" in data:
for sensor in data["sensors"]:
slot = sensor.get("slot")
latest_sample = sensor["samples"][-1]
value = latest_sample["v"]

# Use the slot number and key to find entity
entity_id = f"vegehub_{device_mac}_{slot}".lower()

# Update entity with the new sensor data
await _update_sensor_entity(hass, value, entity_id)

return HomeAssistantView.json(result="OK", status_code=HTTPStatus.OK)

return async_webhook_handler


async def _update_sensor_entity(hass: HomeAssistant, value: float, entity_id: str):
"""Update the corresponding Home Assistant entity with the latest sensor value."""

# Find the sensor entity and update its state
entity = None
try:
if entity_id in hass.data[DOMAIN]:
entity = hass.data[DOMAIN][entity_id]
if not entity:
_LOGGER.error("Sensor entity %s not found", entity_id)
else:
await entity.async_update_sensor(value)
except Exception as e:
_LOGGER.error("Sensor entity %s not found: %s", entity_id, e)
raise
Loading