mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add config component and hassbian example panel (#5868)
* Add hassbian panel * Rename to generic config panel * Allow loading hassbian as test * Add tests * Update frontend * Lint * Lint
This commit is contained in:
parent
2b2c1562a5
commit
44311193ef
28
homeassistant/components/config/__init__.py
Normal file
28
homeassistant/components/config/__init__.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""Component to interact with Hassbian tools."""
|
||||
import asyncio
|
||||
|
||||
from homeassistant.bootstrap import async_prepare_setup_platform
|
||||
from homeassistant.components.frontend import register_built_in_panel
|
||||
|
||||
DOMAIN = 'config'
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Setup the hassbian component."""
|
||||
register_built_in_panel(hass, 'config', 'Configuration', 'mdi:settings')
|
||||
|
||||
for panel_name in ('hassbian',):
|
||||
panel = yield from async_prepare_setup_platform(hass, config, DOMAIN,
|
||||
panel_name)
|
||||
|
||||
if not panel:
|
||||
continue
|
||||
|
||||
success = yield from panel.async_setup(hass)
|
||||
|
||||
if success:
|
||||
hass.config.components.add('{}.{}'.format(DOMAIN, panel_name))
|
||||
|
||||
return True
|
118
homeassistant/components/config/hassbian.py
Normal file
118
homeassistant/components/config/hassbian.py
Normal file
@ -0,0 +1,118 @@
|
||||
"""Component to interact with Hassbian tools."""
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
|
||||
|
||||
_TEST_OUTPUT = """
|
||||
{
|
||||
"suites": [
|
||||
{
|
||||
"openzwave": [
|
||||
{
|
||||
"state": "installed"
|
||||
},
|
||||
{
|
||||
"description": "This is the description of the Open Z-Wave suite."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"openelec": [
|
||||
{
|
||||
"state": "not_installed"
|
||||
},
|
||||
{
|
||||
"description":
|
||||
"OpenElec is amazing. It allows you to control the TV."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mosquitto": [
|
||||
{
|
||||
"state": "installing"
|
||||
},
|
||||
{
|
||||
"description":
|
||||
"Mosquitto is an MQTT broker."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass):
|
||||
"""Setup the hassbian config."""
|
||||
# Test if is hassbian
|
||||
test_mode = 'FORCE_HASSBIAN' in os.environ
|
||||
is_hassbian = test_mode
|
||||
|
||||
if not is_hassbian:
|
||||
return False
|
||||
|
||||
hass.http.register_view(HassbianSuitesView(test_mode))
|
||||
hass.http.register_view(HassbianSuiteInstallView(test_mode))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def hassbian_status(hass, test_mode=False):
|
||||
"""Query for the Hassbian status."""
|
||||
# fetch real output when not in test mode
|
||||
if test_mode:
|
||||
return json.loads(_TEST_OUTPUT)
|
||||
|
||||
raise Exception('Real mode not implemented yet.')
|
||||
|
||||
|
||||
class HassbianSuitesView(HomeAssistantView):
|
||||
"""Hassbian packages endpoint."""
|
||||
|
||||
url = '/api/config/hassbian/suites'
|
||||
name = 'api:config:hassbian:suites'
|
||||
|
||||
def __init__(self, test_mode):
|
||||
"""Initialize suites view."""
|
||||
self._test_mode = test_mode
|
||||
|
||||
@asyncio.coroutine
|
||||
def get(self, request):
|
||||
"""Request suite status."""
|
||||
inp = yield from hassbian_status(request.app['hass'], self._test_mode)
|
||||
|
||||
# Flatten the structure a bit
|
||||
suites = {}
|
||||
|
||||
for suite in inp['suites']:
|
||||
key = next(iter(suite))
|
||||
info = suites[key] = {}
|
||||
|
||||
for item in suite[key]:
|
||||
item_key = next(iter(item))
|
||||
info[item_key] = item[item_key]
|
||||
|
||||
return self.json(suites)
|
||||
|
||||
|
||||
class HassbianSuiteInstallView(HomeAssistantView):
|
||||
"""Hassbian packages endpoint."""
|
||||
|
||||
url = '/api/config/hassbian/suites/{suite}/install'
|
||||
name = 'api:config:hassbian:suite'
|
||||
|
||||
def __init__(self, test_mode):
|
||||
"""Initialize suite view."""
|
||||
self._test_mode = test_mode
|
||||
|
||||
@asyncio.coroutine
|
||||
def post(self, request, suite):
|
||||
"""Request suite status."""
|
||||
# do real install if not in test mode
|
||||
return self.json({"status": "ok"})
|
@ -19,7 +19,7 @@ DOMAIN = 'frontend'
|
||||
DEPENDENCIES = ['api', 'websocket_api']
|
||||
URL_PANEL_COMPONENT = '/frontend/panels/{}.html'
|
||||
URL_PANEL_COMPONENT_FP = '/frontend/panels/{}-{}.html'
|
||||
STATIC_PATH = os.path.join(os.path.dirname(__file__), 'www_static')
|
||||
STATIC_PATH = os.path.join(os.path.dirname(__file__), 'www_static/')
|
||||
MANIFEST_JSON = {
|
||||
"background_color": "#FFFFFF",
|
||||
"description": "Open-source home automation platform running on Python 3.",
|
||||
@ -51,17 +51,22 @@ _LOGGER = logging.getLogger(__name__)
|
||||
def register_built_in_panel(hass, component_name, sidebar_title=None,
|
||||
sidebar_icon=None, url_path=None, config=None):
|
||||
"""Register a built-in panel."""
|
||||
path = 'panels/ha-panel-{}.html'.format(component_name)
|
||||
nondev_path = 'panels/ha-panel-{}.html'.format(component_name)
|
||||
|
||||
if hass.http.development:
|
||||
url = ('/static/home-assistant-polymer/panels/'
|
||||
'{0}/ha-panel-{0}.html'.format(component_name))
|
||||
path = os.path.join(
|
||||
STATIC_PATH, 'home-assistant-polymer/panels/',
|
||||
'{0}/ha-panel-{0}.html'.format(component_name))
|
||||
else:
|
||||
url = None # use default url generate mechanism
|
||||
path = os.path.join(STATIC_PATH, nondev_path)
|
||||
|
||||
register_panel(hass, component_name, os.path.join(STATIC_PATH, path),
|
||||
FINGERPRINTS[path], sidebar_title, sidebar_icon, url_path,
|
||||
url, config)
|
||||
# Fingerprint doesn't exist when adding new built-in panel
|
||||
register_panel(hass, component_name, path,
|
||||
FINGERPRINTS.get(nondev_path, 'dev'), sidebar_title,
|
||||
sidebar_icon, url_path, url, config)
|
||||
|
||||
|
||||
def register_panel(hass, component_name, path, md5=None, sidebar_title=None,
|
||||
|
@ -5,6 +5,7 @@ FINGERPRINTS = {
|
||||
"frontend.html": "cfd75c944ab14912cfbb4fdd9027579c",
|
||||
"mdi.html": "c1dde43ccf5667f687c418fc8daf9668",
|
||||
"micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a",
|
||||
"panels/ha-panel-config.html": "fb50a25da4b4cfbb0d9a74bb22a31db9",
|
||||
"panels/ha-panel-dev-event.html": "5c82300b3cf543a92cf4297506e450e7",
|
||||
"panels/ha-panel-dev-info.html": "0469024d94d6270a8680df2be44ba916",
|
||||
"panels/ha-panel-dev-service.html": "9f749635e518a4ca7991975bdefdb10a",
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 518d0b38da47fa5923c84a963d11e9ed59424c2f
|
||||
Subproject commit ba48e40a2bba273b1cdcdf637ecbef4f4db14284
|
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -210,9 +210,9 @@ def mock_state_change_event(hass, new_state, old_state=None):
|
||||
hass.bus.fire(EVENT_STATE_CHANGED, event_data)
|
||||
|
||||
|
||||
def mock_http_component(hass):
|
||||
def mock_http_component(hass, api_password=None):
|
||||
"""Mock the HTTP component."""
|
||||
hass.http = MagicMock()
|
||||
hass.http = MagicMock(api_password=api_password)
|
||||
hass.config.components.add('http')
|
||||
hass.http.views = {}
|
||||
|
||||
@ -229,7 +229,8 @@ def mock_http_component(hass):
|
||||
|
||||
def mock_http_component_app(hass, api_password=None):
|
||||
"""Create an aiohttp.web.Application instance for testing."""
|
||||
hass.http = MagicMock(api_password=api_password)
|
||||
if 'http' not in hass.config.components:
|
||||
mock_http_component(hass, api_password)
|
||||
app = web.Application(middlewares=[auth_middleware], loop=hass.loop)
|
||||
app['hass'] = hass
|
||||
app[KEY_USE_X_FORWARDED_FOR] = False
|
||||
|
1
tests/components/config/__init__.py
Normal file
1
tests/components/config/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
"""Tests for the config component."""
|
70
tests/components/config/test_hassbian.py
Normal file
70
tests/components/config/test_hassbian.py
Normal file
@ -0,0 +1,70 @@
|
||||
"""Test hassbian config."""
|
||||
import asyncio
|
||||
import os
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
from homeassistant.components.config.hassbian import (
|
||||
HassbianSuitesView, HassbianSuiteInstallView)
|
||||
from tests.common import (
|
||||
mock_http_component, mock_http_component_app)
|
||||
|
||||
|
||||
def test_setup_check_env_prevents_load(hass, loop):
|
||||
"""Test it does not set up hassbian if environment var not present."""
|
||||
mock_http_component(hass)
|
||||
with patch.dict(os.environ, clear=True):
|
||||
loop.run_until_complete(async_setup_component(hass, 'config', {}))
|
||||
assert 'config' in hass.config.components
|
||||
assert HassbianSuitesView.name not in hass.http.views
|
||||
assert HassbianSuiteInstallView.name not in hass.http.views
|
||||
|
||||
|
||||
def test_setup_check_env_works(hass, loop):
|
||||
"""Test it sets up hassbian if environment var present."""
|
||||
mock_http_component(hass)
|
||||
with patch.dict(os.environ, {'FORCE_HASSBIAN': '1'}):
|
||||
loop.run_until_complete(async_setup_component(hass, 'config', {}))
|
||||
assert 'config' in hass.config.components
|
||||
assert HassbianSuitesView.name in hass.http.views
|
||||
assert HassbianSuiteInstallView.name in hass.http.views
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_get_suites(hass, test_client):
|
||||
"""Test getting suites."""
|
||||
app = mock_http_component_app(hass)
|
||||
|
||||
with patch.dict(os.environ, {'FORCE_HASSBIAN': '1'}):
|
||||
yield from async_setup_component(hass, 'config', {})
|
||||
|
||||
hass.http.views[HassbianSuitesView.name].register(app.router)
|
||||
|
||||
client = yield from test_client(app)
|
||||
resp = yield from client.get('/api/config/hassbian/suites')
|
||||
assert resp.status == 200
|
||||
result = yield from resp.json()
|
||||
|
||||
assert 'mosquitto' in result
|
||||
info = result['mosquitto']
|
||||
assert info['state'] == 'installing'
|
||||
assert info['description'] == 'Mosquitto is an MQTT broker.'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_install_suite(hass, test_client):
|
||||
"""Test getting suites."""
|
||||
app = mock_http_component_app(hass)
|
||||
|
||||
with patch.dict(os.environ, {'FORCE_HASSBIAN': '1'}):
|
||||
yield from async_setup_component(hass, 'config', {})
|
||||
|
||||
hass.http.views[HassbianSuiteInstallView.name].register(app.router)
|
||||
|
||||
client = yield from test_client(app)
|
||||
resp = yield from client.post(
|
||||
'/api/config/hassbian/suites/openzwave/install')
|
||||
assert resp.status == 200
|
||||
result = yield from resp.json()
|
||||
|
||||
assert result == {"status": "ok"}
|
18
tests/components/config/test_init.py
Normal file
18
tests/components/config/test_init.py
Normal file
@ -0,0 +1,18 @@
|
||||
"""Test config init."""
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
|
||||
from tests.common import mock_http_component
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def stub_http(hass):
|
||||
"""Stub the HTTP component."""
|
||||
mock_http_component(hass)
|
||||
|
||||
|
||||
def test_config_setup(hass, loop):
|
||||
"""Test it sets up hassbian."""
|
||||
loop.run_until_complete(async_setup_component(hass, 'config', {}))
|
||||
assert 'config' in hass.config.components
|
Loading…
x
Reference in New Issue
Block a user