mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
Add integration for ProgettiHWSW automation boards (#37922)
* Opened a new fresh page to clean my mess. * Solved pylint warnings * Fixing pylint issue of defining attr outside init. * Excluded files from being tested by codecov. * Solved binary sensor error. * Fixed some stylisation errors. * Resolved input not updating problem. * Added port entry to test file. * Added tests for create_entry. * Added support for better state management. * Increased code coverage of config_flow.py & made some tweaks. * Increased coverage of config_flow.py by adding tests for unknown exceptions. * A small bugfix. * Stylised code as per Chris' suggestions. * Stylised code again. * Improved quality of test code. * Added step_id in config flow tests.
This commit is contained in:
parent
4bbc737954
commit
e707b50658
@ -667,6 +667,9 @@ omit =
|
|||||||
homeassistant/components/poolsense/sensor.py
|
homeassistant/components/poolsense/sensor.py
|
||||||
homeassistant/components/poolsense/binary_sensor.py
|
homeassistant/components/poolsense/binary_sensor.py
|
||||||
homeassistant/components/proliphix/climate.py
|
homeassistant/components/proliphix/climate.py
|
||||||
|
homeassistant/components/progettihwsw/__init__.py
|
||||||
|
homeassistant/components/progettihwsw/binary_sensor.py
|
||||||
|
homeassistant/components/progettihwsw/switch.py
|
||||||
homeassistant/components/prometheus/*
|
homeassistant/components/prometheus/*
|
||||||
homeassistant/components/prowl/notify.py
|
homeassistant/components/prowl/notify.py
|
||||||
homeassistant/components/proxmoxve/*
|
homeassistant/components/proxmoxve/*
|
||||||
|
@ -325,6 +325,7 @@ homeassistant/components/plum_lightpad/* @ColinHarrington @prystupa
|
|||||||
homeassistant/components/point/* @fredrike
|
homeassistant/components/point/* @fredrike
|
||||||
homeassistant/components/poolsense/* @haemishkyd
|
homeassistant/components/poolsense/* @haemishkyd
|
||||||
homeassistant/components/powerwall/* @bdraco @jrester
|
homeassistant/components/powerwall/* @bdraco @jrester
|
||||||
|
homeassistant/components/progettihwsw/* @ardaseremet
|
||||||
homeassistant/components/prometheus/* @knyar
|
homeassistant/components/prometheus/* @knyar
|
||||||
homeassistant/components/proxmoxve/* @k4ds3 @jhollowe
|
homeassistant/components/proxmoxve/* @k4ds3 @jhollowe
|
||||||
homeassistant/components/ps4/* @ktnrg45
|
homeassistant/components/ps4/* @ktnrg45
|
||||||
|
64
homeassistant/components/progettihwsw/__init__.py
Normal file
64
homeassistant/components/progettihwsw/__init__.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
"""Automation manager for boards manufactured by ProgettiHWSW Italy."""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from ProgettiHWSW.ProgettiHWSWAPI import ProgettiHWSWAPI
|
||||||
|
from ProgettiHWSW.input import Input
|
||||||
|
from ProgettiHWSW.relay import Relay
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
PLATFORMS = ["switch", "binary_sensor"]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass, config):
|
||||||
|
"""Set up the ProgettiHWSW Automation component."""
|
||||||
|
hass.data[DOMAIN] = {}
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||||
|
"""Set up ProgettiHWSW Automation from a config entry."""
|
||||||
|
|
||||||
|
hass.data[DOMAIN][entry.entry_id] = ProgettiHWSWAPI(
|
||||||
|
f'{entry.data["host"]}:{entry.data["port"]}'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check board validation again to load new values to API.
|
||||||
|
await hass.data[DOMAIN][entry.entry_id].check_board()
|
||||||
|
|
||||||
|
for component in PLATFORMS:
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
||||||
|
"""Unload a config entry."""
|
||||||
|
unload_ok = all(
|
||||||
|
await asyncio.gather(
|
||||||
|
*[
|
||||||
|
hass.config_entries.async_forward_entry_unload(entry, component)
|
||||||
|
for component in PLATFORMS
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if unload_ok:
|
||||||
|
hass.data[DOMAIN].pop(entry.entry_id)
|
||||||
|
|
||||||
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
|
def setup_input(api: ProgettiHWSWAPI, input_number: int) -> Input:
|
||||||
|
"""Initialize the input pin."""
|
||||||
|
return api.get_input(input_number)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_switch(api: ProgettiHWSWAPI, switch_number: int, mode: str) -> Relay:
|
||||||
|
"""Initialize the output pin."""
|
||||||
|
return api.get_relay(switch_number, mode)
|
95
homeassistant/components/progettihwsw/binary_sensor.py
Normal file
95
homeassistant/components/progettihwsw/binary_sensor.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"""Control binary sensor instances."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from ProgettiHWSW.input import Input
|
||||||
|
import async_timeout
|
||||||
|
|
||||||
|
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
|
from . import setup_input
|
||||||
|
from .const import DEFAULT_POLLING_INTERVAL_SEC, DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
|
"""Set the progettihwsw platform up and create sensor instances (legacy)."""
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
"""Set up the binary sensors from a config entry."""
|
||||||
|
board_api = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
input_count = config_entry.data["input_count"]
|
||||||
|
binary_sensors = []
|
||||||
|
|
||||||
|
async def async_update_data():
|
||||||
|
"""Fetch data from API endpoint of board."""
|
||||||
|
async with async_timeout.timeout(5):
|
||||||
|
return await board_api.get_inputs()
|
||||||
|
|
||||||
|
coordinator = DataUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name="binary_sensor",
|
||||||
|
update_method=async_update_data,
|
||||||
|
update_interval=timedelta(seconds=DEFAULT_POLLING_INTERVAL_SEC),
|
||||||
|
)
|
||||||
|
await coordinator.async_refresh()
|
||||||
|
|
||||||
|
for i in range(1, int(input_count) + 1):
|
||||||
|
binary_sensors.append(
|
||||||
|
ProgettihwswBinarySensor(
|
||||||
|
hass,
|
||||||
|
coordinator,
|
||||||
|
config_entry,
|
||||||
|
f"Input #{i}",
|
||||||
|
setup_input(board_api, i),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(binary_sensors)
|
||||||
|
|
||||||
|
|
||||||
|
class ProgettihwswBinarySensor(BinarySensorEntity):
|
||||||
|
"""Represent a binary sensor."""
|
||||||
|
|
||||||
|
def __init__(self, hass, coordinator, config_entry, name, sensor: Input):
|
||||||
|
"""Set initializing values."""
|
||||||
|
self._name = name
|
||||||
|
self._sensor = sensor
|
||||||
|
self._coordinator = coordinator
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""When entity is added to hass."""
|
||||||
|
self.async_on_remove(
|
||||||
|
self._coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the sensor name."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Get sensor state."""
|
||||||
|
return self._coordinator.data[self._sensor.id]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No need to poll. Coordinator notifies entity of updates."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return if entity is available."""
|
||||||
|
return self._coordinator.last_update_success
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Update the state of binary sensor."""
|
||||||
|
await self._coordinator.async_request_refresh()
|
102
homeassistant/components/progettihwsw/config_flow.py
Normal file
102
homeassistant/components/progettihwsw/config_flow.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
"""Config flow for ProgettiHWSW Automation integration."""
|
||||||
|
|
||||||
|
from ProgettiHWSW.ProgettiHWSWAPI import ProgettiHWSWAPI
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant import config_entries, core, exceptions
|
||||||
|
|
||||||
|
from .const import DOMAIN # pylint: disable=unused-import
|
||||||
|
|
||||||
|
DATA_SCHEMA = vol.Schema(
|
||||||
|
{vol.Required("host"): str, vol.Required("port", default=80): int}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def validate_input(hass: core.HomeAssistant, data):
|
||||||
|
"""Validate the user host input."""
|
||||||
|
|
||||||
|
api_instance = ProgettiHWSWAPI(f'{data["host"]}:{data["port"]}')
|
||||||
|
is_valid = await api_instance.check_board()
|
||||||
|
|
||||||
|
if is_valid is False:
|
||||||
|
raise CannotConnect
|
||||||
|
|
||||||
|
return {
|
||||||
|
"title": is_valid["title"],
|
||||||
|
"relay_count": is_valid["relay_count"],
|
||||||
|
"input_count": is_valid["input_count"],
|
||||||
|
"is_old": is_valid["is_old"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def validate_input_relay_modes(data):
|
||||||
|
"""Validate the user input in relay modes form."""
|
||||||
|
for mode in data.values():
|
||||||
|
if mode not in ("bistable", "monostable"):
|
||||||
|
raise WrongInfo
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ProgettiHWSWConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Handle a config flow for ProgettiHWSW Automation."""
|
||||||
|
|
||||||
|
VERSION = 1
|
||||||
|
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||||
|
|
||||||
|
async def async_step_relay_modes(self, user_input=None):
|
||||||
|
"""Manage relay modes step."""
|
||||||
|
errors = {}
|
||||||
|
if user_input is not None:
|
||||||
|
try:
|
||||||
|
await validate_input_relay_modes(user_input)
|
||||||
|
whole_data = user_input
|
||||||
|
whole_data.update(self.s1_in)
|
||||||
|
except WrongInfo:
|
||||||
|
errors["base"] = "wrong_info_relay_modes"
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
errors["base"] = "unknown"
|
||||||
|
else:
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=whole_data["title"], data=whole_data
|
||||||
|
)
|
||||||
|
|
||||||
|
relay_modes_schema = {}
|
||||||
|
for i in range(1, int(self.s1_in["relay_count"]) + 1):
|
||||||
|
relay_modes_schema[
|
||||||
|
vol.Required(f"relay_{str(i)}", default="bistable")
|
||||||
|
] = str
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="relay_modes",
|
||||||
|
data_schema=vol.Schema(relay_modes_schema),
|
||||||
|
errors=errors,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_step_user(self, user_input=None):
|
||||||
|
"""Handle the initial step."""
|
||||||
|
errors = {}
|
||||||
|
if user_input is not None:
|
||||||
|
try:
|
||||||
|
info = await validate_input(self.hass, user_input)
|
||||||
|
user_input.update(info)
|
||||||
|
self.s1_in = ( # pylint: disable=attribute-defined-outside-init
|
||||||
|
user_input
|
||||||
|
)
|
||||||
|
return await self.async_step_relay_modes()
|
||||||
|
except CannotConnect:
|
||||||
|
errors["base"] = "cannot_connect"
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
errors["base"] = "unknown"
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user", data_schema=DATA_SCHEMA, errors=errors
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CannotConnect(exceptions.HomeAssistantError):
|
||||||
|
"""Error to indicate we cannot identify host."""
|
||||||
|
|
||||||
|
|
||||||
|
class WrongInfo(exceptions.HomeAssistantError):
|
||||||
|
"""Error to indicate we cannot validate relay modes input."""
|
5
homeassistant/components/progettihwsw/const.py
Normal file
5
homeassistant/components/progettihwsw/const.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
"""Define constant variables for general usage."""
|
||||||
|
|
||||||
|
DOMAIN = "progettihwsw"
|
||||||
|
|
||||||
|
DEFAULT_POLLING_INTERVAL_SEC = 5
|
12
homeassistant/components/progettihwsw/manifest.json
Normal file
12
homeassistant/components/progettihwsw/manifest.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"domain": "progettihwsw",
|
||||||
|
"name": "ProgettiHWSW Automation",
|
||||||
|
"documentation": "https://www.home-assistant.io/integrations/progettihwsw",
|
||||||
|
"codeowners": [
|
||||||
|
"@ardaseremet"
|
||||||
|
],
|
||||||
|
"requirements": [
|
||||||
|
"progettihwsw==0.1.1"
|
||||||
|
],
|
||||||
|
"config_flow": true
|
||||||
|
}
|
40
homeassistant/components/progettihwsw/strings.json
Normal file
40
homeassistant/components/progettihwsw/strings.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
|
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||||
|
"wrong_info_relay_modes": "Relay mode selection must be monostable or bistable."
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"title": "Set up board",
|
||||||
|
"data": {
|
||||||
|
"host": "[%key:common::config_flow::data::host%]",
|
||||||
|
"port": "[%key:common::config_flow::data::port%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relay_modes": {
|
||||||
|
"title": "Set up relays",
|
||||||
|
"data": {
|
||||||
|
"relay_1": "Relay 1",
|
||||||
|
"relay_2": "Relay 2",
|
||||||
|
"relay_3": "Relay 3",
|
||||||
|
"relay_4": "Relay 4",
|
||||||
|
"relay_5": "Relay 5",
|
||||||
|
"relay_6": "Relay 6",
|
||||||
|
"relay_7": "Relay 7",
|
||||||
|
"relay_8": "Relay 8",
|
||||||
|
"relay_9": "Relay 9",
|
||||||
|
"relay_10": "Relay 10",
|
||||||
|
"relay_11": "Relay 11",
|
||||||
|
"relay_12": "Relay 12",
|
||||||
|
"relay_13": "Relay 13",
|
||||||
|
"relay_14": "Relay 14",
|
||||||
|
"relay_15": "Relay 15",
|
||||||
|
"relay_16": "Relay 16"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ProgettiHWSW Automation"
|
||||||
|
}
|
109
homeassistant/components/progettihwsw/switch.py
Normal file
109
homeassistant/components/progettihwsw/switch.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
"""Control switches."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from ProgettiHWSW.relay import Relay
|
||||||
|
import async_timeout
|
||||||
|
|
||||||
|
from homeassistant.components.switch import SwitchEntity
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
|
from . import setup_switch
|
||||||
|
from .const import DEFAULT_POLLING_INTERVAL_SEC, DOMAIN
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
|
"""Set the switch platform up (legacy)."""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
|
"""Set up the switches from a config entry."""
|
||||||
|
board_api = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
relay_count = config_entry.data["relay_count"]
|
||||||
|
switches = []
|
||||||
|
|
||||||
|
async def async_update_data():
|
||||||
|
"""Fetch data from API endpoint of board."""
|
||||||
|
async with async_timeout.timeout(5):
|
||||||
|
return await board_api.get_switches()
|
||||||
|
|
||||||
|
coordinator = DataUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name="switch",
|
||||||
|
update_method=async_update_data,
|
||||||
|
update_interval=timedelta(seconds=DEFAULT_POLLING_INTERVAL_SEC),
|
||||||
|
)
|
||||||
|
await coordinator.async_refresh()
|
||||||
|
|
||||||
|
for i in range(1, int(relay_count) + 1):
|
||||||
|
switches.append(
|
||||||
|
ProgettihwswSwitch(
|
||||||
|
hass,
|
||||||
|
coordinator,
|
||||||
|
config_entry,
|
||||||
|
f"Relay #{i}",
|
||||||
|
setup_switch(board_api, i, config_entry.data[f"relay_{str(i)}"]),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(switches)
|
||||||
|
|
||||||
|
|
||||||
|
class ProgettihwswSwitch(SwitchEntity):
|
||||||
|
"""Represent a switch entity."""
|
||||||
|
|
||||||
|
def __init__(self, hass, coordinator, config_entry, name, switch: Relay):
|
||||||
|
"""Initialize the values."""
|
||||||
|
self._switch = switch
|
||||||
|
self._name = name
|
||||||
|
self._coordinator = coordinator
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""When entity is added to hass."""
|
||||||
|
self.async_on_remove(
|
||||||
|
self._coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs):
|
||||||
|
"""Turn the switch on."""
|
||||||
|
await self._switch.control(True)
|
||||||
|
await self._coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs):
|
||||||
|
"""Turn the switch off."""
|
||||||
|
await self._switch.control(False)
|
||||||
|
await self._coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
async def async_toggle(self, **kwargs):
|
||||||
|
"""Toggle the state of switch."""
|
||||||
|
await self._switch.toggle()
|
||||||
|
await self._coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the switch name."""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self):
|
||||||
|
"""Get switch state."""
|
||||||
|
return self._coordinator.data[self._switch.id]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No need to poll. Coordinator notifies entity of updates."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return if entity is available."""
|
||||||
|
return self._coordinator.last_update_success
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Update the state of switch."""
|
||||||
|
await self._coordinator.async_request_refresh()
|
40
homeassistant/components/progettihwsw/translations/en.json
Normal file
40
homeassistant/components/progettihwsw/translations/en.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"error": {
|
||||||
|
"cannot_connect": "Cannot connect to the board.",
|
||||||
|
"unknown": "Unknown error.",
|
||||||
|
"wrong_info_relay_modes": "Relay mode selection must be monostable or bistable."
|
||||||
|
},
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"title": "Set up board",
|
||||||
|
"data": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port Number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relay_modes": {
|
||||||
|
"title": "Set up relays",
|
||||||
|
"data": {
|
||||||
|
"relay_1": "Relay 1",
|
||||||
|
"relay_2": "Relay 2",
|
||||||
|
"relay_3": "Relay 3",
|
||||||
|
"relay_4": "Relay 4",
|
||||||
|
"relay_5": "Relay 5",
|
||||||
|
"relay_6": "Relay 6",
|
||||||
|
"relay_7": "Relay 7",
|
||||||
|
"relay_8": "Relay 8",
|
||||||
|
"relay_9": "Relay 9",
|
||||||
|
"relay_10": "Relay 10",
|
||||||
|
"relay_11": "Relay 11",
|
||||||
|
"relay_12": "Relay 12",
|
||||||
|
"relay_13": "Relay 13",
|
||||||
|
"relay_14": "Relay 14",
|
||||||
|
"relay_15": "Relay 15",
|
||||||
|
"relay_16": "Relay 16"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "ProgettiHWSW Automation"
|
||||||
|
}
|
@ -140,6 +140,7 @@ FLOWS = [
|
|||||||
"point",
|
"point",
|
||||||
"poolsense",
|
"poolsense",
|
||||||
"powerwall",
|
"powerwall",
|
||||||
|
"progettihwsw",
|
||||||
"ps4",
|
"ps4",
|
||||||
"pvpc_hourly_pricing",
|
"pvpc_hourly_pricing",
|
||||||
"rachio",
|
"rachio",
|
||||||
|
@ -1115,6 +1115,9 @@ praw==7.1.0
|
|||||||
# homeassistant.components.islamic_prayer_times
|
# homeassistant.components.islamic_prayer_times
|
||||||
prayer_times_calculator==0.0.3
|
prayer_times_calculator==0.0.3
|
||||||
|
|
||||||
|
# homeassistant.components.progettihwsw
|
||||||
|
progettihwsw==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.proliphix
|
# homeassistant.components.proliphix
|
||||||
proliphix==0.4.1
|
proliphix==0.4.1
|
||||||
|
|
||||||
|
@ -539,6 +539,9 @@ praw==7.1.0
|
|||||||
# homeassistant.components.islamic_prayer_times
|
# homeassistant.components.islamic_prayer_times
|
||||||
prayer_times_calculator==0.0.3
|
prayer_times_calculator==0.0.3
|
||||||
|
|
||||||
|
# homeassistant.components.progettihwsw
|
||||||
|
progettihwsw==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.prometheus
|
# homeassistant.components.prometheus
|
||||||
prometheus_client==0.7.1
|
prometheus_client==0.7.1
|
||||||
|
|
||||||
|
1
tests/components/progettihwsw/__init__.py
Normal file
1
tests/components/progettihwsw/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Tests for the ProgettiHWSW Automation integration."""
|
168
tests/components/progettihwsw/test_config_flow.py
Normal file
168
tests/components/progettihwsw/test_config_flow.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
"""Test the ProgettiHWSW Automation config flow."""
|
||||||
|
from homeassistant import config_entries, setup
|
||||||
|
from homeassistant.components.progettihwsw.const import DOMAIN
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||||
|
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM
|
||||||
|
|
||||||
|
from tests.async_mock import patch
|
||||||
|
|
||||||
|
mock_value_step_user = {
|
||||||
|
"title": "1R & 1IN Board",
|
||||||
|
"relay_count": 1,
|
||||||
|
"input_count": 1,
|
||||||
|
"is_old": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form(hass):
|
||||||
|
"""Test we get the form."""
|
||||||
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
assert result["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
assert result["errors"] == {}
|
||||||
|
|
||||||
|
mock_value_step_rm = {
|
||||||
|
"relay_1": "bistable", # Mocking a single relay board instance.
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.ProgettiHWSWAPI.check_board",
|
||||||
|
return_value=mock_value_step_user,
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "", CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["step_id"] == "relay_modes"
|
||||||
|
assert result2["errors"] == {}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.async_setup",
|
||||||
|
return_value=True,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.progettihwsw.async_setup_entry",
|
||||||
|
return_value=True,
|
||||||
|
):
|
||||||
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
|
result2["flow_id"],
|
||||||
|
mock_value_step_rm,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result3["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||||
|
assert result3["data"]
|
||||||
|
assert result3["data"]["title"] == "1R & 1IN Board"
|
||||||
|
assert result3["data"]["is_old"] is False
|
||||||
|
assert result3["data"]["relay_count"] == result3["data"]["input_count"] == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_wrong_info(hass):
|
||||||
|
"""Test we handle wrong info exception."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.ProgettiHWSWAPI.check_board",
|
||||||
|
return_value=mock_value_step_user,
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"], {CONF_HOST: "", CONF_PORT: 80}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["step_id"] == "relay_modes"
|
||||||
|
assert result2["errors"] == {}
|
||||||
|
|
||||||
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
|
result2["flow_id"], {"relay_1": ""}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result3["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result3["step_id"] == "relay_modes"
|
||||||
|
assert result3["errors"] == {"base": "wrong_info_relay_modes"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_cannot_connect(hass):
|
||||||
|
"""Test we handle unexisting board."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.ProgettiHWSWAPI.check_board",
|
||||||
|
return_value=False,
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "", CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["step_id"] == "user"
|
||||||
|
assert result2["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_user_exception(hass):
|
||||||
|
"""Test we handle unknown exception."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.validate_input",
|
||||||
|
side_effect=Exception,
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "", CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["step_id"] == "user"
|
||||||
|
assert result2["errors"] == {"base": "unknown"}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_form_rm_exception(hass):
|
||||||
|
"""Test we handle unknown exception on seconds step."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.ProgettiHWSWAPI.check_board",
|
||||||
|
return_value=mock_value_step_user,
|
||||||
|
):
|
||||||
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "", CONF_PORT: 80},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result2["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result2["step_id"] == "relay_modes"
|
||||||
|
assert result2["errors"] == {}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.progettihwsw.config_flow.validate_input_relay_modes",
|
||||||
|
side_effect=Exception,
|
||||||
|
):
|
||||||
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
|
result2["flow_id"],
|
||||||
|
{"relay_1": "bistable"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result3["type"] == RESULT_TYPE_FORM
|
||||||
|
assert result3["step_id"] == "relay_modes"
|
||||||
|
assert result3["errors"] == {"base": "unknown"}
|
Loading…
x
Reference in New Issue
Block a user