mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Allow separate URL for REST switch state (#39557)
This commit is contained in:
parent
ebc31c0f08
commit
f01a0f9151
@ -30,6 +30,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
CONF_BODY_OFF = "body_off"
|
CONF_BODY_OFF = "body_off"
|
||||||
CONF_BODY_ON = "body_on"
|
CONF_BODY_ON = "body_on"
|
||||||
CONF_IS_ON_TEMPLATE = "is_on_template"
|
CONF_IS_ON_TEMPLATE = "is_on_template"
|
||||||
|
CONF_STATE_RESOURCE = "state_resource"
|
||||||
|
|
||||||
DEFAULT_METHOD = "post"
|
DEFAULT_METHOD = "post"
|
||||||
DEFAULT_BODY_OFF = "OFF"
|
DEFAULT_BODY_OFF = "OFF"
|
||||||
@ -43,6 +44,7 @@ SUPPORT_REST_METHODS = ["post", "put"]
|
|||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_RESOURCE): cv.url,
|
vol.Required(CONF_RESOURCE): cv.url,
|
||||||
|
vol.Optional(CONF_STATE_RESOURCE): cv.url,
|
||||||
vol.Optional(CONF_HEADERS): {cv.string: cv.string},
|
vol.Optional(CONF_HEADERS): {cv.string: cv.string},
|
||||||
vol.Optional(CONF_BODY_OFF, default=DEFAULT_BODY_OFF): cv.template,
|
vol.Optional(CONF_BODY_OFF, default=DEFAULT_BODY_OFF): cv.template,
|
||||||
vol.Optional(CONF_BODY_ON, default=DEFAULT_BODY_ON): cv.template,
|
vol.Optional(CONF_BODY_ON, default=DEFAULT_BODY_ON): cv.template,
|
||||||
@ -73,6 +75,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
username = config.get(CONF_USERNAME)
|
username = config.get(CONF_USERNAME)
|
||||||
password = config.get(CONF_PASSWORD)
|
password = config.get(CONF_PASSWORD)
|
||||||
resource = config.get(CONF_RESOURCE)
|
resource = config.get(CONF_RESOURCE)
|
||||||
|
state_resource = config.get(CONF_STATE_RESOURCE) or resource
|
||||||
verify_ssl = config.get(CONF_VERIFY_SSL)
|
verify_ssl = config.get(CONF_VERIFY_SSL)
|
||||||
|
|
||||||
auth = None
|
auth = None
|
||||||
@ -91,6 +94,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
|
|||||||
switch = RestSwitch(
|
switch = RestSwitch(
|
||||||
name,
|
name,
|
||||||
resource,
|
resource,
|
||||||
|
state_resource,
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
auth,
|
auth,
|
||||||
@ -122,6 +126,7 @@ class RestSwitch(SwitchEntity):
|
|||||||
self,
|
self,
|
||||||
name,
|
name,
|
||||||
resource,
|
resource,
|
||||||
|
state_resource,
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
auth,
|
auth,
|
||||||
@ -135,6 +140,7 @@ class RestSwitch(SwitchEntity):
|
|||||||
self._state = None
|
self._state = None
|
||||||
self._name = name
|
self._name = name
|
||||||
self._resource = resource
|
self._resource = resource
|
||||||
|
self._state_resource = state_resource
|
||||||
self._method = method
|
self._method = method
|
||||||
self._headers = headers
|
self._headers = headers
|
||||||
self._auth = auth
|
self._auth = auth
|
||||||
@ -213,7 +219,7 @@ class RestSwitch(SwitchEntity):
|
|||||||
|
|
||||||
with async_timeout.timeout(self._timeout):
|
with async_timeout.timeout(self._timeout):
|
||||||
req = await websession.get(
|
req = await websession.get(
|
||||||
self._resource, auth=self._auth, headers=self._headers
|
self._state_resource, auth=self._auth, headers=self._headers
|
||||||
)
|
)
|
||||||
text = await req.text()
|
text = await req.text()
|
||||||
|
|
||||||
|
@ -4,7 +4,17 @@ import asyncio
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
import homeassistant.components.rest.switch as rest
|
import homeassistant.components.rest.switch as rest
|
||||||
from homeassistant.const import HTTP_INTERNAL_SERVER_ERROR
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_HEADERS,
|
||||||
|
CONF_NAME,
|
||||||
|
CONF_PLATFORM,
|
||||||
|
CONF_RESOURCE,
|
||||||
|
CONTENT_TYPE_JSON,
|
||||||
|
HTTP_INTERNAL_SERVER_ERROR,
|
||||||
|
HTTP_NOT_FOUND,
|
||||||
|
HTTP_OK,
|
||||||
|
)
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
from homeassistant.setup import setup_component
|
from homeassistant.setup import setup_component
|
||||||
|
|
||||||
@ -25,7 +35,7 @@ class TestRestSwitchSetup:
|
|||||||
def test_setup_missing_config(self):
|
def test_setup_missing_config(self):
|
||||||
"""Test setup with configuration missing required entries."""
|
"""Test setup with configuration missing required entries."""
|
||||||
assert not asyncio.run_coroutine_threadsafe(
|
assert not asyncio.run_coroutine_threadsafe(
|
||||||
rest.async_setup_platform(self.hass, {"platform": "rest"}, None),
|
rest.async_setup_platform(self.hass, {CONF_PLATFORM: rest.DOMAIN}, None),
|
||||||
self.hass.loop,
|
self.hass.loop,
|
||||||
).result()
|
).result()
|
||||||
|
|
||||||
@ -33,7 +43,9 @@ class TestRestSwitchSetup:
|
|||||||
"""Test setup with resource missing schema."""
|
"""Test setup with resource missing schema."""
|
||||||
assert not asyncio.run_coroutine_threadsafe(
|
assert not asyncio.run_coroutine_threadsafe(
|
||||||
rest.async_setup_platform(
|
rest.async_setup_platform(
|
||||||
self.hass, {"platform": "rest", "resource": "localhost"}, None
|
self.hass,
|
||||||
|
{CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "localhost"},
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
self.hass.loop,
|
self.hass.loop,
|
||||||
).result()
|
).result()
|
||||||
@ -43,7 +55,9 @@ class TestRestSwitchSetup:
|
|||||||
aioclient_mock.get("http://localhost", exc=aiohttp.ClientError)
|
aioclient_mock.get("http://localhost", exc=aiohttp.ClientError)
|
||||||
assert not asyncio.run_coroutine_threadsafe(
|
assert not asyncio.run_coroutine_threadsafe(
|
||||||
rest.async_setup_platform(
|
rest.async_setup_platform(
|
||||||
self.hass, {"platform": "rest", "resource": "http://localhost"}, None
|
self.hass,
|
||||||
|
{CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"},
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
self.hass.loop,
|
self.hass.loop,
|
||||||
).result()
|
).result()
|
||||||
@ -53,41 +67,70 @@ class TestRestSwitchSetup:
|
|||||||
aioclient_mock.get("http://localhost", exc=asyncio.TimeoutError())
|
aioclient_mock.get("http://localhost", exc=asyncio.TimeoutError())
|
||||||
assert not asyncio.run_coroutine_threadsafe(
|
assert not asyncio.run_coroutine_threadsafe(
|
||||||
rest.async_setup_platform(
|
rest.async_setup_platform(
|
||||||
self.hass, {"platform": "rest", "resource": "http://localhost"}, None
|
self.hass,
|
||||||
|
{CONF_PLATFORM: rest.DOMAIN, CONF_RESOURCE: "http://localhost"},
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
self.hass.loop,
|
self.hass.loop,
|
||||||
).result()
|
).result()
|
||||||
|
|
||||||
def test_setup_minimum(self, aioclient_mock):
|
def test_setup_minimum(self, aioclient_mock):
|
||||||
"""Test setup with minimum configuration."""
|
"""Test setup with minimum configuration."""
|
||||||
aioclient_mock.get("http://localhost", status=200)
|
aioclient_mock.get("http://localhost", status=HTTP_OK)
|
||||||
with assert_setup_component(1, "switch"):
|
with assert_setup_component(1, SWITCH_DOMAIN):
|
||||||
assert setup_component(
|
assert setup_component(
|
||||||
self.hass,
|
self.hass,
|
||||||
"switch",
|
SWITCH_DOMAIN,
|
||||||
{"switch": {"platform": "rest", "resource": "http://localhost"}},
|
{
|
||||||
|
SWITCH_DOMAIN: {
|
||||||
|
CONF_PLATFORM: rest.DOMAIN,
|
||||||
|
CONF_RESOURCE: "http://localhost",
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
assert aioclient_mock.call_count == 1
|
assert aioclient_mock.call_count == 1
|
||||||
|
|
||||||
def test_setup(self, aioclient_mock):
|
def test_setup(self, aioclient_mock):
|
||||||
"""Test setup with valid configuration."""
|
"""Test setup with valid configuration."""
|
||||||
aioclient_mock.get("http://localhost", status=200)
|
aioclient_mock.get("http://localhost", status=HTTP_OK)
|
||||||
assert setup_component(
|
assert setup_component(
|
||||||
self.hass,
|
self.hass,
|
||||||
"switch",
|
SWITCH_DOMAIN,
|
||||||
{
|
{
|
||||||
"switch": {
|
SWITCH_DOMAIN: {
|
||||||
"platform": "rest",
|
CONF_PLATFORM: rest.DOMAIN,
|
||||||
"name": "foo",
|
CONF_NAME: "foo",
|
||||||
"resource": "http://localhost",
|
CONF_RESOURCE: "http://localhost",
|
||||||
"headers": {"Content-type": "application/json"},
|
CONF_HEADERS: {"Content-type": CONTENT_TYPE_JSON},
|
||||||
"body_on": "custom on text",
|
rest.CONF_BODY_ON: "custom on text",
|
||||||
"body_off": "custom off text",
|
rest.CONF_BODY_OFF: "custom off text",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert aioclient_mock.call_count == 1
|
assert aioclient_mock.call_count == 1
|
||||||
assert_setup_component(1, "switch")
|
assert_setup_component(1, SWITCH_DOMAIN)
|
||||||
|
|
||||||
|
def test_setup_with_state_resource(self, aioclient_mock):
|
||||||
|
"""Test setup with valid configuration."""
|
||||||
|
aioclient_mock.get("http://localhost", status=HTTP_NOT_FOUND)
|
||||||
|
aioclient_mock.get("http://localhost/state", status=HTTP_OK)
|
||||||
|
assert setup_component(
|
||||||
|
self.hass,
|
||||||
|
SWITCH_DOMAIN,
|
||||||
|
{
|
||||||
|
SWITCH_DOMAIN: {
|
||||||
|
CONF_PLATFORM: rest.DOMAIN,
|
||||||
|
CONF_NAME: "foo",
|
||||||
|
CONF_RESOURCE: "http://localhost",
|
||||||
|
rest.CONF_STATE_RESOURCE: "http://localhost/state",
|
||||||
|
CONF_HEADERS: {"Content-type": "application/json"},
|
||||||
|
rest.CONF_BODY_ON: "custom on text",
|
||||||
|
rest.CONF_BODY_OFF: "custom off text",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert aioclient_mock.call_count == 1
|
||||||
|
assert_setup_component(1, SWITCH_DOMAIN)
|
||||||
|
|
||||||
|
|
||||||
class TestRestSwitch:
|
class TestRestSwitch:
|
||||||
@ -99,6 +142,7 @@ class TestRestSwitch:
|
|||||||
self.name = "foo"
|
self.name = "foo"
|
||||||
self.method = "post"
|
self.method = "post"
|
||||||
self.resource = "http://localhost/"
|
self.resource = "http://localhost/"
|
||||||
|
self.state_resource = self.resource
|
||||||
self.headers = {"Content-type": "application/json"}
|
self.headers = {"Content-type": "application/json"}
|
||||||
self.auth = None
|
self.auth = None
|
||||||
self.body_on = Template("on", self.hass)
|
self.body_on = Template("on", self.hass)
|
||||||
@ -106,6 +150,7 @@ class TestRestSwitch:
|
|||||||
self.switch = rest.RestSwitch(
|
self.switch = rest.RestSwitch(
|
||||||
self.name,
|
self.name,
|
||||||
self.resource,
|
self.resource,
|
||||||
|
self.state_resource,
|
||||||
self.method,
|
self.method,
|
||||||
self.headers,
|
self.headers,
|
||||||
self.auth,
|
self.auth,
|
||||||
@ -131,7 +176,7 @@ class TestRestSwitch:
|
|||||||
|
|
||||||
def test_turn_on_success(self, aioclient_mock):
|
def test_turn_on_success(self, aioclient_mock):
|
||||||
"""Test turn_on."""
|
"""Test turn_on."""
|
||||||
aioclient_mock.post(self.resource, status=200)
|
aioclient_mock.post(self.resource, status=HTTP_OK)
|
||||||
asyncio.run_coroutine_threadsafe(
|
asyncio.run_coroutine_threadsafe(
|
||||||
self.switch.async_turn_on(), self.hass.loop
|
self.switch.async_turn_on(), self.hass.loop
|
||||||
).result()
|
).result()
|
||||||
@ -160,7 +205,7 @@ class TestRestSwitch:
|
|||||||
|
|
||||||
def test_turn_off_success(self, aioclient_mock):
|
def test_turn_off_success(self, aioclient_mock):
|
||||||
"""Test turn_off."""
|
"""Test turn_off."""
|
||||||
aioclient_mock.post(self.resource, status=200)
|
aioclient_mock.post(self.resource, status=HTTP_OK)
|
||||||
asyncio.run_coroutine_threadsafe(
|
asyncio.run_coroutine_threadsafe(
|
||||||
self.switch.async_turn_off(), self.hass.loop
|
self.switch.async_turn_off(), self.hass.loop
|
||||||
).result()
|
).result()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user