commit
6902e522b9
|
@ -17,7 +17,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
|
||||
REQUIREMENTS = ['aioautomatic==0.1.1']
|
||||
REQUIREMENTS = ['aioautomatic==0.2.1']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -27,6 +27,8 @@ CONF_DEVICES = 'devices'
|
|||
|
||||
DEFAULT_TIMEOUT = 5
|
||||
|
||||
SCOPE = ['location', 'vehicle:profile', 'trip']
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_CLIENT_ID): cv.string,
|
||||
vol.Required(CONF_SECRET): cv.string,
|
||||
|
@ -49,7 +51,7 @@ def async_setup_scanner(hass, config, async_see, discovery_info=None):
|
|||
request_kwargs={'timeout': DEFAULT_TIMEOUT})
|
||||
try:
|
||||
session = yield from client.create_session_from_password(
|
||||
config[CONF_USERNAME], config[CONF_PASSWORD])
|
||||
SCOPE, config[CONF_USERNAME], config[CONF_PASSWORD])
|
||||
data = AutomaticData(hass, session, config[CONF_DEVICES], async_see)
|
||||
except aioautomatic.exceptions.AutomaticError as err:
|
||||
_LOGGER.error(str(err))
|
||||
|
|
|
@ -3,19 +3,20 @@
|
|||
FINGERPRINTS = {
|
||||
"compatibility.js": "83d9c77748dafa9db49ae77d7f3d8fb0",
|
||||
"core.js": "5d08475f03adb5969bd31855d5ca0cfd",
|
||||
"frontend.html": "8264c0ee8dafb09785ec7b934795d3b1",
|
||||
"mdi.html": "d86ee142ae2476f49384bfe866a2885e",
|
||||
"frontend.html": "1533f44c55927e814294de757cd7eada",
|
||||
"mdi.html": "1cc8593d3684f7f6f3b3854403216f77",
|
||||
"micromarkdown-js.html": "93b5ec4016f0bba585521cf4d18dec1a",
|
||||
"panels/ha-panel-config.html": "0b42cb4e709ce35ad2666ffeca6f9b14",
|
||||
"panels/ha-panel-config.html": "39f00f769faa63ee61f1fe6fc85d67f7",
|
||||
"panels/ha-panel-dev-event.html": "2db9c218065ef0f61d8d08db8093cad2",
|
||||
"panels/ha-panel-dev-info.html": "61610e015a411cfc84edd2c4d489e71d",
|
||||
"panels/ha-panel-dev-service.html": "415552027cb083badeff5f16080410ed",
|
||||
"panels/ha-panel-dev-state.html": "d70314913b8923d750932367b1099750",
|
||||
"panels/ha-panel-dev-template.html": "567fbf86735e1b891e40c2f4060fec9b",
|
||||
"panels/ha-panel-history.html": "be115906882752d220199abbaddc53e5",
|
||||
"panels/ha-panel-hassio.html": "1d954cfe5f47c4be3cf4f6f5db9a83b2",
|
||||
"panels/ha-panel-history.html": "89062c48c76206cad1cec14ddbb1cbb1",
|
||||
"panels/ha-panel-iframe.html": "d920f0aa3c903680f2f8795e2255daab",
|
||||
"panels/ha-panel-logbook.html": "bf29de0c586a598113c6cc09ead12b00",
|
||||
"panels/ha-panel-logbook.html": "6dd6a16f52117318b202e60f98400163",
|
||||
"panels/ha-panel-map.html": "31c592c239636f91e07c7ac232a5ebc4",
|
||||
"panels/ha-panel-zwave.html": "f52d0c001f48e0c7b33a172f3a71b547",
|
||||
"panels/ha-panel-zwave.html": "a81f82b48439da80286798558f414a2e",
|
||||
"websocket_test.html": "575de64b431fe11c3785bf96d7813450"
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1 +1 @@
|
|||
Subproject commit 3fdba359865823805e8ea756c8500d3913976158
|
||||
Subproject commit 863ccb548616236faafa3b3393a1f51429bb8afd
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -7,70 +7,53 @@ https://home-assistant.io/components/hassio/
|
|||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
from aiohttp.web_exceptions import HTTPBadGateway
|
||||
from aiohttp.web_exceptions import (
|
||||
HTTPBadGateway, HTTPNotFound, HTTPMethodNotAllowed)
|
||||
from aiohttp.hdrs import CONTENT_TYPE
|
||||
import async_timeout
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
from homeassistant.const import CONTENT_TYPE_TEXT_PLAIN
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.components.frontend import register_built_in_panel
|
||||
|
||||
DOMAIN = 'hassio'
|
||||
DEPENDENCIES = ['http']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
LONG_TASK_TIMEOUT = 900
|
||||
DEFAULT_TIMEOUT = 10
|
||||
TIMEOUT = 10
|
||||
|
||||
SERVICE_HOST_SHUTDOWN = 'host_shutdown'
|
||||
SERVICE_HOST_REBOOT = 'host_reboot'
|
||||
HASSIO_REST_COMMANDS = {
|
||||
'host/shutdown': ['POST'],
|
||||
'host/reboot': ['POST'],
|
||||
'host/update': ['GET'],
|
||||
'host/info': ['GET'],
|
||||
'supervisor/info': ['GET'],
|
||||
'supervisor/update': ['POST'],
|
||||
'supervisor/options': ['POST'],
|
||||
'supervisor/reload': ['POST'],
|
||||
'supervisor/logs': ['GET'],
|
||||
'homeassistant/info': ['GET'],
|
||||
'homeassistant/update': ['POST'],
|
||||
'homeassistant/logs': ['GET'],
|
||||
'network/info': ['GET'],
|
||||
'network/options': ['GET'],
|
||||
}
|
||||
|
||||
SERVICE_HOST_UPDATE = 'host_update'
|
||||
SERVICE_HOMEASSISTANT_UPDATE = 'homeassistant_update'
|
||||
|
||||
SERVICE_SUPERVISOR_UPDATE = 'supervisor_update'
|
||||
SERVICE_SUPERVISOR_RELOAD = 'supervisor_reload'
|
||||
|
||||
SERVICE_ADDON_INSTALL = 'addon_install'
|
||||
SERVICE_ADDON_UNINSTALL = 'addon_uninstall'
|
||||
SERVICE_ADDON_UPDATE = 'addon_update'
|
||||
SERVICE_ADDON_START = 'addon_start'
|
||||
SERVICE_ADDON_STOP = 'addon_stop'
|
||||
|
||||
ATTR_ADDON = 'addon'
|
||||
ATTR_VERSION = 'version'
|
||||
|
||||
|
||||
SCHEMA_SERVICE_UPDATE = vol.Schema({
|
||||
vol.Optional(ATTR_VERSION): cv.string,
|
||||
})
|
||||
|
||||
SCHEMA_SERVICE_ADDONS = vol.Schema({
|
||||
vol.Required(ATTR_ADDON): cv.slug,
|
||||
})
|
||||
|
||||
SCHEMA_SERVICE_ADDONS_VERSION = SCHEMA_SERVICE_ADDONS.extend({
|
||||
vol.Optional(ATTR_VERSION): cv.string,
|
||||
})
|
||||
|
||||
|
||||
SERVICE_MAP = {
|
||||
SERVICE_HOST_SHUTDOWN: None,
|
||||
SERVICE_HOST_REBOOT: None,
|
||||
SERVICE_HOST_UPDATE: SCHEMA_SERVICE_UPDATE,
|
||||
SERVICE_HOMEASSISTANT_UPDATE: SCHEMA_SERVICE_UPDATE,
|
||||
SERVICE_SUPERVISOR_UPDATE: SCHEMA_SERVICE_UPDATE,
|
||||
SERVICE_SUPERVISOR_RELOAD: None,
|
||||
SERVICE_ADDON_INSTALL: SCHEMA_SERVICE_ADDONS_VERSION,
|
||||
SERVICE_ADDON_UNINSTALL: SCHEMA_SERVICE_ADDONS,
|
||||
SERVICE_ADDON_START: SCHEMA_SERVICE_ADDONS,
|
||||
SERVICE_ADDON_STOP: SCHEMA_SERVICE_ADDONS,
|
||||
SERVICE_ADDON_UPDATE: SCHEMA_SERVICE_ADDONS_VERSION,
|
||||
ADDON_REST_COMMANDS = {
|
||||
'install': ['POST'],
|
||||
'uninstall': ['POST'],
|
||||
'start': ['POST'],
|
||||
'stop': ['POST'],
|
||||
'update': ['POST'],
|
||||
'options': ['POST'],
|
||||
'info': ['GET'],
|
||||
'logs': ['GET'],
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,67 +74,11 @@ def async_setup(hass, config):
|
|||
_LOGGER.error("Not connected with HassIO!")
|
||||
return False
|
||||
|
||||
# register base api views
|
||||
for base in ('host', 'homeassistant'):
|
||||
hass.http.register_view(HassIOBaseView(hassio, base))
|
||||
for base in ('supervisor', 'network'):
|
||||
hass.http.register_view(HassIOBaseEditView(hassio, base))
|
||||
hass.http.register_view(HassIOView(hassio))
|
||||
|
||||
# register view for addons
|
||||
hass.http.register_view(HassIOAddonsView(hassio))
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_service_handler(service):
|
||||
"""Handle HassIO service calls."""
|
||||
addon = service.data.get(ATTR_ADDON)
|
||||
if ATTR_VERSION in service.data:
|
||||
version = {ATTR_VERSION: service.data[ATTR_VERSION]}
|
||||
else:
|
||||
version = None
|
||||
|
||||
# map to api call
|
||||
if service.service == SERVICE_HOST_UPDATE:
|
||||
yield from hassio.send_command(
|
||||
"/host/update", payload=version)
|
||||
elif service.service == SERVICE_HOST_REBOOT:
|
||||
yield from hassio.send_command("/host/reboot")
|
||||
elif service.service == SERVICE_HOST_SHUTDOWN:
|
||||
yield from hassio.send_command("/host/shutdown")
|
||||
elif service.service == SERVICE_SUPERVISOR_UPDATE:
|
||||
yield from hassio.send_command(
|
||||
"/supervisor/update", payload=version)
|
||||
elif service.service == SERVICE_SUPERVISOR_RELOAD:
|
||||
yield from hassio.send_command(
|
||||
"/supervisor/reload", timeout=LONG_TASK_TIMEOUT)
|
||||
elif service.service == SERVICE_HOMEASSISTANT_UPDATE:
|
||||
yield from hassio.send_command(
|
||||
"/homeassistant/update", payload=version,
|
||||
timeout=LONG_TASK_TIMEOUT)
|
||||
elif service.service == SERVICE_ADDON_INSTALL:
|
||||
yield from hassio.send_command(
|
||||
"/addons/{}/install".format(addon), payload=version,
|
||||
timeout=LONG_TASK_TIMEOUT)
|
||||
elif service.service == SERVICE_ADDON_UNINSTALL:
|
||||
yield from hassio.send_command(
|
||||
"/addons/{}/uninstall".format(addon))
|
||||
elif service.service == SERVICE_ADDON_START:
|
||||
yield from hassio.send_command("/addons/{}/start".format(addon))
|
||||
elif service.service == SERVICE_ADDON_STOP:
|
||||
yield from hassio.send_command(
|
||||
"/addons/{}/stop".format(addon), timeout=LONG_TASK_TIMEOUT)
|
||||
elif service.service == SERVICE_ADDON_UPDATE:
|
||||
yield from hassio.send_command(
|
||||
"/addons/{}/update".format(addon), payload=version,
|
||||
timeout=LONG_TASK_TIMEOUT)
|
||||
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, load_yaml_config_file, os.path.join(
|
||||
os.path.dirname(__file__), 'services.yaml'))
|
||||
|
||||
for service, schema in SERVICE_MAP.items():
|
||||
hass.services.async_register(
|
||||
DOMAIN, service, async_service_handler,
|
||||
descriptions[DOMAIN][service], schema=schema)
|
||||
if 'frontend' in hass.config.components:
|
||||
register_built_in_panel(hass, 'hassio', 'Hass.io',
|
||||
'mdi:access-point-network')
|
||||
|
||||
return True
|
||||
|
||||
|
@ -165,117 +92,122 @@ class HassIO(object):
|
|||
self.websession = websession
|
||||
self._ip = ip
|
||||
|
||||
@asyncio.coroutine
|
||||
def is_connected(self):
|
||||
"""Return True if it connected to HassIO supervisor.
|
||||
|
||||
Return a coroutine.
|
||||
This method is a coroutine.
|
||||
"""
|
||||
return self.send_command("/supervisor/ping")
|
||||
|
||||
@asyncio.coroutine
|
||||
def send_command(self, cmd, payload=None, timeout=DEFAULT_TIMEOUT):
|
||||
"""Send request to API."""
|
||||
answer = yield from self.send_raw(
|
||||
cmd, payload=payload, timeout=timeout
|
||||
)
|
||||
if answer and answer['result'] == 'ok':
|
||||
return answer['data'] if answer['data'] else True
|
||||
|
||||
_LOGGER.error("%s return error %s.", cmd, answer['message'])
|
||||
return False
|
||||
|
||||
@asyncio.coroutine
|
||||
def send_raw(self, cmd, payload=None, timeout=DEFAULT_TIMEOUT):
|
||||
"""Send raw request to API."""
|
||||
try:
|
||||
with async_timeout.timeout(timeout, loop=self.loop):
|
||||
with async_timeout.timeout(TIMEOUT, loop=self.loop):
|
||||
request = yield from self.websession.get(
|
||||
"http://{}{}".format(self._ip, cmd),
|
||||
timeout=None, json=payload
|
||||
"http://{}{}".format(self._ip, "/supervisor/ping")
|
||||
)
|
||||
|
||||
if request.status != 200:
|
||||
_LOGGER.error("%s return code %d.", cmd, request.status)
|
||||
return
|
||||
_LOGGER.error("Ping return code %d.", request.status)
|
||||
return False
|
||||
|
||||
return (yield from request.json())
|
||||
answer = yield from request.json()
|
||||
return answer and answer['result'] == 'ok'
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Timeout on api request %s.", cmd)
|
||||
_LOGGER.error("Timeout on ping request")
|
||||
|
||||
except aiohttp.ClientError:
|
||||
_LOGGER.error("Client error on api request %s.", cmd)
|
||||
except aiohttp.ClientError as err:
|
||||
_LOGGER.error("Client error on ping request %s", err)
|
||||
|
||||
return False
|
||||
|
||||
@asyncio.coroutine
|
||||
def command_proxy(self, path, request):
|
||||
"""Return a client request with proxy origin for HassIO supervisor.
|
||||
|
||||
This method is a coroutine.
|
||||
"""
|
||||
try:
|
||||
data = None
|
||||
headers = None
|
||||
with async_timeout.timeout(TIMEOUT, loop=self.loop):
|
||||
data = yield from request.read()
|
||||
if data:
|
||||
headers = {CONTENT_TYPE: request.content_type}
|
||||
else:
|
||||
data = None
|
||||
|
||||
method = getattr(self.websession, request.method.lower())
|
||||
client = yield from method(
|
||||
"http://{}/{}".format(self._ip, path), data=data,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
return client
|
||||
|
||||
except aiohttp.ClientError as err:
|
||||
_LOGGER.error("Client error on api %s request %s.", path, err)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
_LOGGER.error("Client timeout error on api request %s.", path)
|
||||
|
||||
raise HTTPBadGateway()
|
||||
|
||||
|
||||
class HassIOBaseView(HomeAssistantView):
|
||||
class HassIOView(HomeAssistantView):
|
||||
"""HassIO view to handle base part."""
|
||||
|
||||
name = "api:hassio"
|
||||
url = "/api/hassio/{path:.+}"
|
||||
requires_auth = True
|
||||
|
||||
def __init__(self, hassio, base):
|
||||
"""Initialize a hassio base view."""
|
||||
self.hassio = hassio
|
||||
self._url_info = "/{}/info".format(base)
|
||||
|
||||
self.url = "/api/hassio/{}".format(base)
|
||||
self.name = "api:hassio:{}".format(base)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get(self, request):
|
||||
"""Get base data."""
|
||||
data = yield from self.hassio.send_command(self._url_info)
|
||||
if not data:
|
||||
raise HTTPBadGateway()
|
||||
return web.json_response(data)
|
||||
|
||||
|
||||
class HassIOBaseEditView(HassIOBaseView):
|
||||
"""HassIO view to handle base with options support."""
|
||||
|
||||
def __init__(self, hassio, base):
|
||||
"""Initialize a hassio base edit view."""
|
||||
super().__init__(hassio, base)
|
||||
self._url_options = "/{}/options".format(base)
|
||||
|
||||
@asyncio.coroutine
|
||||
def post(self, request):
|
||||
"""Set options on host."""
|
||||
data = yield from request.json()
|
||||
|
||||
response = yield from self.hassio.send_raw(
|
||||
self._url_options, payload=data)
|
||||
if not response:
|
||||
raise HTTPBadGateway()
|
||||
return web.json_response(response)
|
||||
|
||||
|
||||
class HassIOAddonsView(HomeAssistantView):
|
||||
"""HassIO view to handle addons part."""
|
||||
|
||||
requires_auth = True
|
||||
url = "/api/hassio/addons/{addon}"
|
||||
name = "api:hassio:addons"
|
||||
|
||||
def __init__(self, hassio):
|
||||
"""Initialize a hassio addon view."""
|
||||
"""Initialize a hassio base view."""
|
||||
self.hassio = hassio
|
||||
|
||||
@asyncio.coroutine
|
||||
def get(self, request, addon):
|
||||
"""Get addon data."""
|
||||
data = yield from self.hassio.send_command(
|
||||
"/addons/{}/info".format(addon))
|
||||
if not data:
|
||||
raise HTTPBadGateway()
|
||||
return web.json_response(data)
|
||||
def _handle(self, request, path):
|
||||
"""Route data to hassio."""
|
||||
if path.startswith('addons/'):
|
||||
parts = path.split('/')
|
||||
|
||||
@asyncio.coroutine
|
||||
def post(self, request, addon):
|
||||
"""Set options on host."""
|
||||
data = yield from request.json()
|
||||
if len(parts) != 3:
|
||||
raise HTTPNotFound()
|
||||
|
||||
response = yield from self.hassio.send_raw(
|
||||
"/addons/{}/options".format(addon), payload=data)
|
||||
if not response:
|
||||
raise HTTPBadGateway()
|
||||
return web.json_response(response)
|
||||
allowed_methods = ADDON_REST_COMMANDS.get(parts[-1])
|
||||
else:
|
||||
allowed_methods = HASSIO_REST_COMMANDS.get(path)
|
||||
|
||||
if allowed_methods is None:
|
||||
raise HTTPNotFound()
|
||||
if request.method not in allowed_methods:
|
||||
raise HTTPMethodNotAllowed(request.method, allowed_methods)
|
||||
|
||||
client = yield from self.hassio.command_proxy(path, request)
|
||||
|
||||
data = yield from client.read()
|
||||
if path.endswith('/logs'):
|
||||
return _create_response_log(client, data)
|
||||
return _create_response(client, data)
|
||||
|
||||
get = _handle
|
||||
post = _handle
|
||||
|
||||
|
||||
def _create_response(client, data):
|
||||
"""Convert a response from client request."""
|
||||
return web.Response(
|
||||
body=data,
|
||||
status=client.status,
|
||||
content_type=client.content_type,
|
||||
)
|
||||
|
||||
|
||||
def _create_response_log(client, data):
|
||||
"""Convert a response from client request."""
|
||||
# Remove color codes
|
||||
log = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", data.decode())
|
||||
|
||||
return web.Response(
|
||||
text=log,
|
||||
status=client.status,
|
||||
content_type=CONTENT_TYPE_TEXT_PLAIN,
|
||||
)
|
||||
|
|
|
@ -129,7 +129,8 @@ class Tradfri(Light):
|
|||
"""Fetch new state data for this light."""
|
||||
self._light.update()
|
||||
|
||||
# Handle Hue lights paired with the gatway
|
||||
if self._light_data.hex_color is not None:
|
||||
# Handle Hue lights paired with the gateway
|
||||
# hex_color is 0 when bulb is unreachable
|
||||
if self._light_data.hex_color not in (None, '0'):
|
||||
self._rgb_color = color_util.rgb_hex_to_rgb_list(
|
||||
self._light_data.hex_color)
|
||||
|
|
|
@ -25,7 +25,8 @@ from homeassistant.components.http import HomeAssistantView
|
|||
from homeassistant.components.frontend import add_manifest_json_key
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
REQUIREMENTS = ['pywebpush==0.6.1', 'PyJWT==1.4.2']
|
||||
# pyelliptic is dependency of pywebpush and 1.5.8 contains a breaking change
|
||||
REQUIREMENTS = ['pywebpush==0.6.1', 'PyJWT==1.4.2', 'pyelliptic==1.5.7']
|
||||
|
||||
DEPENDENCIES = ['frontend']
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from homeassistant.const import (
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.0']
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.1']
|
||||
|
||||
ATTR_PHOTO = 'photo'
|
||||
ATTR_KEYBOARD = 'keyboard'
|
||||
|
@ -47,7 +47,7 @@ def get_service(hass, config, discovery_info=None):
|
|||
api_key = config.get(CONF_API_KEY)
|
||||
bot = telegram.Bot(token=api_key)
|
||||
username = bot.getMe()['username']
|
||||
_LOGGER.info("Telegram bot is '%s'", username)
|
||||
_LOGGER.debug("Telegram bot is '%s'", username)
|
||||
except urllib.error.HTTPError:
|
||||
_LOGGER.error("Please check your access token")
|
||||
return None
|
||||
|
@ -59,7 +59,7 @@ def load_data(url=None, file=None, username=None, password=None):
|
|||
"""Load photo/document into ByteIO/File container from a source."""
|
||||
try:
|
||||
if url is not None:
|
||||
# load photo from url
|
||||
# Load photo from URL
|
||||
if username is not None and password is not None:
|
||||
req = requests.get(url, auth=(username, password), timeout=15)
|
||||
else:
|
||||
|
@ -67,7 +67,7 @@ def load_data(url=None, file=None, username=None, password=None):
|
|||
return io.BytesIO(req.content)
|
||||
|
||||
elif file is not None:
|
||||
# load photo from file
|
||||
# Load photo from file
|
||||
return open(file, "rb")
|
||||
else:
|
||||
_LOGGER.warning("Can't load photo no photo found in params!")
|
||||
|
@ -96,7 +96,7 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
title = kwargs.get(ATTR_TITLE)
|
||||
data = kwargs.get(ATTR_DATA)
|
||||
|
||||
# exists data for send a photo/location
|
||||
# Exists data for send a photo/location
|
||||
if data is not None and ATTR_PHOTO in data:
|
||||
photos = data.get(ATTR_PHOTO, None)
|
||||
photos = photos if isinstance(photos, list) else [photos]
|
||||
|
@ -120,11 +120,10 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
|
||||
parse_mode = telegram.parsemode.ParseMode.MARKDOWN
|
||||
|
||||
# send message
|
||||
# Send message
|
||||
try:
|
||||
self.bot.sendMessage(chat_id=self._chat_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode)
|
||||
self.bot.sendMessage(
|
||||
chat_id=self._chat_id, text=text, parse_mode=parse_mode)
|
||||
except telegram.error.TelegramError:
|
||||
_LOGGER.exception("Error sending message")
|
||||
|
||||
|
@ -135,8 +134,8 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
keyboard = telegram.ReplyKeyboardMarkup([
|
||||
[key.strip() for key in row.split(",")] for row in keys])
|
||||
try:
|
||||
self.bot.sendMessage(chat_id=self._chat_id, text=message,
|
||||
reply_markup=keyboard)
|
||||
self.bot.sendMessage(
|
||||
chat_id=self._chat_id, text=message, reply_markup=keyboard)
|
||||
except telegram.error.TelegramError:
|
||||
_LOGGER.exception("Error sending message")
|
||||
|
||||
|
@ -145,7 +144,7 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
import telegram
|
||||
caption = data.get(ATTR_CAPTION)
|
||||
|
||||
# send photo
|
||||
# Send photo
|
||||
try:
|
||||
photo = load_data(
|
||||
url=data.get(ATTR_URL),
|
||||
|
@ -153,8 +152,8 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
username=data.get(ATTR_USERNAME),
|
||||
password=data.get(ATTR_PASSWORD),
|
||||
)
|
||||
self.bot.sendPhoto(chat_id=self._chat_id,
|
||||
photo=photo, caption=caption)
|
||||
self.bot.sendPhoto(
|
||||
chat_id=self._chat_id, photo=photo, caption=caption)
|
||||
except telegram.error.TelegramError:
|
||||
_LOGGER.exception("Error sending photo")
|
||||
|
||||
|
@ -171,8 +170,8 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
username=data.get(ATTR_USERNAME),
|
||||
password=data.get(ATTR_PASSWORD),
|
||||
)
|
||||
self.bot.sendDocument(chat_id=self._chat_id,
|
||||
document=document, caption=caption)
|
||||
self.bot.sendDocument(
|
||||
chat_id=self._chat_id, document=document, caption=caption)
|
||||
except telegram.error.TelegramError:
|
||||
_LOGGER.exception("Error sending document")
|
||||
|
||||
|
@ -182,9 +181,9 @@ class TelegramNotificationService(BaseNotificationService):
|
|||
latitude = float(gps.get(ATTR_LATITUDE, 0.0))
|
||||
longitude = float(gps.get(ATTR_LONGITUDE, 0.0))
|
||||
|
||||
# send location
|
||||
# Send location
|
||||
try:
|
||||
self.bot.sendLocation(chat_id=self._chat_id,
|
||||
latitude=latitude, longitude=longitude)
|
||||
self.bot.sendLocation(
|
||||
chat_id=self._chat_id, latitude=latitude, longitude=longitude)
|
||||
except telegram.error.TelegramError:
|
||||
_LOGGER.exception("Error sending location")
|
||||
|
|
|
@ -16,7 +16,7 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.0']
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.1']
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ from homeassistant.const import CONF_API_KEY
|
|||
from homeassistant.components.http.util import get_real_ip
|
||||
|
||||
DEPENDENCIES = ['http']
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.0']
|
||||
REQUIREMENTS = ['python-telegram-bot==5.3.1']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ DOMAIN = 'tradfri'
|
|||
CONFIG_FILE = 'tradfri.conf'
|
||||
KEY_CONFIG = 'tradfri_configuring'
|
||||
KEY_GATEWAY = 'tradfri_gateway'
|
||||
REQUIREMENTS = ['pytradfri==1.0']
|
||||
REQUIREMENTS = ['pytradfri==1.1']
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"""Constants used by Home Assistant components."""
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 43
|
||||
PATCH_VERSION = '1'
|
||||
PATCH_VERSION = '2'
|
||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||
REQUIRED_PYTHON_VER = (3, 4, 2)
|
||||
|
|
|
@ -38,7 +38,7 @@ SoCo==0.12
|
|||
TwitterAPI==2.4.5
|
||||
|
||||
# homeassistant.components.device_tracker.automatic
|
||||
aioautomatic==0.1.1
|
||||
aioautomatic==0.2.1
|
||||
|
||||
# homeassistant.components.sensor.dnsip
|
||||
aiodns==1.1.1
|
||||
|
@ -520,6 +520,9 @@ pydroid-ipcam==0.8
|
|||
# homeassistant.components.sensor.ebox
|
||||
pyebox==0.1.0
|
||||
|
||||
# homeassistant.components.notify.html5
|
||||
pyelliptic==1.5.7
|
||||
|
||||
# homeassistant.components.media_player.emby
|
||||
pyemby==1.2
|
||||
|
||||
|
@ -648,7 +651,7 @@ python-synology==0.1.0
|
|||
# homeassistant.components.notify.telegram
|
||||
# homeassistant.components.telegram_bot.polling
|
||||
# homeassistant.components.telegram_bot.webhooks
|
||||
python-telegram-bot==5.3.0
|
||||
python-telegram-bot==5.3.1
|
||||
|
||||
# homeassistant.components.sensor.twitch
|
||||
python-twitch==1.3.0
|
||||
|
@ -663,7 +666,7 @@ python-wink==1.2.3
|
|||
pytrackr==0.0.5
|
||||
|
||||
# homeassistant.components.tradfri
|
||||
pytradfri==1.0
|
||||
pytradfri==1.1
|
||||
|
||||
# homeassistant.components.device_tracker.unifi
|
||||
pyunifi==2.0
|
||||
|
|
|
@ -1,561 +1,184 @@
|
|||
"""The tests for the hassio component."""
|
||||
import asyncio
|
||||
import os
|
||||
from unittest.mock import patch, Mock, MagicMock
|
||||
|
||||
import aiohttp
|
||||
import pytest
|
||||
|
||||
import homeassistant.components.hassio as ho
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, assert_setup_component)
|
||||
from tests.common import mock_coro, mock_http_component_app
|
||||
|
||||
|
||||
class TestHassIOSetup(object):
|
||||
"""Test the hassio component."""
|
||||
@pytest.fixture
|
||||
def hassio_env():
|
||||
"""Fixture to inject hassio env."""
|
||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
||||
patch('homeassistant.components.hassio.HassIO.is_connected',
|
||||
Mock(return_value=mock_coro(True))):
|
||||
yield
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
self.config = {
|
||||
ho.DOMAIN: {},
|
||||
}
|
||||
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
|
||||
def teardown_method(self):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_setup_component(self, aioclient_mock):
|
||||
"""Test setup component."""
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
def test_setup_component_test_service(self, aioclient_mock):
|
||||
"""Test setup component and check if service exits."""
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_HOST_REBOOT)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_HOST_SHUTDOWN)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_HOST_UPDATE)
|
||||
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_SUPERVISOR_UPDATE)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_SUPERVISOR_RELOAD)
|
||||
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_INSTALL)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_UNINSTALL)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_UPDATE)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_START)
|
||||
assert self.hass.services.has_service(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_STOP)
|
||||
|
||||
|
||||
class TestHassIOComponent(object):
|
||||
"""Test the HassIO component."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
self.config = {
|
||||
ho.DOMAIN: {},
|
||||
}
|
||||
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
self.url = "http://127.0.0.1/{}"
|
||||
|
||||
self.error_msg = {
|
||||
'result': 'error',
|
||||
'message': 'Test error',
|
||||
}
|
||||
self.ok_msg = {
|
||||
'result': 'ok',
|
||||
'data': {},
|
||||
}
|
||||
|
||||
def teardown_method(self):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_rest_command_timeout(self, aioclient_mock):
|
||||
"""Call a hassio with timeout."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/update"), exc=asyncio.TimeoutError())
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_UPDATE, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_aiohttp_error(self, aioclient_mock):
|
||||
"""Call a hassio with aiohttp exception."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/update"), exc=aiohttp.ClientError())
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_UPDATE, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_error(self, aioclient_mock):
|
||||
"""Call a hassio with status code 503."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/update"), status=503)
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_UPDATE, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_error_api(self, aioclient_mock):
|
||||
"""Call a hassio with status code 503."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/update"), json=self.error_msg)
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_UPDATE, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_host_reboot(self, aioclient_mock):
|
||||
"""Call a hassio for host reboot."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/reboot"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_REBOOT, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_host_shutdown(self, aioclient_mock):
|
||||
"""Call a hassio for host shutdown."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/shutdown"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(ho.DOMAIN, ho.SERVICE_HOST_SHUTDOWN, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_host_update(self, aioclient_mock):
|
||||
"""Call a hassio for host update."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("host/update"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_HOST_UPDATE, {'version': '0.4'})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][2]['version'] == '0.4'
|
||||
|
||||
def test_rest_command_http_supervisor_update(self, aioclient_mock):
|
||||
"""Call a hassio for supervisor update."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("supervisor/update"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_SUPERVISOR_UPDATE, {'version': '0.4'})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][2]['version'] == '0.4'
|
||||
|
||||
def test_rest_command_http_supervisor_reload(self, aioclient_mock):
|
||||
"""Call a hassio for supervisor reload."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("supervisor/reload"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_SUPERVISOR_RELOAD, {})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_homeassistant_update(self, aioclient_mock):
|
||||
"""Call a hassio for homeassistant update."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("homeassistant/update"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_HOMEASSISTANT_UPDATE, {'version': '0.4'})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][2]['version'] == '0.4'
|
||||
|
||||
def test_rest_command_http_addon_install(self, aioclient_mock):
|
||||
"""Call a hassio for addon install."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("addons/smb_config/install"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_INSTALL, {
|
||||
'addon': 'smb_config',
|
||||
'version': '0.4'
|
||||
})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][2]['version'] == '0.4'
|
||||
|
||||
def test_rest_command_http_addon_uninstall(self, aioclient_mock):
|
||||
"""Call a hassio for addon uninstall."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("addons/smb_config/uninstall"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_UNINSTALL, {
|
||||
'addon': 'smb_config'
|
||||
})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_addon_update(self, aioclient_mock):
|
||||
"""Call a hassio for addon update."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("addons/smb_config/update"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_UPDATE, {
|
||||
'addon': 'smb_config',
|
||||
'version': '0.4'
|
||||
})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert aioclient_mock.mock_calls[-1][2]['version'] == '0.4'
|
||||
|
||||
def test_rest_command_http_addon_start(self, aioclient_mock):
|
||||
"""Call a hassio for addon start."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("addons/smb_config/start"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_START, {
|
||||
'addon': 'smb_config',
|
||||
})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
|
||||
def test_rest_command_http_addon_stop(self, aioclient_mock):
|
||||
"""Call a hassio for addon stop."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json=self.ok_msg)
|
||||
with assert_setup_component(0, ho.DOMAIN):
|
||||
setup_component(self.hass, ho.DOMAIN, self.config)
|
||||
|
||||
aioclient_mock.get(
|
||||
self.url.format("addons/smb_config/stop"), json=self.ok_msg)
|
||||
|
||||
self.hass.services.call(
|
||||
ho.DOMAIN, ho.SERVICE_ADDON_STOP, {
|
||||
'addon': 'smb_config'
|
||||
})
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
@pytest.fixture
|
||||
def hassio_client(hassio_env, hass, test_client):
|
||||
"""Create mock hassio http client."""
|
||||
app = mock_http_component_app(hass)
|
||||
hass.loop.run_until_complete(async_setup_component(hass, 'hassio', {}))
|
||||
hass.http.views['api:hassio'].register(app.router)
|
||||
yield hass.loop.run_until_complete(test_client(app))
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_hassio_host_view(aioclient_mock, hass, test_client):
|
||||
"""Test that it fetches the given url."""
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
result = yield from async_setup_component(hass, ho.DOMAIN, {ho.DOMAIN: {}})
|
||||
assert result, 'Failed to setup hasio'
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/host/info', json={
|
||||
'result': 'ok',
|
||||
'data': {
|
||||
'os': 'resinos',
|
||||
'version': '0.3',
|
||||
'current': '0.4',
|
||||
'level': 16,
|
||||
'hostname': 'test',
|
||||
}
|
||||
})
|
||||
|
||||
resp = yield from client.get('/api/hassio/host')
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert resp.status == 200
|
||||
assert data['os'] == 'resinos'
|
||||
assert data['version'] == '0.3'
|
||||
assert data['current'] == '0.4'
|
||||
assert data['level'] == 16
|
||||
assert data['hostname'] == 'test'
|
||||
def test_fail_setup_without_environ_var(hass):
|
||||
"""Fail setup if no environ variable set."""
|
||||
with patch.dict(os.environ, {}, clear=True):
|
||||
result = yield from async_setup_component(hass, 'hassio', {})
|
||||
assert not result
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_hassio_homeassistant_view(aioclient_mock, hass, test_client):
|
||||
"""Test that it fetches the given url."""
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
result = yield from async_setup_component(hass, ho.DOMAIN, {ho.DOMAIN: {}})
|
||||
assert result, 'Failed to setup hasio'
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/homeassistant/info', json={
|
||||
'result': 'ok',
|
||||
'data': {
|
||||
'version': '0.41',
|
||||
'current': '0.41.1',
|
||||
}
|
||||
})
|
||||
|
||||
resp = yield from client.get('/api/hassio/homeassistant')
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert resp.status == 200
|
||||
assert data['version'] == '0.41'
|
||||
assert data['current'] == '0.41.1'
|
||||
def test_fail_setup_cannot_connect(hass):
|
||||
"""Fail setup if cannot connect."""
|
||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
||||
patch('homeassistant.components.hassio.HassIO.is_connected',
|
||||
Mock(return_value=mock_coro(False))):
|
||||
result = yield from async_setup_component(hass, 'hassio', {})
|
||||
assert not result
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_hassio_supervisor_view(aioclient_mock, hass, test_client):
|
||||
"""Test that it fetches the given url."""
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
def test_invalid_path(hassio_client):
|
||||
"""Test requesting invalid path."""
|
||||
with patch.dict(ho.HASSIO_REST_COMMANDS, {}, clear=True):
|
||||
resp = yield from hassio_client.post('/api/hassio/beer')
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
result = yield from async_setup_component(hass, ho.DOMAIN, {ho.DOMAIN: {}})
|
||||
assert result, 'Failed to setup hasio'
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/supervisor/info', json={
|
||||
'result': 'ok',
|
||||
'data': {
|
||||
'version': '0.3',
|
||||
'current': '0.4',
|
||||
'beta': False,
|
||||
}
|
||||
})
|
||||
|
||||
resp = yield from client.get('/api/hassio/supervisor')
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert resp.status == 200
|
||||
assert data['version'] == '0.3'
|
||||
assert data['current'] == '0.4'
|
||||
assert not data['beta']
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/supervisor/options', json={
|
||||
'result': 'ok',
|
||||
'data': {},
|
||||
})
|
||||
|
||||
resp = yield from client.post('/api/hassio/supervisor', json={
|
||||
'beta': True,
|
||||
})
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 3
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.mock_calls[-1][2]['beta']
|
||||
assert resp.status == 404
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_hassio_network_view(aioclient_mock, hass, test_client):
|
||||
"""Test that it fetches the given url."""
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
def test_invalid_method(hassio_client):
|
||||
"""Test requesting path with invalid method."""
|
||||
with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer': ['POST']}):
|
||||
resp = yield from hassio_client.get('/api/hassio/beer')
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
result = yield from async_setup_component(hass, ho.DOMAIN, {ho.DOMAIN: {}})
|
||||
assert result, 'Failed to setup hasio'
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/network/info', json={
|
||||
'result': 'ok',
|
||||
'data': {
|
||||
'mode': 'dhcp',
|
||||
'ssid': 'my_wlan',
|
||||
'password': '123456',
|
||||
}
|
||||
})
|
||||
|
||||
resp = yield from client.get('/api/hassio/network')
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
assert resp.status == 200
|
||||
assert data['mode'] == 'dhcp'
|
||||
assert data['ssid'] == 'my_wlan'
|
||||
assert data['password'] == '123456'
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/network/options', json={
|
||||
'result': 'ok',
|
||||
'data': {},
|
||||
})
|
||||
|
||||
resp = yield from client.post('/api/hassio/network', json={
|
||||
'mode': 'dhcp',
|
||||
'ssid': 'my_wlan2',
|
||||
'password': '654321',
|
||||
})
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 3
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.mock_calls[-1][2]['ssid'] == 'my_wlan2'
|
||||
assert aioclient_mock.mock_calls[-1][2]['password'] == '654321'
|
||||
assert resp.status == 405
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_async_hassio_addon_view(aioclient_mock, hass, test_client):
|
||||
"""Test that it fetches the given url."""
|
||||
os.environ['HASSIO'] = "127.0.0.1"
|
||||
def test_forward_normal_path(hassio_client):
|
||||
"""Test fetching normal path."""
|
||||
response = MagicMock()
|
||||
response.read.return_value = mock_coro('data')
|
||||
|
||||
aioclient_mock.get("http://127.0.0.1/supervisor/ping", json={
|
||||
'result': 'ok', 'data': {}
|
||||
})
|
||||
result = yield from async_setup_component(hass, ho.DOMAIN, {ho.DOMAIN: {}})
|
||||
assert result, 'Failed to setup hasio'
|
||||
with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer': ['POST']}), \
|
||||
patch('homeassistant.components.hassio.HassIO.command_proxy',
|
||||
Mock(return_value=mock_coro(response))), \
|
||||
patch('homeassistant.components.hassio._create_response') as mresp:
|
||||
mresp.return_value = 'response'
|
||||
resp = yield from hassio_client.post('/api/hassio/beer')
|
||||
|
||||
client = yield from test_client(hass.http.app)
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/addons/smb_config/info', json={
|
||||
'result': 'ok',
|
||||
'data': {
|
||||
'name': 'SMB Config',
|
||||
'state': 'running',
|
||||
'boot': 'auto',
|
||||
'options': {
|
||||
'bla': False,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
resp = yield from client.get('/api/hassio/addons/smb_config')
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 2
|
||||
# Check we got right response
|
||||
assert resp.status == 200
|
||||
assert data['name'] == 'SMB Config'
|
||||
assert data['state'] == 'running'
|
||||
assert data['boot'] == 'auto'
|
||||
assert not data['options']['bla']
|
||||
body = yield from resp.text()
|
||||
assert body == 'response'
|
||||
|
||||
aioclient_mock.get('http://127.0.0.1/addons/smb_config/options', json={
|
||||
'result': 'ok',
|
||||
'data': {},
|
||||
})
|
||||
# Check we forwarded command
|
||||
assert len(mresp.mock_calls) == 1
|
||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||
|
||||
resp = yield from client.post('/api/hassio/addons/smb_config', json={
|
||||
'boot': 'manual',
|
||||
'options': {
|
||||
'bla': True,
|
||||
}
|
||||
})
|
||||
data = yield from resp.json()
|
||||
|
||||
assert len(aioclient_mock.mock_calls) == 3
|
||||
@asyncio.coroutine
|
||||
def test_forward_normal_log_path(hassio_client):
|
||||
"""Test fetching normal log path."""
|
||||
response = MagicMock()
|
||||
response.read.return_value = mock_coro('data')
|
||||
|
||||
with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer/logs': ['GET']}), \
|
||||
patch('homeassistant.components.hassio.HassIO.command_proxy',
|
||||
Mock(return_value=mock_coro(response))), \
|
||||
patch('homeassistant.components.hassio.'
|
||||
'_create_response_log') as mresp:
|
||||
mresp.return_value = 'response'
|
||||
resp = yield from hassio_client.get('/api/hassio/beer/logs')
|
||||
|
||||
# Check we got right response
|
||||
assert resp.status == 200
|
||||
assert aioclient_mock.mock_calls[-1][2]['boot'] == 'manual'
|
||||
assert aioclient_mock.mock_calls[-1][2]['options']['bla']
|
||||
body = yield from resp.text()
|
||||
assert body == 'response'
|
||||
|
||||
# Check we forwarded command
|
||||
assert len(mresp.mock_calls) == 1
|
||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_forward_addon_path(hassio_client):
|
||||
"""Test fetching addon path."""
|
||||
response = MagicMock()
|
||||
response.read.return_value = mock_coro('data')
|
||||
|
||||
with patch.dict(ho.ADDON_REST_COMMANDS, {'install': ['POST']}), \
|
||||
patch('homeassistant.components.hassio.'
|
||||
'HassIO.command_proxy') as proxy_command, \
|
||||
patch('homeassistant.components.hassio._create_response') as mresp:
|
||||
proxy_command.return_value = mock_coro(response)
|
||||
mresp.return_value = 'response'
|
||||
resp = yield from hassio_client.post('/api/hassio/addons/beer/install')
|
||||
|
||||
# Check we got right response
|
||||
assert resp.status == 200
|
||||
body = yield from resp.text()
|
||||
assert body == 'response'
|
||||
|
||||
assert proxy_command.mock_calls[0][1][0] == 'addons/beer/install'
|
||||
|
||||
# Check we forwarded command
|
||||
assert len(mresp.mock_calls) == 1
|
||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_forward_addon_log_path(hassio_client):
|
||||
"""Test fetching addon log path."""
|
||||
response = MagicMock()
|
||||
response.read.return_value = mock_coro('data')
|
||||
|
||||
with patch.dict(ho.ADDON_REST_COMMANDS, {'logs': ['GET']}), \
|
||||
patch('homeassistant.components.hassio.'
|
||||
'HassIO.command_proxy') as proxy_command, \
|
||||
patch('homeassistant.components.hassio.'
|
||||
'_create_response_log') as mresp:
|
||||
proxy_command.return_value = mock_coro(response)
|
||||
mresp.return_value = 'response'
|
||||
resp = yield from hassio_client.get('/api/hassio/addons/beer/logs')
|
||||
|
||||
# Check we got right response
|
||||
assert resp.status == 200
|
||||
body = yield from resp.text()
|
||||
assert body == 'response'
|
||||
|
||||
assert proxy_command.mock_calls[0][1][0] == 'addons/beer/logs'
|
||||
|
||||
# Check we forwarded command
|
||||
assert len(mresp.mock_calls) == 1
|
||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_bad_request_when_wrong_addon_url(hassio_client):
|
||||
"""Test we cannot mess with addon url."""
|
||||
resp = yield from hassio_client.get('/api/hassio/addons/../../info')
|
||||
assert resp.status == 404
|
||||
|
||||
resp = yield from hassio_client.get('/api/hassio/addons/info')
|
||||
assert resp.status == 404
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_bad_gateway_when_cannot_find_supervisor(hassio_client):
|
||||
"""Test we get a bad gateway error if we can't find supervisor."""
|
||||
with patch('homeassistant.components.hassio.async_timeout.timeout',
|
||||
side_effect=asyncio.TimeoutError):
|
||||
resp = yield from hassio_client.get('/api/hassio/addons/test/info')
|
||||
assert resp.status == 502
|
||||
|
|
|
@ -16,14 +16,12 @@ cd build
|
|||
|
||||
if [ -d python-openzwave ]; then
|
||||
cd python-openzwave
|
||||
git pull --recurse-submodules=yes
|
||||
git submodule update --init --recursive
|
||||
git checkout v0.3.3
|
||||
else
|
||||
git clone --branch python3 --recursive --depth 1 https://github.com/OpenZWave/python-openzwave.git
|
||||
git clone --branch v0.3.3 --recursive --depth 1 https://github.com/OpenZWave/python-openzwave.git
|
||||
cd python-openzwave
|
||||
fi
|
||||
|
||||
git checkout python3
|
||||
pip3 install --upgrade cython==0.24.1
|
||||
PYTHON_EXEC=`which python3` make build
|
||||
PYTHON_EXEC=`which python3` make install
|
||||
|
|
Loading…
Reference in New Issue