1
0
mirror of https://github.com/USA-RedDragon/badnest.git synced 2025-01-31 08:00:27 +00:00

Implemented custom service for hot water boosting and hot water sensor

This commit is contained in:
Charles Garner 2020-03-20 04:22:34 +00:00
parent 7ab48d968e
commit 40af195cb6
6 changed files with 150 additions and 2 deletions

View File

@ -1,10 +1,22 @@
"""The example integration.""" """The example integration."""
import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from datetime import datetime
import time
from homeassistant.util.dt import utcnow
from homeassistant.const import (
ATTR_ENTITY_ID
)
from .api import NestAPI from .api import NestAPI
from .const import DOMAIN, CONF_ISSUE_TOKEN, CONF_COOKIE, CONF_USER_ID, CONF_ACCESS_TOKEN, CONF_REGION from .const import DOMAIN, CONF_ISSUE_TOKEN, CONF_COOKIE, CONF_USER_ID, CONF_ACCESS_TOKEN, CONF_REGION
SERVICE_BOOST_HOT_WATER = "boost_hot_water"
ATTR_TIME_PERIOD = "time_period"
ATTR_MODE = "on_off"
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
DOMAIN: vol.All( DOMAIN: vol.All(
@ -23,9 +35,36 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA, extra=vol.ALLOW_EXTRA,
) )
BOOST_HOT_WATER_SCHEMA = vol.Schema(
{
vol.Required(ATTR_ENTITY_ID): cv.entity_id,
vol.Optional(ATTR_TIME_PERIOD, default=30): cv.positive_int,
vol.Required(ATTR_MODE): cv.string,
}
)
_LOGGER = logging.getLogger(__name__)
def setup(hass, config): def setup(hass, config):
"""Set up the badnest component.""" """Set up the badnest component."""
def hot_water_boost(service):
"""Handle the service call."""
node_id = hass.data.get(service.data[ATTR_ENTITY_ID])
if not node_id:
# log or raise error
_LOGGER.error("Cannot boost entity id entered")
return
minutes = service.data[ATTR_TIME_PERIOD]
timeToEnd = int(time.mktime(datetime.timetuple(utcnow()))+(minutes*60))
mode = service.data[ATTR_MODE]
if mode == "on":
api.hotwater_set_boost(node_id, timeToEnd)
elif mode == "off":
api.hotwater_set_boost(node_id, 0)
if config.get(DOMAIN) is not None: if config.get(DOMAIN) is not None:
user_id = config[DOMAIN].get(CONF_USER_ID) user_id = config[DOMAIN].get(CONF_USER_ID)
access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN) access_token = config[DOMAIN].get(CONF_ACCESS_TOKEN)
@ -49,4 +88,13 @@ def setup(hass, config):
), ),
} }
api = hass.data[DOMAIN]['api']
hass.services.register(
DOMAIN,
SERVICE_BOOST_HOT_WATER,
hot_water_boost,
schema=BOOST_HOT_WATER_SCHEMA,
)
return True return True

View File

@ -48,6 +48,7 @@ class NestAPI():
self.cameras = [] self.cameras = []
self.thermostats = [] self.thermostats = []
self.temperature_sensors = [] self.temperature_sensors = []
self.hotwatercontrollers = []
self.protects = [] self.protects = []
self.login() self.login()
self._get_devices() self._get_devices()
@ -153,6 +154,7 @@ class NestAPI():
sn = bucket.replace('device.', '') sn = bucket.replace('device.', '')
self.thermostats.append(sn) self.thermostats.append(sn)
self.temperature_sensors.append(sn) self.temperature_sensors.append(sn)
self.hotwatercontrollers.append(sn)
self.device_data[sn] = {} self.device_data[sn] = {}
self.cameras = self._get_cameras() self.cameras = self._get_cameras()
@ -270,6 +272,9 @@ class NestAPI():
self.device_data[sn]['eco'] = True self.device_data[sn]['eco'] = True
else: else:
self.device_data[sn]['eco'] = False self.device_data[sn]['eco'] = False
# Hot water
self.device_data[sn]['hot_water_active'] = \
sensor_data["hot_water_active"]
# Protect # Protect
elif bucket["object_key"].startswith( elif bucket["object_key"].startswith(
f"topaz.{sn}"): f"topaz.{sn}"):
@ -484,6 +489,34 @@ class NestAPI():
self.login() self.login()
self.thermostat_set_eco_mode(device_id, state) self.thermostat_set_eco_mode(device_id, state)
def hotwater_set_boost(self, device_id, time):
if device_id not in self.hotwatercontrollers:
return
try:
self._session.post(
f"{self._czfe_url}/v5/put",
json={
"objects": [
{
"object_key": f'device.{device_id}',
"op": "MERGE",
"value": {"hot_water_boost_time_to_end": time},
}
]
},
headers={"Authorization": f"Basic {self._access_token}"},
)
except requests.exceptions.RequestException as e:
_LOGGER.error(e)
_LOGGER.error('Failed to boost hot water, trying again')
self.hotwater_set_boost(device_id, time)
except KeyError:
_LOGGER.debug('Failed to boost hot water, trying to log in again')
self.login()
self.hotwater_set_boost(device_id, time)
def _camera_set_properties(self, device_id, property, value): def _camera_set_properties(self, device_id, property, value):
if device_id not in self.cameras: if device_id not in self.cameras:
return return

View File

@ -117,6 +117,9 @@ class NestClimate(ClimateDevice):
if self.device.device_data[device_id]['target_humidity_enabled']: if self.device.device_data[device_id]['target_humidity_enabled']:
self._support_flags = self._support_flags | SUPPORT_TARGET_HUMIDITY self._support_flags = self._support_flags | SUPPORT_TARGET_HUMIDITY
async def async_added_to_hass(self):
"""When entity is added to Home Assistant."""
self.hass.data[self.entity_id] = self.device_id
@property @property
def unique_id(self): def unique_id(self):

View File

@ -32,7 +32,14 @@ async def async_setup_platform(hass,
_LOGGER.info(f"Adding nest temp sensor uuid: {sensor}") _LOGGER.info(f"Adding nest temp sensor uuid: {sensor}")
temperature_sensors.append(NestTemperatureSensor(sensor, api)) temperature_sensors.append(NestTemperatureSensor(sensor, api))
hw_sensors = []
_LOGGER.info("Adding hot water sensors")
for hotwater in api['hotwatercontrollers']:
_LOGGER.info(f"Adding nest hot water sensor uuid: {hotwater}")
hw_sensors.append(NestHWSensor(hotwater, api))
async_add_entities(temperature_sensors) async_add_entities(temperature_sensors)
async_add_entities(hw_sensors)
protect_sensors = [] protect_sensors = []
_LOGGER.info("Adding protect sensors") _LOGGER.info("Adding protect sensors")
@ -92,6 +99,43 @@ class NestTemperatureSensor(Entity):
} }
class NestHWSensor(Entity):
"""Implementation of the Nest Hot Water sensor."""
def __init__(self, device_id, api):
"""Initialize the sensor."""
self._name = "Nest Hot Water Sensor"
self.device_id = device_id
self.device = api
@property
def unique_id(self):
"""Return an unique ID."""
return self.device_id + '_hw'
@property
def name(self):
"""Return the name of the sensor."""
return "{0} Hot Water".format(self.device.device_data[self.device_id]['name'])
@property
def icon(self):
"""Return the icon to use in the frontend."""
return "mdi:water"
@property
def state(self):
"""Return the state of the sensor."""
if self.device.device_data[self.device_id]['hot_water_active']:
return 'On'
else:
return 'Off'
def update(self):
"""Get the latest data from the Protect and updates the states."""
self.device.update()
class NestProtectSensor(Entity): class NestProtectSensor(Entity):
"""Implementation of the Nest Protect sensor.""" """Implementation of the Nest Protect sensor."""

View File

@ -0,0 +1,11 @@
boost_hot_water:
description:
"Set the boost mode ON or OFF defining the period of time for the boost."
fields:
entity_id:
{
description: Enter the entity_id for the device reuired to set the boost mode.,
example: "water_heater.hot_water",
}
time_period: { description: Set the time period in minutes for the boost., example: 30}
on_off: { description: Set the boost function on or off., example: "on" }

View File

@ -14,6 +14,7 @@ This isn't an advertised or public API, it's still better than web scraping, but
- Nest Thermostat support - Nest Thermostat support
- Nest Thermostat Sensor support - Nest Thermostat Sensor support
- Nest Camera support - Nest Camera support
- Nest Hot Water support (UK)
## Drawbacks ## Drawbacks
@ -28,6 +29,14 @@ The camera's region is one of `us` or `eu` depending on your region.
If you're not in the US or EU, you should be able to add your If you're not in the US or EU, you should be able to add your
two-character country code, and it should work. two-character country code, and it should work.
## Hot Water Control (UK)
Hot water boosting is controlled through the `badnest.boost_hot_water` service.
The required variables are:
`entity_id`
`time_period` - integer in minutes
`on_off`
### Example configuration.yaml - When you're not using the Google Auth Login ### Example configuration.yaml - When you're not using the Google Auth Login
Google recently introduced reCAPTCHA when logging to Nest. That means username Google recently introduced reCAPTCHA when logging to Nest. That means username