Improve Smappee integration (#37087)
parent
fe5bf96e5d
commit
680f8f8d5a
homeassistant/components/smappee
tests/components/smappee
|
@ -5,7 +5,7 @@ from pysmappee import Smappee
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_PLATFORM
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv
|
||||
from homeassistant.util import Throttle
|
||||
|
@ -40,6 +40,15 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
|||
if DOMAIN not in config:
|
||||
return True
|
||||
|
||||
# decide platform
|
||||
platform = "PRODUCTION"
|
||||
if config[DOMAIN][CONF_CLIENT_ID] == "homeassistant_f2":
|
||||
platform = "ACCEPTANCE"
|
||||
elif config[DOMAIN][CONF_CLIENT_ID] == "homeassistant_f3":
|
||||
platform = "DEVELOPMENT"
|
||||
|
||||
hass.data[DOMAIN][CONF_PLATFORM] = platform
|
||||
|
||||
config_flow.SmappeeFlowHandler.async_register_implementation(
|
||||
hass,
|
||||
config_entry_oauth2_flow.LocalOAuth2Implementation(
|
||||
|
@ -47,8 +56,8 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
|||
DOMAIN,
|
||||
config[DOMAIN][CONF_CLIENT_ID],
|
||||
config[DOMAIN][CONF_CLIENT_SECRET],
|
||||
AUTHORIZE_URL,
|
||||
TOKEN_URL,
|
||||
AUTHORIZE_URL[platform],
|
||||
TOKEN_URL[platform],
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -89,6 +98,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(BASE, None)
|
||||
hass.data[DOMAIN].pop(CONF_PLATFORM, None)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
|
|
@ -4,8 +4,11 @@ from asyncio import run_coroutine_threadsafe
|
|||
from pysmappee import api
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
from homeassistant.helpers import config_entry_oauth2_flow
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
|
||||
class ConfigEntrySmappeeApi(api.SmappeeApi):
|
||||
"""Provide Smappee authentication tied to an OAuth2 based config entry."""
|
||||
|
@ -22,7 +25,18 @@ class ConfigEntrySmappeeApi(api.SmappeeApi):
|
|||
self.session = config_entry_oauth2_flow.OAuth2Session(
|
||||
hass, config_entry, implementation
|
||||
)
|
||||
super().__init__(None, None, token=self.session.token)
|
||||
|
||||
platform_to_farm = {
|
||||
"PRODUCTION": 1,
|
||||
"ACCEPTANCE": 2,
|
||||
"DEVELOPMENT": 3,
|
||||
}
|
||||
super().__init__(
|
||||
None,
|
||||
None,
|
||||
token=self.session.token,
|
||||
farm=platform_to_farm[hass.data[DOMAIN][CONF_PLATFORM]],
|
||||
)
|
||||
|
||||
def refresh_tokens(self) -> dict:
|
||||
"""Refresh and return new Smappee tokens using Home Assistant OAuth2 session."""
|
||||
|
|
|
@ -139,12 +139,6 @@ class SmappeeAppliance(BinarySensorEntity):
|
|||
}
|
||||
return icon_mapping.get(self._appliance_type)
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||
# Only lights can be mapped onto the generic list of binary sensors
|
||||
return "light" if self._appliance_type == "Lights" else "power"
|
||||
|
||||
@property
|
||||
def unique_id(self,):
|
||||
"""Return the unique ID for this binary sensor."""
|
||||
|
|
|
@ -21,10 +21,3 @@ class SmappeeFlowHandler(
|
|||
def logger(self) -> logging.Logger:
|
||||
"""Return logger."""
|
||||
return logging.getLogger(__name__)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a flow start."""
|
||||
if self.hass.config_entries.async_entries(DOMAIN):
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
return await super().async_step_user(user_input)
|
||||
|
|
|
@ -11,5 +11,13 @@ SMAPPEE_PLATFORMS = ["binary_sensor", "sensor", "switch"]
|
|||
|
||||
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=5)
|
||||
|
||||
AUTHORIZE_URL = "https://app1pub.smappee.net/dev/v1/oauth2/authorize"
|
||||
TOKEN_URL = "https://app1pub.smappee.net/dev/v3/oauth2/token"
|
||||
AUTHORIZE_URL = {
|
||||
"PRODUCTION": "https://app1pub.smappee.net/dev/v1/oauth2/authorize",
|
||||
"ACCEPTANCE": "https://farm2pub.smappee.net/dev/v1/oauth2/authorize",
|
||||
"DEVELOPMENT": "https://farm3pub.smappee.net/dev/v1/oauth2/authorize",
|
||||
}
|
||||
TOKEN_URL = {
|
||||
"PRODUCTION": "https://app1pub.smappee.net/dev/v3/oauth2/token",
|
||||
"ACCEPTANCE": "https://farm2pub.smappee.net/dev/v3/oauth2/token",
|
||||
"DEVELOPMENT": "https://farm3pub.smappee.net/dev/v3/oauth2/token",
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
},
|
||||
"abort": {
|
||||
"authorize_url_timeout": "Timeout generating authorize url.",
|
||||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"missing_configuration": "The component is not configured. Please follow the documentation."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,15 @@
|
|||
"""Test the Smappee config flow."""
|
||||
from homeassistant import config_entries, data_entry_flow, setup
|
||||
from homeassistant import config_entries, setup
|
||||
from homeassistant.components.smappee.const import AUTHORIZE_URL, DOMAIN, TOKEN_URL
|
||||
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET
|
||||
from homeassistant.helpers import config_entry_oauth2_flow
|
||||
|
||||
from tests.async_mock import patch
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
CLIENT_ID = "1234"
|
||||
CLIENT_SECRET = "5678"
|
||||
|
||||
|
||||
async def test_abort_if_existing_entry(hass):
|
||||
"""Check flow abort when an entry already exist."""
|
||||
MockConfigEntry(domain=DOMAIN).add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_full_flow(hass, aiohttp_client, aioclient_mock):
|
||||
"""Check full flow."""
|
||||
assert await setup.async_setup_component(
|
||||
|
@ -39,7 +27,7 @@ async def test_full_flow(hass, aiohttp_client, aioclient_mock):
|
|||
state = config_entry_oauth2_flow._encode_jwt(hass, {"flow_id": result["flow_id"]})
|
||||
|
||||
assert result["url"] == (
|
||||
f"{AUTHORIZE_URL}?response_type=code&client_id={CLIENT_ID}"
|
||||
f"{AUTHORIZE_URL['PRODUCTION']}?response_type=code&client_id={CLIENT_ID}"
|
||||
"&redirect_uri=https://example.com/auth/external/callback"
|
||||
f"&state={state}"
|
||||
)
|
||||
|
@ -50,7 +38,7 @@ async def test_full_flow(hass, aiohttp_client, aioclient_mock):
|
|||
assert resp.headers["content-type"] == "text/html; charset=utf-8"
|
||||
|
||||
aioclient_mock.post(
|
||||
TOKEN_URL,
|
||||
TOKEN_URL["PRODUCTION"],
|
||||
json={
|
||||
"refresh_token": "mock-refresh-token",
|
||||
"access_token": "mock-access-token",
|
||||
|
|
Loading…
Reference in New Issue