mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add services to set/update and cancel Nest ETA (#17836)
* Add service to cancel ETA * Update test requirements * Change service name and update logging * Reformat logging to verify structures
This commit is contained in:
parent
52074ee9bb
commit
42fea4fb97
@ -12,10 +12,12 @@ import threading
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.climate import (
|
||||||
|
ATTR_AWAY_MODE, SERVICE_SET_AWAY_MODE)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_STRUCTURE, CONF_FILENAME, CONF_BINARY_SENSORS, CONF_SENSORS,
|
CONF_BINARY_SENSORS, CONF_FILENAME, CONF_MONITORED_CONDITIONS,
|
||||||
CONF_MONITORED_CONDITIONS,
|
CONF_SENSORS, CONF_STRUCTURE, EVENT_HOMEASSISTANT_START,
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
EVENT_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import config_validation as cv
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.dispatcher import dispatcher_send, \
|
from homeassistant.helpers.dispatcher import dispatcher_send, \
|
||||||
@ -25,11 +27,13 @@ from homeassistant.helpers.entity import Entity
|
|||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from . import local_auth
|
from . import local_auth
|
||||||
|
|
||||||
REQUIREMENTS = ['python-nest==4.0.3']
|
REQUIREMENTS = ['python-nest==4.0.4']
|
||||||
|
|
||||||
_CONFIGURING = {}
|
_CONFIGURING = {}
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
SERVICE_CANCEL_ETA = 'cancel_eta'
|
||||||
|
SERVICE_SET_ETA = 'set_eta'
|
||||||
|
|
||||||
DATA_NEST = 'nest'
|
DATA_NEST = 'nest'
|
||||||
DATA_NEST_CONFIG = 'nest_config'
|
DATA_NEST_CONFIG = 'nest_config'
|
||||||
@ -40,27 +44,18 @@ NEST_CONFIG_FILE = 'nest.conf'
|
|||||||
CONF_CLIENT_ID = 'client_id'
|
CONF_CLIENT_ID = 'client_id'
|
||||||
CONF_CLIENT_SECRET = 'client_secret'
|
CONF_CLIENT_SECRET = 'client_secret'
|
||||||
|
|
||||||
ATTR_HOME_MODE = 'home_mode'
|
|
||||||
ATTR_STRUCTURE = 'structure'
|
|
||||||
ATTR_TRIP_ID = 'trip_id'
|
|
||||||
ATTR_ETA = 'eta'
|
ATTR_ETA = 'eta'
|
||||||
ATTR_ETA_WINDOW = 'eta_window'
|
ATTR_ETA_WINDOW = 'eta_window'
|
||||||
|
ATTR_STRUCTURE = 'structure'
|
||||||
|
ATTR_TRIP_ID = 'trip_id'
|
||||||
|
|
||||||
HOME_MODE_AWAY = 'away'
|
AWAY_MODE_AWAY = 'away'
|
||||||
HOME_MODE_HOME = 'home'
|
AWAY_MODE_HOME = 'home'
|
||||||
|
|
||||||
SENSOR_SCHEMA = vol.Schema({
|
SENSOR_SCHEMA = vol.Schema({
|
||||||
vol.Optional(CONF_MONITORED_CONDITIONS): vol.All(cv.ensure_list)
|
vol.Optional(CONF_MONITORED_CONDITIONS): vol.All(cv.ensure_list)
|
||||||
})
|
})
|
||||||
|
|
||||||
AWAY_SCHEMA = vol.Schema({
|
|
||||||
vol.Required(ATTR_HOME_MODE): vol.In([HOME_MODE_AWAY, HOME_MODE_HOME]),
|
|
||||||
vol.Optional(ATTR_STRUCTURE): vol.All(cv.ensure_list, [cv.string]),
|
|
||||||
vol.Optional(ATTR_TRIP_ID): cv.string,
|
|
||||||
vol.Optional(ATTR_ETA): cv.time_period,
|
|
||||||
vol.Optional(ATTR_ETA_WINDOW): cv.time_period
|
|
||||||
})
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema({
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
DOMAIN: vol.Schema({
|
DOMAIN: vol.Schema({
|
||||||
vol.Required(CONF_CLIENT_ID): cv.string,
|
vol.Required(CONF_CLIENT_ID): cv.string,
|
||||||
@ -71,6 +66,23 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
})
|
})
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
SET_AWAY_MODE_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_AWAY_MODE): vol.In([AWAY_MODE_AWAY, AWAY_MODE_HOME]),
|
||||||
|
vol.Optional(ATTR_STRUCTURE): vol.All(cv.ensure_list, [cv.string])
|
||||||
|
})
|
||||||
|
|
||||||
|
SET_ETA_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_ETA): cv.time_period,
|
||||||
|
vol.Optional(ATTR_TRIP_ID): cv.string,
|
||||||
|
vol.Optional(ATTR_ETA_WINDOW): cv.time_period,
|
||||||
|
vol.Optional(ATTR_STRUCTURE): vol.All(cv.ensure_list, [cv.string])
|
||||||
|
})
|
||||||
|
|
||||||
|
CANCEL_ETA_SCHEMA = vol.Schema({
|
||||||
|
vol.Required(ATTR_TRIP_ID): cv.string,
|
||||||
|
vol.Optional(ATTR_STRUCTURE): vol.All(cv.ensure_list, [cv.string])
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def nest_update_event_broker(hass, nest):
|
def nest_update_event_broker(hass, nest):
|
||||||
"""
|
"""
|
||||||
@ -134,40 +146,83 @@ async def async_setup_entry(hass, entry):
|
|||||||
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
|
hass.async_create_task(hass.config_entries.async_forward_entry_setup(
|
||||||
entry, component))
|
entry, component))
|
||||||
|
|
||||||
def set_mode(service):
|
def validate_structures(target_structures):
|
||||||
"""
|
all_structures = [structure.name for structure in nest.structures]
|
||||||
Set the home/away mode for a Nest structure.
|
for target in target_structures:
|
||||||
|
if target not in all_structures:
|
||||||
|
_LOGGER.info("Invalid structure: %s", target)
|
||||||
|
|
||||||
You can set optional eta information when set mode to away.
|
def set_away_mode(service):
|
||||||
"""
|
"""Set the away mode for a Nest structure."""
|
||||||
if ATTR_STRUCTURE in service.data:
|
if ATTR_STRUCTURE in service.data:
|
||||||
structures = service.data[ATTR_STRUCTURE]
|
target_structures = service.data[ATTR_STRUCTURE]
|
||||||
|
validate_structures(target_structures)
|
||||||
else:
|
else:
|
||||||
structures = hass.data[DATA_NEST].local_structure
|
target_structures = hass.data[DATA_NEST].local_structure
|
||||||
|
|
||||||
for structure in nest.structures:
|
for structure in nest.structures:
|
||||||
if structure.name in structures:
|
if structure.name in target_structures:
|
||||||
_LOGGER.info("Setting mode for %s", structure.name)
|
_LOGGER.info("Setting away mode for: %s to: %s",
|
||||||
structure.away = service.data[ATTR_HOME_MODE]
|
structure.name, service.data[ATTR_AWAY_MODE])
|
||||||
|
structure.away = service.data[ATTR_AWAY_MODE]
|
||||||
|
|
||||||
|
def set_eta(service):
|
||||||
|
"""Set away mode to away and include ETA for a Nest structure."""
|
||||||
|
if ATTR_STRUCTURE in service.data:
|
||||||
|
target_structures = service.data[ATTR_STRUCTURE]
|
||||||
|
validate_structures(target_structures)
|
||||||
|
else:
|
||||||
|
target_structures = hass.data[DATA_NEST].local_structure
|
||||||
|
|
||||||
|
for structure in nest.structures:
|
||||||
|
if structure.name in target_structures:
|
||||||
|
if structure.thermostats:
|
||||||
|
_LOGGER.info("Setting away mode for: %s to: %s",
|
||||||
|
structure.name, AWAY_MODE_AWAY)
|
||||||
|
structure.away = AWAY_MODE_AWAY
|
||||||
|
|
||||||
if service.data[ATTR_HOME_MODE] == HOME_MODE_AWAY \
|
|
||||||
and ATTR_ETA in service.data:
|
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
|
trip_id = service.data.get(
|
||||||
|
ATTR_TRIP_ID, "trip_{}".format(int(now.timestamp())))
|
||||||
eta_begin = now + service.data[ATTR_ETA]
|
eta_begin = now + service.data[ATTR_ETA]
|
||||||
eta_window = service.data.get(ATTR_ETA_WINDOW,
|
eta_window = service.data.get(ATTR_ETA_WINDOW,
|
||||||
timedelta(minutes=1))
|
timedelta(minutes=1))
|
||||||
eta_end = eta_begin + eta_window
|
eta_end = eta_begin + eta_window
|
||||||
trip_id = service.data.get(
|
_LOGGER.info("Setting ETA for trip: %s, "
|
||||||
ATTR_TRIP_ID, "trip_{}".format(int(now.timestamp())))
|
"ETA window starts at: %s and ends at: %s",
|
||||||
_LOGGER.info("Setting eta for %s, eta window starts at "
|
trip_id, eta_begin, eta_end)
|
||||||
"%s ends at %s", trip_id, eta_begin, eta_end)
|
|
||||||
structure.set_eta(trip_id, eta_begin, eta_end)
|
structure.set_eta(trip_id, eta_begin, eta_end)
|
||||||
else:
|
else:
|
||||||
_LOGGER.error("Invalid structure %s",
|
_LOGGER.info("No thermostats found in structure: %s, "
|
||||||
service.data[ATTR_STRUCTURE])
|
"unable to set ETA", structure.name)
|
||||||
|
|
||||||
|
def cancel_eta(service):
|
||||||
|
"""Cancel ETA for a Nest structure."""
|
||||||
|
if ATTR_STRUCTURE in service.data:
|
||||||
|
target_structures = service.data[ATTR_STRUCTURE]
|
||||||
|
validate_structures(target_structures)
|
||||||
|
else:
|
||||||
|
target_structures = hass.data[DATA_NEST].local_structure
|
||||||
|
|
||||||
|
for structure in nest.structures:
|
||||||
|
if structure.name in target_structures:
|
||||||
|
if structure.thermostats:
|
||||||
|
trip_id = service.data[ATTR_TRIP_ID]
|
||||||
|
_LOGGER.info("Cancelling ETA for trip: %s", trip_id)
|
||||||
|
structure.cancel_eta(trip_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.info("No thermostats found in structure: %s, "
|
||||||
|
"unable to cancel ETA", structure.name)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, 'set_mode', set_mode, schema=AWAY_SCHEMA)
|
DOMAIN, SERVICE_SET_AWAY_MODE, set_away_mode,
|
||||||
|
schema=SET_AWAY_MODE_SCHEMA)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, SERVICE_SET_ETA, set_eta, schema=SET_ETA_SCHEMA)
|
||||||
|
|
||||||
|
hass.services.async_register(
|
||||||
|
DOMAIN, SERVICE_CANCEL_ETA, cancel_eta, schema=CANCEL_ETA_SCHEMA)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def start_up(event):
|
def start_up(event):
|
||||||
|
@ -1189,7 +1189,7 @@ python-mpd2==1.0.0
|
|||||||
python-mystrom==0.4.4
|
python-mystrom==0.4.4
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
python-nest==4.0.3
|
python-nest==4.0.4
|
||||||
|
|
||||||
# homeassistant.components.device_tracker.nmap_tracker
|
# homeassistant.components.device_tracker.nmap_tracker
|
||||||
python-nmap==0.6.1
|
python-nmap==0.6.1
|
||||||
|
@ -196,7 +196,7 @@ pyspcwebgw==0.4.0
|
|||||||
python-forecastio==1.4.0
|
python-forecastio==1.4.0
|
||||||
|
|
||||||
# homeassistant.components.nest
|
# homeassistant.components.nest
|
||||||
python-nest==4.0.3
|
python-nest==4.0.4
|
||||||
|
|
||||||
# homeassistant.components.sensor.whois
|
# homeassistant.components.sensor.whois
|
||||||
pythonwhois==2.4.3
|
pythonwhois==2.4.3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user