Add Solar-Log platform (#27036)
* Add Solar-Log sensor * Codeowners update * Update homeassistant/components/solarlog/manifest.json Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * remove sunwatcher from gen_requirements_all.py * remove sunwatcher from requirements_test_all.txt * Remove scan_interval as configuration variable I've set it to a fixed scan_interval of 1 minute. Removed the configuration option. * Fix black format * Config flow added (__init__.py) * Config flow added (manifest.json) * Config flow added (const.py) * Config flow added (config_flow.py) * Config flow added (strings.json) * Config flow added (en.json translation) * Config flow added (sensor.py rewritten) * Config flow added (sensor.py) * Config flow added (config_flows.py) * resolve conflict config_flows.py * Add tests * add tests * add tests * Update .coverage to include all files for solarlog * Fix await the unload * Adjust icons, add http:// to default host * Change icons * Add http:// to host if not provided, fix await * Add http:// to host if not provided, fix await * Adjust tests for http:// added to host * remove line * Remove without http:// requirement * Remove without http;// requirement
This commit is contained in:
parent
b27dc5bd39
commit
acc3646ef3
14 changed files with 572 additions and 0 deletions
|
@ -620,6 +620,7 @@ omit =
|
|||
homeassistant/components/solaredge/__init__.py
|
||||
homeassistant/components/solaredge/sensor.py
|
||||
homeassistant/components/solaredge_local/sensor.py
|
||||
homeassistant/components/solarlog/*
|
||||
homeassistant/components/solax/sensor.py
|
||||
homeassistant/components/soma/cover.py
|
||||
homeassistant/components/soma/__init__.py
|
||||
|
|
|
@ -265,6 +265,7 @@ homeassistant/components/smartthings/* @andrewsayre
|
|||
homeassistant/components/smarty/* @z0mbieprocess
|
||||
homeassistant/components/smtp/* @fabaff
|
||||
homeassistant/components/solaredge_local/* @drobtravels @scheric
|
||||
homeassistant/components/solarlog/* @Ernst79
|
||||
homeassistant/components/solax/* @squishykid
|
||||
homeassistant/components/soma/* @ratsept
|
||||
homeassistant/components/somfy/* @tetienne
|
||||
|
|
21
homeassistant/components/solarlog/.translations/en.json
Normal file
21
homeassistant/components/solarlog/.translations/en.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "Solar-Log",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Define your Solar-Log connection",
|
||||
"data": {
|
||||
"host": "The hostname or ip-address of your Solar-Log device",
|
||||
"name": "The prefix to be used for your Solar-Log sensors"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"already_configured": "Device is already configured",
|
||||
"cannot_connect": "Failed to connect, please verify host address"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
}
|
||||
}
|
||||
}
|
21
homeassistant/components/solarlog/__init__.py
Normal file
21
homeassistant/components/solarlog/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
"""Solar-Log integration."""
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Component setup, do nothing."""
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
||||
"""Set up a config entry for solarlog."""
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, "sensor")
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass, entry):
|
||||
"""Unload a config entry."""
|
||||
return await hass.config_entries.async_forward_entry_unload(entry, "sensor")
|
107
homeassistant/components/solarlog/config_flow.py
Normal file
107
homeassistant/components/solarlog/config_flow.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
"""Config flow for solarlog integration."""
|
||||
import logging
|
||||
from urllib.parse import ParseResult, urlparse
|
||||
|
||||
from requests.exceptions import HTTPError, Timeout
|
||||
from sunwatcher.solarlog.solarlog import SolarLog
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import DEFAULT_HOST, DEFAULT_NAME, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@callback
|
||||
def solarlog_entries(hass: HomeAssistant):
|
||||
"""Return the hosts already configured."""
|
||||
return set(
|
||||
entry.data[CONF_HOST] for entry in hass.config_entries.async_entries(DOMAIN)
|
||||
)
|
||||
|
||||
|
||||
class SolarLogConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for solarlog."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the config flow."""
|
||||
self._errors = {}
|
||||
|
||||
def _host_in_configuration_exists(self, host) -> bool:
|
||||
"""Return True if host exists in configuration."""
|
||||
if host in solarlog_entries(self.hass):
|
||||
return True
|
||||
return False
|
||||
|
||||
async def _test_connection(self, host):
|
||||
"""Check if we can connect to the Solar-Log device."""
|
||||
try:
|
||||
await self.hass.async_add_executor_job(SolarLog, host)
|
||||
return True
|
||||
except (OSError, HTTPError, Timeout):
|
||||
self._errors[CONF_HOST] = "cannot_connect"
|
||||
_LOGGER.error(
|
||||
"Could not connect to Solar-Log device at %s, check host ip address",
|
||||
host,
|
||||
)
|
||||
return False
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Step when user intializes a integration."""
|
||||
self._errors = {}
|
||||
if user_input is not None:
|
||||
# set some defaults in case we need to return to the form
|
||||
name = slugify(user_input.get(CONF_NAME, DEFAULT_NAME))
|
||||
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
|
||||
url = urlparse(host_entry, "http")
|
||||
netloc = url.netloc or url.path
|
||||
path = url.path if url.netloc else ""
|
||||
url = ParseResult("http", netloc, path, *url[3:])
|
||||
host = url.geturl()
|
||||
|
||||
if self._host_in_configuration_exists(host):
|
||||
self._errors[CONF_HOST] = "already_configured"
|
||||
else:
|
||||
if await self._test_connection(host):
|
||||
return self.async_create_entry(title=name, data={CONF_HOST: host})
|
||||
else:
|
||||
user_input = {}
|
||||
user_input[CONF_NAME] = DEFAULT_NAME
|
||||
user_input[CONF_HOST] = DEFAULT_HOST
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_NAME, default=user_input.get(CONF_NAME, DEFAULT_NAME)
|
||||
): str,
|
||||
vol.Required(
|
||||
CONF_HOST, default=user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
): str,
|
||||
}
|
||||
),
|
||||
errors=self._errors,
|
||||
)
|
||||
|
||||
async def async_step_import(self, user_input=None):
|
||||
"""Import a config entry."""
|
||||
host_entry = user_input.get(CONF_HOST, DEFAULT_HOST)
|
||||
|
||||
url = urlparse(host_entry, "http")
|
||||
netloc = url.netloc or url.path
|
||||
path = url.path if url.netloc else ""
|
||||
url = ParseResult("http", netloc, path, *url[3:])
|
||||
host = url.geturl()
|
||||
|
||||
if self._host_in_configuration_exists(host):
|
||||
return self.async_abort(reason="already_configured")
|
||||
return await self.async_step_user(user_input)
|
89
homeassistant/components/solarlog/const.py
Normal file
89
homeassistant/components/solarlog/const.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
"""Constants for the Solar-Log integration."""
|
||||
from datetime import timedelta
|
||||
|
||||
from homeassistant.const import POWER_WATT, ENERGY_KILO_WATT_HOUR
|
||||
|
||||
DOMAIN = "solarlog"
|
||||
|
||||
"""Default config for solarlog."""
|
||||
DEFAULT_HOST = "http://solar-log"
|
||||
DEFAULT_NAME = "solarlog"
|
||||
|
||||
"""Fixed constants."""
|
||||
SCAN_INTERVAL = timedelta(seconds=60)
|
||||
|
||||
"""Supported sensor types."""
|
||||
SENSOR_TYPES = {
|
||||
"time": ["TIME", "last update", None, "mdi:calendar-clock"],
|
||||
"power_ac": ["powerAC", "power AC", POWER_WATT, "mdi:solar-power"],
|
||||
"power_dc": ["powerDC", "power DC", POWER_WATT, "mdi:solar-power"],
|
||||
"voltage_ac": ["voltageAC", "voltage AC", "V", "mdi:flash"],
|
||||
"voltage_dc": ["voltageDC", "voltage DC", "V", "mdi:flash"],
|
||||
"yield_day": ["yieldDAY", "yield day", ENERGY_KILO_WATT_HOUR, "mdi:solar-power"],
|
||||
"yield_yesterday": [
|
||||
"yieldYESTERDAY",
|
||||
"yield yesterday",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:solar-power",
|
||||
],
|
||||
"yield_month": [
|
||||
"yieldMONTH",
|
||||
"yield month",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:solar-power",
|
||||
],
|
||||
"yield_year": ["yieldYEAR", "yield year", ENERGY_KILO_WATT_HOUR, "mdi:solar-power"],
|
||||
"yield_total": [
|
||||
"yieldTOTAL",
|
||||
"yield total",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:solar-power",
|
||||
],
|
||||
"consumption_ac": ["consumptionAC", "consumption AC", POWER_WATT, "mdi:power-plug"],
|
||||
"consumption_day": [
|
||||
"consumptionDAY",
|
||||
"consumption day",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:power-plug",
|
||||
],
|
||||
"consumption_yesterday": [
|
||||
"consumptionYESTERDAY",
|
||||
"consumption yesterday",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:power-plug",
|
||||
],
|
||||
"consumption_month": [
|
||||
"consumptionMONTH",
|
||||
"consumption month",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:power-plug",
|
||||
],
|
||||
"consumption_year": [
|
||||
"consumptionYEAR",
|
||||
"consumption year",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:power-plug",
|
||||
],
|
||||
"consumption_total": [
|
||||
"consumptionTOTAL",
|
||||
"consumption total",
|
||||
ENERGY_KILO_WATT_HOUR,
|
||||
"mdi:power-plug",
|
||||
],
|
||||
"total_power": ["totalPOWER", "total power", "Wp", "mdi:solar-power"],
|
||||
"alternator_loss": [
|
||||
"alternatorLOSS",
|
||||
"alternator loss",
|
||||
POWER_WATT,
|
||||
"mdi:solar-power",
|
||||
],
|
||||
"capacity": ["CAPACITY", "capacity", "%", "mdi:solar-power"],
|
||||
"efficiency": ["EFFICIENCY", "efficiency", "% W/Wp", "mdi:solar-power"],
|
||||
"power_available": [
|
||||
"powerAVAILABLE",
|
||||
"power available",
|
||||
POWER_WATT,
|
||||
"mdi:solar-power",
|
||||
],
|
||||
"usage": ["USAGE", "usage", None, "mdi:solar-power"],
|
||||
}
|
9
homeassistant/components/solarlog/manifest.json
Normal file
9
homeassistant/components/solarlog/manifest.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"domain": "solarlog",
|
||||
"name": "Solar-Log",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integration/solarlog",
|
||||
"dependencies": [],
|
||||
"codeowners": ["@Ernst79"],
|
||||
"requirements": ["sunwatcher==0.2.1"]
|
||||
}
|
159
homeassistant/components/solarlog/sensor.py
Normal file
159
homeassistant/components/solarlog/sensor.py
Normal file
|
@ -0,0 +1,159 @@
|
|||
"""Platform for solarlog sensors."""
|
||||
import logging
|
||||
from urllib.parse import ParseResult, urlparse
|
||||
|
||||
from requests.exceptions import HTTPError, Timeout
|
||||
from sunwatcher.solarlog.solarlog import SolarLog
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.config_entries import SOURCE_IMPORT
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from .const import DOMAIN, DEFAULT_HOST, DEFAULT_NAME, SCAN_INTERVAL, SENSOR_TYPES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||
"""Import YAML configuration when available."""
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=dict(config)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry, async_add_entities):
|
||||
"""Add solarlog entry."""
|
||||
host_entry = entry.data[CONF_HOST]
|
||||
|
||||
url = urlparse(host_entry, "http")
|
||||
netloc = url.netloc or url.path
|
||||
path = url.path if url.netloc else ""
|
||||
url = ParseResult("http", netloc, path, *url[3:])
|
||||
host = url.geturl()
|
||||
|
||||
platform_name = entry.title
|
||||
|
||||
try:
|
||||
api = await hass.async_add_executor_job(SolarLog, host)
|
||||
_LOGGER.debug("Connected to Solar-Log device, setting up entries")
|
||||
except (OSError, HTTPError, Timeout):
|
||||
_LOGGER.error(
|
||||
"Could not connect to Solar-Log device at %s, check host ip address", host
|
||||
)
|
||||
return
|
||||
|
||||
# Create solarlog data service which will retrieve and update the data.
|
||||
data = await hass.async_add_executor_job(SolarlogData, hass, api, host)
|
||||
|
||||
# Create a new sensor for each sensor type.
|
||||
entities = []
|
||||
for sensor_key in SENSOR_TYPES:
|
||||
sensor = SolarlogSensor(platform_name, sensor_key, data)
|
||||
entities.append(sensor)
|
||||
|
||||
async_add_entities(entities, True)
|
||||
return True
|
||||
|
||||
|
||||
class SolarlogSensor(Entity):
|
||||
"""Representation of a Sensor."""
|
||||
|
||||
def __init__(self, platform_name, sensor_key, data):
|
||||
"""Initialize the sensor."""
|
||||
self.platform_name = platform_name
|
||||
self.sensor_key = sensor_key
|
||||
self.data = data
|
||||
self._state = None
|
||||
|
||||
self._json_key = SENSOR_TYPES[self.sensor_key][0]
|
||||
self._unit_of_measurement = SENSOR_TYPES[self.sensor_key][2]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return "{} ({})".format(self.platform_name, SENSOR_TYPES[self.sensor_key][1])
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the sensor icon."""
|
||||
return SENSOR_TYPES[self.sensor_key][3]
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
def update(self):
|
||||
"""Get the latest data from the sensor and update the state."""
|
||||
self.data.update()
|
||||
self._state = self.data.data[self._json_key]
|
||||
|
||||
|
||||
class SolarlogData:
|
||||
"""Get and update the latest data."""
|
||||
|
||||
def __init__(self, hass, api, host):
|
||||
"""Initialize the data object."""
|
||||
self.api = api
|
||||
self.hass = hass
|
||||
self.host = host
|
||||
self.update = Throttle(SCAN_INTERVAL)(self._update)
|
||||
self.data = {}
|
||||
|
||||
def _update(self):
|
||||
"""Update the data from the SolarLog device."""
|
||||
try:
|
||||
self.api = SolarLog(self.host)
|
||||
response = self.api.time
|
||||
_LOGGER.debug(
|
||||
"Connection to Solarlog successful. Retrieving latest Solarlog update of %s",
|
||||
response,
|
||||
)
|
||||
except (OSError, Timeout, HTTPError):
|
||||
_LOGGER.error("Connection error, Could not retrieve data, skipping update")
|
||||
return
|
||||
|
||||
try:
|
||||
self.data["TIME"] = self.api.time
|
||||
self.data["powerAC"] = self.api.power_ac
|
||||
self.data["powerDC"] = self.api.power_dc
|
||||
self.data["voltageAC"] = self.api.voltage_ac
|
||||
self.data["voltageDC"] = self.api.voltage_dc
|
||||
self.data["yieldDAY"] = self.api.yield_day / 1000
|
||||
self.data["yieldYESTERDAY"] = self.api.yield_yesterday / 1000
|
||||
self.data["yieldMONTH"] = self.api.yield_month / 1000
|
||||
self.data["yieldYEAR"] = self.api.yield_year / 1000
|
||||
self.data["yieldTOTAL"] = self.api.yield_total / 1000
|
||||
self.data["consumptionAC"] = self.api.consumption_ac
|
||||
self.data["consumptionDAY"] = self.api.consumption_day / 1000
|
||||
self.data["consumptionYESTERDAY"] = self.api.consumption_yesterday / 1000
|
||||
self.data["consumptionMONTH"] = self.api.consumption_month / 1000
|
||||
self.data["consumptionYEAR"] = self.api.consumption_year / 1000
|
||||
self.data["consumptionTOTAL"] = self.api.consumption_total / 1000
|
||||
self.data["totalPOWER"] = self.api.total_power
|
||||
self.data["alternatorLOSS"] = self.api.alternator_loss
|
||||
self.data["CAPACITY"] = round(self.api.capacity * 100, 0)
|
||||
self.data["EFFICIENCY"] = round(self.api.efficiency * 100, 0)
|
||||
self.data["powerAVAILABLE"] = self.api.power_available
|
||||
self.data["USAGE"] = self.api.usage
|
||||
_LOGGER.debug("Updated Solarlog overview data: %s", self.data)
|
||||
except AttributeError:
|
||||
_LOGGER.error("Missing details data in Solarlog response")
|
21
homeassistant/components/solarlog/strings.json
Normal file
21
homeassistant/components/solarlog/strings.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "Solar-Log",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Define your Solar-Log connection",
|
||||
"data": {
|
||||
"host": "The hostname or ip-address of your Solar-Log device",
|
||||
"name": "The prefix to be used for your Solar-Log sensors"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"already_configured": "Device is already configured",
|
||||
"cannot_connect": "Failed to connect, please verify host address"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@ FLOWS = [
|
|||
"smartthings",
|
||||
"smhi",
|
||||
"solaredge",
|
||||
"solarlog",
|
||||
"soma",
|
||||
"somfy",
|
||||
"sonos",
|
||||
|
|
|
@ -1842,6 +1842,9 @@ stringcase==1.2.0
|
|||
# homeassistant.components.ecovacs
|
||||
sucks==0.9.4
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
sunwatcher==0.2.1
|
||||
|
||||
# homeassistant.components.swiss_hydrological_data
|
||||
swisshydrodata==0.0.3
|
||||
|
||||
|
|
|
@ -583,6 +583,9 @@ statsd==3.2.1
|
|||
# homeassistant.components.traccar
|
||||
stringcase==1.2.0
|
||||
|
||||
# homeassistant.components.solarlog
|
||||
sunwatcher==0.2.1
|
||||
|
||||
# homeassistant.components.tellduslive
|
||||
tellduslive==0.10.10
|
||||
|
||||
|
|
1
tests/components/solarlog/__init__.py
Normal file
1
tests/components/solarlog/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
"""Tests for the solarlog integration."""
|
135
tests/components/solarlog/test_config_flow.py
Normal file
135
tests/components/solarlog/test_config_flow.py
Normal file
|
@ -0,0 +1,135 @@
|
|||
"""Test the solarlog config flow."""
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.solarlog import config_flow
|
||||
from homeassistant.components.solarlog.const import DEFAULT_HOST, DOMAIN
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME
|
||||
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
|
||||
NAME = "Solarlog test 1 2 3"
|
||||
HOST = "http://1.1.1.1"
|
||||
|
||||
|
||||
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"] == "form"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection",
|
||||
return_value=mock_coro({"title": "solarlog test 1 2 3"}),
|
||||
), patch(
|
||||
"homeassistant.components.solarlog.async_setup", return_value=mock_coro(True)
|
||||
) as mock_setup, patch(
|
||||
"homeassistant.components.solarlog.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
) as mock_setup_entry:
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], {"host": HOST, "name": NAME}
|
||||
)
|
||||
|
||||
assert result2["type"] == "create_entry"
|
||||
assert result2["title"] == "solarlog_test_1_2_3"
|
||||
assert result2["data"] == {"host": "http://1.1.1.1"}
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
assert len(mock_setup_entry.mock_calls) == 1
|
||||
|
||||
|
||||
@pytest.fixture(name="test_connect")
|
||||
def mock_controller():
|
||||
"""Mock a successfull _host_in_configuration_exists."""
|
||||
with patch(
|
||||
"homeassistant.components.solarlog.config_flow.SolarLogConfigFlow._test_connection",
|
||||
side_effect=lambda *_: mock_coro(True),
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def init_config_flow(hass):
|
||||
"""Init a configuration flow."""
|
||||
flow = config_flow.SolarLogConfigFlow()
|
||||
flow.hass = hass
|
||||
return flow
|
||||
|
||||
|
||||
async def test_user(hass, test_connect):
|
||||
"""Test user config."""
|
||||
flow = init_config_flow(hass)
|
||||
|
||||
result = await flow.async_step_user()
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
# tets with all provided
|
||||
result = await flow.async_step_user({CONF_NAME: NAME, CONF_HOST: HOST})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
|
||||
|
||||
async def test_import(hass, test_connect):
|
||||
"""Test import step."""
|
||||
flow = init_config_flow(hass)
|
||||
|
||||
# import with only host
|
||||
result = await flow.async_step_import({CONF_HOST: HOST})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog"
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
|
||||
# import with only name
|
||||
result = await flow.async_step_import({CONF_NAME: NAME})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == DEFAULT_HOST
|
||||
|
||||
# import with host and name
|
||||
result = await flow.async_step_import({CONF_HOST: HOST, CONF_NAME: NAME})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == HOST
|
||||
|
||||
|
||||
async def test_abort_if_already_setup(hass, test_connect):
|
||||
"""Test we abort if the device is already setup."""
|
||||
flow = init_config_flow(hass)
|
||||
MockConfigEntry(
|
||||
domain="solarlog", data={CONF_NAME: NAME, CONF_HOST: HOST}
|
||||
).add_to_hass(hass)
|
||||
|
||||
# Should fail, same HOST different NAME (default)
|
||||
result = await flow.async_step_import(
|
||||
{CONF_HOST: HOST, CONF_NAME: "solarlog_test_7_8_9"}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
# Should fail, same HOST and NAME
|
||||
result = await flow.async_step_user({CONF_HOST: HOST, CONF_NAME: NAME})
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["errors"] == {CONF_HOST: "already_configured"}
|
||||
|
||||
# SHOULD pass, diff HOST (without http://), different NAME
|
||||
result = await flow.async_step_import(
|
||||
{CONF_HOST: "2.2.2.2", CONF_NAME: "solarlog_test_7_8_9"}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog_test_7_8_9"
|
||||
assert result["data"][CONF_HOST] == "http://2.2.2.2"
|
||||
|
||||
# SHOULD pass, diff HOST, same NAME
|
||||
result = await flow.async_step_import(
|
||||
{CONF_HOST: "http://2.2.2.2", CONF_NAME: NAME}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "solarlog_test_1_2_3"
|
||||
assert result["data"][CONF_HOST] == "http://2.2.2.2"
|
Loading…
Add table
Reference in a new issue