mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
commit
e1b2e00cf6
@ -26,7 +26,7 @@ from homeassistant.helpers.translation import async_get_translations
|
|||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.util.yaml import load_yaml
|
from homeassistant.util.yaml import load_yaml
|
||||||
|
|
||||||
REQUIREMENTS = ['home-assistant-frontend==20180816.1']
|
REQUIREMENTS = ['home-assistant-frontend==20180818.0']
|
||||||
|
|
||||||
DOMAIN = 'frontend'
|
DOMAIN = 'frontend'
|
||||||
DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log',
|
DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log',
|
||||||
|
@ -156,6 +156,8 @@ def async_setup(hass, config):
|
|||||||
DOMAIN, platform_name_slug, async_notify_message,
|
DOMAIN, platform_name_slug, async_notify_message,
|
||||||
schema=NOTIFY_SERVICE_SCHEMA)
|
schema=NOTIFY_SERVICE_SCHEMA)
|
||||||
|
|
||||||
|
hass.config.components.add('{}.{}'.format(DOMAIN, p_type))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
setup_tasks = [async_setup_platform(p_type, p_config) for p_type, p_config
|
setup_tasks = [async_setup_platform(p_type, p_config) for p_type, p_config
|
||||||
|
@ -1,24 +1,35 @@
|
|||||||
"""Schema migration helpers."""
|
"""Schema migration helpers."""
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from .util import session_scope
|
from .util import session_scope
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
PROGRESS_FILE = '.migration_progress'
|
||||||
|
|
||||||
|
|
||||||
def migrate_schema(instance):
|
def migrate_schema(instance):
|
||||||
"""Check if the schema needs to be upgraded."""
|
"""Check if the schema needs to be upgraded."""
|
||||||
from .models import SchemaChanges, SCHEMA_VERSION
|
from .models import SchemaChanges, SCHEMA_VERSION
|
||||||
|
|
||||||
|
progress_path = instance.hass.config.path(PROGRESS_FILE)
|
||||||
|
|
||||||
with session_scope(session=instance.get_session()) as session:
|
with session_scope(session=instance.get_session()) as session:
|
||||||
res = session.query(SchemaChanges).order_by(
|
res = session.query(SchemaChanges).order_by(
|
||||||
SchemaChanges.change_id.desc()).first()
|
SchemaChanges.change_id.desc()).first()
|
||||||
current_version = getattr(res, 'schema_version', None)
|
current_version = getattr(res, 'schema_version', None)
|
||||||
|
|
||||||
if current_version == SCHEMA_VERSION:
|
if current_version == SCHEMA_VERSION:
|
||||||
|
# Clean up if old migration left file
|
||||||
|
if os.path.isfile(progress_path):
|
||||||
|
_LOGGER.warning("Found existing migration file, cleaning up")
|
||||||
|
os.remove(instance.hass.config.path(PROGRESS_FILE))
|
||||||
return
|
return
|
||||||
|
|
||||||
_LOGGER.debug("Database requires upgrade. Schema version: %s",
|
with open(progress_path, 'w'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
_LOGGER.warning("Database requires upgrade. Schema version: %s",
|
||||||
current_version)
|
current_version)
|
||||||
|
|
||||||
if current_version is None:
|
if current_version is None:
|
||||||
@ -26,6 +37,7 @@ def migrate_schema(instance):
|
|||||||
_LOGGER.debug("No schema version found. Inspected version: %s",
|
_LOGGER.debug("No schema version found. Inspected version: %s",
|
||||||
current_version)
|
current_version)
|
||||||
|
|
||||||
|
try:
|
||||||
for version in range(current_version, SCHEMA_VERSION):
|
for version in range(current_version, SCHEMA_VERSION):
|
||||||
new_version = version + 1
|
new_version = version + 1
|
||||||
_LOGGER.info("Upgrading recorder db schema to version %s",
|
_LOGGER.info("Upgrading recorder db schema to version %s",
|
||||||
@ -34,6 +46,8 @@ def migrate_schema(instance):
|
|||||||
session.add(SchemaChanges(schema_version=new_version))
|
session.add(SchemaChanges(schema_version=new_version))
|
||||||
|
|
||||||
_LOGGER.info("Upgrade to version %s done", new_version)
|
_LOGGER.info("Upgrade to version %s done", new_version)
|
||||||
|
finally:
|
||||||
|
os.remove(instance.hass.config.path(PROGRESS_FILE))
|
||||||
|
|
||||||
|
|
||||||
def _create_index(engine, table_name, index_name):
|
def _create_index(engine, table_name, index_name):
|
||||||
@ -117,22 +131,37 @@ def _drop_index(engine, table_name, index_name):
|
|||||||
def _add_columns(engine, table_name, columns_def):
|
def _add_columns(engine, table_name, columns_def):
|
||||||
"""Add columns to a table."""
|
"""Add columns to a table."""
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import OperationalError
|
||||||
|
|
||||||
columns_def = ['ADD COLUMN {}'.format(col_def) for col_def in columns_def]
|
_LOGGER.info("Adding columns %s to table %s. Note: this can take several "
|
||||||
|
"minutes on large databases and slow computers. Please "
|
||||||
|
"be patient!",
|
||||||
|
', '.join(column.split(' ')[0] for column in columns_def),
|
||||||
|
table_name)
|
||||||
|
|
||||||
|
columns_def = ['ADD {}'.format(col_def) for col_def in columns_def]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
engine.execute(text("ALTER TABLE {table} {columns_def}".format(
|
engine.execute(text("ALTER TABLE {table} {columns_def}".format(
|
||||||
table=table_name,
|
table=table_name,
|
||||||
columns_def=', '.join(columns_def))))
|
columns_def=', '.join(columns_def))))
|
||||||
return
|
return
|
||||||
except SQLAlchemyError:
|
except OperationalError:
|
||||||
pass
|
# Some engines support adding all columns at once,
|
||||||
|
# this error is when they dont'
|
||||||
|
_LOGGER.info('Unable to use quick column add. Adding 1 by 1.')
|
||||||
|
|
||||||
for column_def in columns_def:
|
for column_def in columns_def:
|
||||||
|
try:
|
||||||
engine.execute(text("ALTER TABLE {table} {column_def}".format(
|
engine.execute(text("ALTER TABLE {table} {column_def}".format(
|
||||||
table=table_name,
|
table=table_name,
|
||||||
column_def=column_def)))
|
column_def=column_def)))
|
||||||
|
except OperationalError as err:
|
||||||
|
if 'duplicate' not in str(err).lower():
|
||||||
|
raise
|
||||||
|
|
||||||
|
_LOGGER.warning('Column %s already exists on %s, continueing',
|
||||||
|
column_def.split(' ')[1], table_name)
|
||||||
|
|
||||||
|
|
||||||
def _apply_update(engine, new_version, old_version):
|
def _apply_update(engine, new_version, old_version):
|
||||||
|
@ -10,14 +10,14 @@ import voluptuous as vol
|
|||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD)
|
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, CONF_PLATFORM)
|
||||||
from homeassistant.helpers import discovery
|
from homeassistant.helpers import discovery
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
dispatcher_send, async_dispatcher_connect)
|
dispatcher_send, async_dispatcher_connect)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.event import track_time_interval
|
from homeassistant.helpers.event import track_time_interval
|
||||||
|
|
||||||
REQUIREMENTS = ['tuyapy==0.1.2']
|
REQUIREMENTS = ['tuyapy==0.1.3']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -45,7 +45,8 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
DOMAIN: vol.Schema({
|
DOMAIN: vol.Schema({
|
||||||
vol.Required(CONF_PASSWORD): cv.string,
|
vol.Required(CONF_PASSWORD): cv.string,
|
||||||
vol.Required(CONF_USERNAME): cv.string,
|
vol.Required(CONF_USERNAME): cv.string,
|
||||||
vol.Required(CONF_COUNTRYCODE): cv.string
|
vol.Required(CONF_COUNTRYCODE): cv.string,
|
||||||
|
vol.Optional(CONF_PLATFORM, default='tuya'): cv.string,
|
||||||
})
|
})
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
@ -58,9 +59,10 @@ def setup(hass, config):
|
|||||||
username = config[DOMAIN][CONF_USERNAME]
|
username = config[DOMAIN][CONF_USERNAME]
|
||||||
password = config[DOMAIN][CONF_PASSWORD]
|
password = config[DOMAIN][CONF_PASSWORD]
|
||||||
country_code = config[DOMAIN][CONF_COUNTRYCODE]
|
country_code = config[DOMAIN][CONF_COUNTRYCODE]
|
||||||
|
platform = config[DOMAIN][CONF_PLATFORM]
|
||||||
|
|
||||||
hass.data[DATA_TUYA] = tuya
|
hass.data[DATA_TUYA] = tuya
|
||||||
tuya.init(username, password, country_code)
|
tuya.init(username, password, country_code, platform)
|
||||||
hass.data[DOMAIN] = {
|
hass.data[DOMAIN] = {
|
||||||
'entities': {}
|
'entities': {}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"""Constants used by Home Assistant components."""
|
"""Constants used by Home Assistant components."""
|
||||||
MAJOR_VERSION = 0
|
MAJOR_VERSION = 0
|
||||||
MINOR_VERSION = 76
|
MINOR_VERSION = 76
|
||||||
PATCH_VERSION = '0'
|
PATCH_VERSION = '1'
|
||||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
|
||||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
|
||||||
REQUIRED_PYTHON_VER = (3, 5, 3)
|
REQUIRED_PYTHON_VER = (3, 5, 3)
|
||||||
|
@ -432,7 +432,7 @@ hole==0.3.0
|
|||||||
holidays==0.9.6
|
holidays==0.9.6
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20180816.1
|
home-assistant-frontend==20180818.0
|
||||||
|
|
||||||
# homeassistant.components.homekit_controller
|
# homeassistant.components.homekit_controller
|
||||||
# homekit==0.10
|
# homekit==0.10
|
||||||
@ -1389,7 +1389,7 @@ tplink==0.2.1
|
|||||||
transmissionrpc==0.11
|
transmissionrpc==0.11
|
||||||
|
|
||||||
# homeassistant.components.tuya
|
# homeassistant.components.tuya
|
||||||
tuyapy==0.1.2
|
tuyapy==0.1.3
|
||||||
|
|
||||||
# homeassistant.components.twilio
|
# homeassistant.components.twilio
|
||||||
twilio==5.7.0
|
twilio==5.7.0
|
||||||
|
@ -81,7 +81,7 @@ hbmqtt==0.9.2
|
|||||||
holidays==0.9.6
|
holidays==0.9.6
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20180816.1
|
home-assistant-frontend==20180818.0
|
||||||
|
|
||||||
# homeassistant.components.homematicip_cloud
|
# homeassistant.components.homematicip_cloud
|
||||||
homematicip==0.9.8
|
homematicip==0.9.8
|
||||||
|
@ -5,11 +5,11 @@ from unittest.mock import patch, call
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.pool import StaticPool
|
||||||
|
|
||||||
from homeassistant.bootstrap import async_setup_component
|
from homeassistant.bootstrap import async_setup_component
|
||||||
from homeassistant.components.recorder import wait_connection_ready, migration
|
from homeassistant.components.recorder import (
|
||||||
from homeassistant.components.recorder.models import SCHEMA_VERSION
|
wait_connection_ready, migration, const, models)
|
||||||
from homeassistant.components.recorder.const import DATA_INSTANCE
|
|
||||||
from tests.components.recorder import models_original
|
from tests.components.recorder import models_original
|
||||||
|
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ def test_schema_update_calls(hass):
|
|||||||
yield from wait_connection_ready(hass)
|
yield from wait_connection_ready(hass)
|
||||||
|
|
||||||
update.assert_has_calls([
|
update.assert_has_calls([
|
||||||
call(hass.data[DATA_INSTANCE].engine, version+1, 0) for version
|
call(hass.data[const.DATA_INSTANCE].engine, version+1, 0) for version
|
||||||
in range(0, SCHEMA_VERSION)])
|
in range(0, models.SCHEMA_VERSION)])
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
@ -65,3 +65,18 @@ def test_invalid_update():
|
|||||||
"""Test that an invalid new version raises an exception."""
|
"""Test that an invalid new version raises an exception."""
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
migration._apply_update(None, -1, 0)
|
migration._apply_update(None, -1, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_forgiving_add_column():
|
||||||
|
"""Test that add column will continue if column exists."""
|
||||||
|
engine = create_engine(
|
||||||
|
'sqlite://',
|
||||||
|
poolclass=StaticPool
|
||||||
|
)
|
||||||
|
engine.execute('CREATE TABLE hello (id int)')
|
||||||
|
migration._add_columns(engine, 'hello', [
|
||||||
|
'context_id CHARACTER(36)',
|
||||||
|
])
|
||||||
|
migration._add_columns(engine, 'hello', [
|
||||||
|
'context_id CHARACTER(36)',
|
||||||
|
])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user