Is it possible to a to add support for the E-thermostaat | ICY?
2 sites with how they connected the device:
http://www.domoticz.com/wiki/Essent
http://forum.micasaverde.com/index.php/topic,13722.45.html
Is it possible to a to add support for the E-thermostaat | ICY?
2 sites with how they connected the device:
http://www.domoticz.com/wiki/Essent
http://forum.micasaverde.com/index.php/topic,13722.45.html
Hi,
I did i quick first try. It seems to work so far. Just copy the code into
<config_dir>/custom_components/climate/e_thermostaat.py
afterwards edit your config to include:
climate:
- platform: e_thermostaat
username: USERNAME
password: PASSWORD
Here is the code:
import logging
import voluptuous as vol
from homeassistant.components.climate import (
ClimateDevice, PLATFORM_SCHEMA)
from homeassistant.const import (
ATTR_TEMPERATURE,
CONF_USERNAME, CONF_PASSWORD, TEMP_CELSIUS)
import homeassistant.helpers.config_validation as cv
import requests
_LOGGER = logging.getLogger(__name__)
URL_LOGIN = "https://portal.icy.nl/login"
URL_DATA = "https://portal.icy.nl/data"
DEFAULT_NAME = 'E-Thermostaat'
CONF_NAME = 'name'
CONF_TARGET_TEMP = 'target_temp'
CONF_AWAY_TEMPERATURE = 'away_temperature'
CONF_COMFORT_TEMPERATURE = 'comfort_temperature'
CONF_UUID = 'uuid'
DEFAULT_AWAY_TEMPERATURE = 14
DEFAULT_COMFORT_TEMPERATURE = 19
# Values reverse engineered
HOME = 32
AWAY = 64
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_AWAY_TEMPERATURE, default=DEFAULT_AWAY_TEMPERATURE):
vol.Coerce(float),
vol.Optional(CONF_COMFORT_TEMPERATURE, default=DEFAULT_COMFORT_TEMPERATURE):
vol.Coerce(float),
vol.Optional(CONF_TARGET_TEMP): vol.Coerce(float),
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the e thermostat."""
name = config.get(CONF_NAME)
target_temp = config.get(CONF_TARGET_TEMP)
away_temp = config.get(CONF_AWAY_TEMPERATURE)
comfort_temp = config.get(CONF_COMFORT_TEMPERATURE)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
add_devices([EThermostaat(
name, username, password, away_temp, comfort_temp,
target_temp)])
class EThermostaat(ClimateDevice):
"""Representation of a GenericThermostat device."""
def __init__(self, name, username, password, away_temp, comfort_temp, target_temp):
"""Initialize the thermostat."""
self._name = name
self._username = username
self._password = password
self._comfort_temp = comfort_temp
self._away = False
self._away_temp = away_temp
self._current_temperature = None
self._target_temperature = target_temp
self._old_conf = None
self.update()
@property
def name(self):
"""Return the name of the honeywell, if any."""
return self._name
@property
def temperature_unit(self):
"""Return the unit of measurement."""
return TEMP_CELSIUS
@property
def current_temperature(self):
"""Return the current temperature."""
return self._current_temperature
@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._target_temperature
def set_temperature(self, **kwargs):
"""Set new target temperature."""
temperature = kwargs.get(ATTR_TEMPERATURE)
if temperature is None:
return
self._set_temperature(temperature)
def _set_temperature(self, temperature, home=True):
token, uid = self.get_token_and_uid()
header = {'Session-token': token} # , 'content-type': 'application/json'}
payload_new = [("uid", uid),
("temperature1", temperature)]
if self._old_conf is not None:
if home:
payload_new.append(("configuration[]", HOME))
else:
payload_new.append(("configuration[]", AWAY))
for i in self._old_conf[1:]:
payload_new.append(('configuration[]', i))
r = requests.post(URL_DATA, data=payload_new, headers=header)
try:
if not r.json()['status']['code'] == 200:
_LOGGER.error("Could not set temperature")
except Exception as e:
_LOGGER.error(e)
return
def get_token_and_uid(self):
payload = {'username': self._username, 'password': self._password}
with requests.Session() as s:
s.get(URL_LOGIN)
r = s.post(URL_LOGIN, data=payload)
try:
res = r.json()
token = res['token']
uid = res['serialthermostat1']
except Exception as e:
_LOGGER.error("Could not get token and uid: %s" % e)
return None
return token, uid
def _get_data(self):
token, uid = self.get_token_and_uid()
header = {'Session-token': token}
payload = {'username': self._username, 'password': self._password}
r = requests.get(URL_DATA, data=payload, headers=header)
try:
data = r.json()
self._target_temperature = data['temperature1']
self._current_temperature = data['temperature2']
self._old_conf = data['configuration']
if self._old_conf[0] >= AWAY:
self._away = True
else:
self._away = False
except Exception as e:
_LOGGER.error("Could not get data from e-Thermostaat: %s" % e)
@property
def is_away_mode_on(self):
"""Return true if away mode is on."""
return self._away
def turn_away_mode_on(self):
"""Turn away on.
"""
self._away = True
self._set_temperature(self._away_temp, home=False)
def turn_away_mode_off(self):
"""Turn away off."""
self._away = False
self._set_temperature(self._comfort_temp, home=True)
def update(self):
"""Get the latest data."""
self._get_data()
I started a pull request here:
Great that you have done some work on the implementation. Are you able to validate the if it works or do you need some help there? Iām actually running Domoticz since some items where not supported by Home Assistant. If this implementation will work it will be more likely
I am running it at the moment. So far it seems to work nicely. But you are welcome to test it also. I am also always changing to comfort mode when I change the temperature (this is something domoticz did not do), so it automatically switches back to away mode after the pre set time.
I followed the instruction as mentioned and it works! Do you know when the pull request will be implemented?
Can you also implement the the quick setting as mentioned by the app/site?
Hi,
I have closed the pull request at the moment, since I do not have time to implement it nicely (and they are pretty strict in quality control for Home Assistant, which is a good thing, but makes it a bit harder to get new stuff merged). My plan is to implement the other operation modes and then reopen the pull request. I am not sure when I will find time for it. And apparently we are the only two users at the moment
Away/Comfort mode is already working. If it is in comfort mode, and you switch the button underneath the target temperature slider it will set the thermostat to away mode and set the away temperature (default 14 degrees).
You can set the temperatures that it will set via the yaml configuration file:
climate:
- platform: e_thermostaat
username: USERNAME
password: PASSWORD
away_temperature: 14
comfort_temperature: 19
Thanks for adding support for the E-thermostaat. I installed it today and it works.
This will make three users ;). Love to see the last extra bits and pushed in the main software.
I had some time this weekend and did some updates:
One additional optional setting to above is now:
saving_temperature: 10
It behaves now like this:
I was considering to set the temperature always to the comfort_temp if you come from lang-weg or bespaar-stand (similar to the behaviour in the app). Do you think that would make sense?
The updated version can be found here:
The easiest to test is to use it as a ācustom_componentā as above. Just overwrite the old file.
If you find any bugs and weird things let me know.
Thanks for implementing the missing parts. I updated my HA and will test the updates.
Really great news.
I have been able to test is for a while now and it works really great.
It does in deed make sense o set the temperature always to the comfort_temp if you come from lang-weg or bespaar-stand (similar to the behaviour in the app).
Thanks for letting me know. I am not sure how the interaction might feel, since the state is not updated immediately by the web-interface.
So it might be like
You are in bespaar-stand -> want to set the temperature to 20 degrees, but comfort_temp is on 19
you select 20 degrees with the slider and it jumps back to 19 degrees.
Thatās why I also did not implement it yet.
But I am just thinking, if the set value its above the comfort_temp, i should just take that. From the top of my head it should be this (beware untested):
def _set_temperature(self, temperature, mode_int=None):
"""Set new target temperature, via URL commands."""
payload_new = [("temperature1", temperature)]
if self._old_conf is not None:
# overwrite first int to set mode
if mode_int is not None:
payload_new.append(("configuration[]", mode_int))
elif self._current_operation_mode \
and self._current_operation_mode == STATE_FIXED_TEMP:
payload_new.append(("configuration[]", FIXED_TEMP))
else:
### NEW: Set temp to max of comfort_temp or requested temp
if self._current_operation_mode and self.is_away_mode_on:
payload_new[0][1] = max(temperature, self._comfort_temp)
### END
payload_new.append(("configuration[]", COMFORT))
mode_int = payload_new[1][1]
# append old config not to overwrite old settings
for i in self._old_conf[1:]:
payload_new.append(('configuration[]', i))
if self._request_with_retry(URL_DATA, payload_new, request_type='post'):
# update state values since we assume update was successful
self._current_operation_mode = self.map_int_to_operation_mode(mode_int)
self._target_temperature = temperature
# self.schedule_update_ha_state(force_refresh=True)
Just change the _set_temperature
method in your file to match this and be aware of the spacing.
Nice. I will give it a go when I get something else fixed.
The slider you mentioned I donāt have that. I donāt really mind because i think the up and down arrows in the interface is more useful. I use a Mac and I donāt see a slider with safari or firefox and I donāt have the ugly scroll slider on the right ;). HA version is 0.40.1.
hi i am new to home assistant and i have a question where do i copy the code .
thanx
See the second post:
thank you
had to create the folder works great thank you for the great work.
Thanks for this custom component! It works great
@daenny do you still have plans to add this as a pull request to Home Assistant?
If someone helps with the documentation, I would be willing to add it again. However, at the moment I am pretty busy with other projects and moving to a new house where I cannot use the ICY anymore, so if someone else wants to take the lead with the pull request, just go ahead and use/change my code as needed.
I can help with the documentation (maybe even some help with the pull request of the component, but still fairly new to Home Assistant). But I understand this is not on your priority list and this custom component is working fine as it is .
Great work on the component! This saves me a lot of time trying to implement it myself
After an update of hass.io to 0.59.1 this afternoon the component doesnāt show up anymore.
I can find the following error mentioning climate. In the standard log it only mentions āsetting up climate.e_thermostaatā (with debugging enabled).
Tue Dec 05 2017 19:14:38 GMT+0100 (West-Europa (standaardtijd))
Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/lib/python3.6/asyncio/tasks.py", line 179, in _step
result = coro.send(None)
File "/usr/lib/python3.6/site-packages/homeassistant/helpers/entity_component.py", line 399, in async_process_entity
new_entity, self, update_before_add=update_before_add
File "/usr/lib/python3.6/site-packages/homeassistant/helpers/entity_component.py", line 247, in async_add_entity
yield from entity.async_update_ha_state()
File "/usr/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 231, in async_update_ha_state
attr)
File "/usr/lib/python3.6/site-packages/homeassistant/helpers/entity.py", line 333, in _attr_setter
value = getattr(self, name)
File "/usr/lib/python3.6/site-packages/homeassistant/components/climate/__init__.py", line 736, in supported_features
raise NotImplementedError()
NotImplementedError
Any idea what causes this?
Thanks!