forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add powerfox integration (home-assistant#131640)
- Loading branch information
1 parent
535b477
commit abd3466
Showing
23 changed files
with
1,228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"""The Powerfox integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
import asyncio | ||
|
||
from powerfox import Powerfox, PowerfoxConnectionError | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD, Platform | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import ConfigEntryNotReady | ||
from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||
|
||
from .coordinator import PowerfoxDataUpdateCoordinator | ||
|
||
PLATFORMS: list[Platform] = [Platform.SENSOR] | ||
|
||
type PowerfoxConfigEntry = ConfigEntry[list[PowerfoxDataUpdateCoordinator]] | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: PowerfoxConfigEntry) -> bool: | ||
"""Set up Powerfox from a config entry.""" | ||
client = Powerfox( | ||
username=entry.data[CONF_EMAIL], | ||
password=entry.data[CONF_PASSWORD], | ||
session=async_get_clientsession(hass), | ||
) | ||
|
||
try: | ||
devices = await client.all_devices() | ||
except PowerfoxConnectionError as err: | ||
await client.close() | ||
raise ConfigEntryNotReady from err | ||
|
||
coordinators: list[PowerfoxDataUpdateCoordinator] = [ | ||
PowerfoxDataUpdateCoordinator(hass, client, device) for device in devices | ||
] | ||
|
||
await asyncio.gather( | ||
*[ | ||
coordinator.async_config_entry_first_refresh() | ||
for coordinator in coordinators | ||
] | ||
) | ||
|
||
entry.runtime_data = coordinators | ||
|
||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) | ||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: PowerfoxConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
"""Config flow for Powerfox integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
from typing import Any | ||
|
||
from powerfox import Powerfox, PowerfoxAuthenticationError, PowerfoxConnectionError | ||
import voluptuous as vol | ||
|
||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult | ||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD | ||
from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||
|
||
from .const import DOMAIN | ||
|
||
STEP_USER_DATA_SCHEMA = vol.Schema( | ||
{ | ||
vol.Required(CONF_EMAIL): str, | ||
vol.Required(CONF_PASSWORD): str, | ||
} | ||
) | ||
|
||
|
||
class PowerfoxConfigFlow(ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow for Powerfox.""" | ||
|
||
async def async_step_user( | ||
self, user_input: dict[str, Any] | None = None | ||
) -> ConfigFlowResult: | ||
"""Handle the initial step.""" | ||
errors: dict[str, str] = {} | ||
if user_input is not None: | ||
self._async_abort_entries_match({CONF_EMAIL: user_input[CONF_EMAIL]}) | ||
client = Powerfox( | ||
username=user_input[CONF_EMAIL], | ||
password=user_input[CONF_PASSWORD], | ||
session=async_get_clientsession(self.hass), | ||
) | ||
try: | ||
await client.all_devices() | ||
except PowerfoxAuthenticationError: | ||
errors["base"] = "invalid_auth" | ||
except PowerfoxConnectionError: | ||
errors["base"] = "cannot_connect" | ||
else: | ||
return self.async_create_entry( | ||
title=user_input[CONF_EMAIL], | ||
data={ | ||
CONF_EMAIL: user_input[CONF_EMAIL], | ||
CONF_PASSWORD: user_input[CONF_PASSWORD], | ||
}, | ||
) | ||
return self.async_show_form( | ||
step_id="user", | ||
errors=errors, | ||
data_schema=STEP_USER_DATA_SCHEMA, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"""Constants for the Powerfox integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
from datetime import timedelta | ||
import logging | ||
from typing import Final | ||
|
||
DOMAIN: Final = "powerfox" | ||
LOGGER = logging.getLogger(__package__) | ||
SCAN_INTERVAL = timedelta(minutes=5) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
"""Coordinator for Powerfox integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
from powerfox import Device, Powerfox, PowerfoxConnectionError, Poweropti | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed | ||
|
||
from .const import DOMAIN, LOGGER, SCAN_INTERVAL | ||
|
||
|
||
class PowerfoxDataUpdateCoordinator(DataUpdateCoordinator[Poweropti]): | ||
"""Class to manage fetching Powerfox data from the API.""" | ||
|
||
config_entry: ConfigEntry | ||
|
||
def __init__( | ||
self, | ||
hass: HomeAssistant, | ||
client: Powerfox, | ||
device: Device, | ||
) -> None: | ||
"""Initialize global Powerfox data updater.""" | ||
super().__init__( | ||
hass, | ||
LOGGER, | ||
name=DOMAIN, | ||
update_interval=SCAN_INTERVAL, | ||
) | ||
self.client = client | ||
self.device = device | ||
|
||
async def _async_update_data(self) -> Poweropti: | ||
"""Fetch data from Powerfox API.""" | ||
try: | ||
return await self.client.device(device_id=self.device.id) | ||
except PowerfoxConnectionError as error: | ||
raise UpdateFailed(error) from error |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
"""Generic entity for Powerfox.""" | ||
|
||
from __future__ import annotations | ||
|
||
from powerfox import Device | ||
|
||
from homeassistant.helpers.device_registry import DeviceInfo | ||
from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
||
from .const import DOMAIN | ||
from .coordinator import PowerfoxDataUpdateCoordinator | ||
|
||
|
||
class PowerfoxEntity(CoordinatorEntity[PowerfoxDataUpdateCoordinator]): | ||
"""Base entity for Powerfox.""" | ||
|
||
_attr_has_entity_name = True | ||
|
||
def __init__( | ||
self, | ||
coordinator: PowerfoxDataUpdateCoordinator, | ||
device: Device, | ||
) -> None: | ||
"""Initialize Powerfox entity.""" | ||
super().__init__(coordinator) | ||
self._attr_device_info = DeviceInfo( | ||
identifiers={(DOMAIN, device.id)}, | ||
manufacturer="Powerfox", | ||
model=device.type.human_readable, | ||
name=device.name, | ||
serial_number=device.id, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"domain": "powerfox", | ||
"name": "Powerfox", | ||
"codeowners": ["@klaasnicolaas"], | ||
"config_flow": true, | ||
"documentation": "https://www.home-assistant.io/integrations/powerfox", | ||
"iot_class": "cloud_polling", | ||
"quality_scale": "bronze", | ||
"requirements": ["powerfox==1.0.0"], | ||
"zeroconf": [ | ||
{ | ||
"type": "_http._tcp.local.", | ||
"name": "powerfox*" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
rules: | ||
# Bronze | ||
action-setup: | ||
status: exempt | ||
comment: | | ||
This integration does not provide additional actions. | ||
appropriate-polling: done | ||
brands: done | ||
common-modules: done | ||
config-flow-test-coverage: done | ||
config-flow: done | ||
dependency-transparency: done | ||
docs-actions: | ||
status: exempt | ||
comment: | | ||
This integration does not provide additional actions. | ||
docs-high-level-description: done | ||
docs-installation-instructions: done | ||
docs-removal-instructions: done | ||
entity-event-setup: | ||
status: exempt | ||
comment: | | ||
Entities of this integration does not explicitly subscribe to events. | ||
entity-unique-id: done | ||
has-entity-name: done | ||
runtime-data: done | ||
test-before-configure: done | ||
test-before-setup: done | ||
unique-config-entry: done | ||
|
||
# Silver | ||
action-exceptions: | ||
status: exempt | ||
comment: | | ||
This integration does not provide additional actions. | ||
config-entry-unloading: done | ||
docs-configuration-parameters: | ||
status: exempt | ||
comment: | | ||
This integration does not have an options flow. | ||
docs-installation-parameters: done | ||
entity-unavailable: done | ||
integration-owner: done | ||
log-when-unavailable: done | ||
parallel-updates: | ||
status: exempt | ||
comment: | | ||
This integration uses a coordinator to handle updates. | ||
reauthentication-flow: todo | ||
test-coverage: done | ||
|
||
# Gold | ||
devices: done | ||
diagnostics: todo | ||
discovery-update-info: | ||
status: exempt | ||
comment: | | ||
This integration is connecting to a cloud service. | ||
discovery: | ||
status: exempt | ||
comment: | | ||
It can find poweropti devices via zeroconf, but will start a normal user flow. | ||
docs-data-update: done | ||
docs-examples: todo | ||
docs-known-limitations: done | ||
docs-supported-devices: done | ||
docs-supported-functions: done | ||
docs-troubleshooting: todo | ||
docs-use-cases: done | ||
dynamic-devices: todo | ||
entity-category: done | ||
entity-device-class: done | ||
entity-disabled-by-default: | ||
status: exempt | ||
comment: | | ||
This integration does not have any entities that should disabled by default. | ||
entity-translations: done | ||
exception-translations: done | ||
icon-translations: | ||
status: exempt | ||
comment: | | ||
There is no need for icon translations. | ||
reconfiguration-flow: todo | ||
repair-issues: | ||
status: exempt | ||
comment: | | ||
This integration doesn't have any cases where raising an issue is needed. | ||
stale-devices: todo | ||
# Platinum | ||
async-dependency: done | ||
inject-websession: done | ||
strict-typing: done |
Oops, something went wrong.