Integration for Watts Vision Smart Home System

Sorry for not noticing your question earlier.

Which firmware were they talking about? I noticed when I got the unit it was loaded with 3.07 While the latest on their website was 3.06

Thatā€™s weird: I see here that the latest version is 3.09: Software Watts Vision Central Unit | capacitive screen 3.09 (wattswater.nl)

I just installed this update; so I upgraded from 3.07 to 3.09. Does anybody know where the change log can be found?

is it possible to change the project import to meet the new requirements for a HACS repository?

Also upgraded the Central Unit to version 3.09 last weekend

Did you notice any changes?

I hope they are still working on this. The whole system is really unstable in my eyes. Iā€™m actually wondering how this is v3 already. It feels more like an Alpha version

Some problems Iā€™m encountering:

  • Cloud didnā€™t work at first
  • The Android app doesnā€™t work on my phone (Even though it looks like the website ported to android)
  • Changes made through the web app sometimes take multiple attempts before they propagate

Although everything was running fine for a few months, since mid of May, the integration stopped working.
For some reason the log files are showing:

Source: custom_components/_watts_vision/watts_api.py:109
Integration: _watts_vision
First occurred: 2:49:55 PM (1 occurrences)
Last logged: 2:49:55 PM

Something went wrong fetching user data: 401

After inspecting the netowrk tab of https://smarthome.wattselectronics.com/ i found that the smarthome_id was changed from a four digit number into a text string.
Although iā€™ve adjusted it in the config, the error remains the sameā€¦

When trying to connect to https://smarthome.wattselectronics.com/api/v0.1/human/user/read/ using postman or browser i get the following error:

{
    "code": {
        "code": "7",
        "key": "ERR_DB",
        "value": "Failure to connect to database"
    },
    "data": {}
}

Contacted Watts support for help, but they really donā€™t understand how we managed to get this connection at allā€¦?
They did say that thwey were working on an integration layer, but iā€™ve heard that a year ago as well.
Does anyone have any suggestion (username and psw have been checked of course)?

The API changed. I made some quick fixes a couple of days ago. In my own environment itā€™s working again.

Good Evening,
I have a Wats themostat for my flooring in my master bathroom. Any chance this will work with it as well? How do I set it up?

Has anyone noticed a change to the API in the last week?

I started seeing random / unknown devices pop up in the watts responses, breaking the hass integration.

Iā€™ve noticed it too. Iā€™ve deleted my main panel since it was missing a thermostat and somehow managed to add a wall plug. All the while changing the language to something slavic/russion.

After re-adding it, all looked like normal. But iā€™m seeing an increase in the amount of coupled devices in the api responses. It is now at 14 while I only have 5. (6 including the panel) The web view still looks normal though.

Hi Paul, How did you get it to work again?

After reinstalling the plugin, iā€™m not getting it up to running again.
The entities are not being created and the logs throw in the following error:

Error while setting up watts_vision platform for climate Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 281, in _async_setup_platform await asyncio.shield(task) File "/config/custom_components/_watts_vision/climate.py", line 59, in async_setup_entry for y in range(len(smartHomes)): TypeError: object of type 'NoneType' has no len()

Hi All,

Iā€™m currently figuring everything out. It is a shame there is not a fully supported home assistant integration yet.

Iā€™m trying to get the one from paul working. But it only refreshes everything when i restart home assistant. After that, no updates. Anyone else having this problem?

I updated my AppDeamon script so that the temperature can be set as well. This solution works without problems. You only need install the AppDeamon add-on and set up the helpers and sensors to make it work.

AppDeamon configuration (apps.yaml):

get_watts_vision_status:
  module: get_watts_vision_status
  class: GetWattsVisionStatus
  username: !secret watts_vision_username
  password: !secret watts_vision_password
  client_id: !secret watts_vision_client_id
  url: !secret watts_vision_url
  smarthome_id: !secret watts_vision_smarthome_id

set_watts_vision_temperature:
  module: set_watts_vision_temperature
  class: SetWattsVisionTemperature
  username: !secret watts_vision_username
  password: !secret watts_vision_password
  client_id: !secret watts_vision_client_id
  url: !secret watts_vision_url
  smarthome_id: !secret watts_vision_smarthome_id

Read temperatures (get_watts_vision_status.py):

import appdaemon.plugins.hass.hassapi as hass
import requests

class GetWattsVisionStatus(hass.Hass):
  def initialize(self):
    self.run_every(self.get_status, "now", 60)

  def fetch_token(self):
    access_token = ''
    username = self.args['username']
    password = self.args['password']
    client_id = self.args['client_id']
    url = '{}/auth/realms/watts/protocol/openid-connect/token'.format(self.args['url'])
    payload = { 'grant_type': 'password', 'username': username, 'password': password, 'client_id': client_id }
    request = requests.post(url = url, data = payload)
    request_status_code = request.status_code
    if request_status_code == 200:
      access_token = request.json()['access_token']
    else:
      self.log('Fetching access token was unsuccessful.')
    return access_token

  def calculate_fahrenheit_to_celsius_degrees(self, temperature_in_fahrenheit):
    return round((float (temperature_in_fahrenheit) / 10 - 32) / 1.8, 2)

  def set_temperature(self, zone, helper, data):
    temperature_in_fahrenheit = data[zone]['devices'][0]['temperature_air']
    temperature = self.calculate_fahrenheit_to_celsius_degrees(temperature_in_fahrenheit)
    self.set_value('input_number.{}'.format(helper), temperature)
    gv_mode = data[zone]['devices'][0]['gv_mode']
    match gv_mode:
      case '4':
        set_temperature_in_fahrenheit = data[zone]['devices'][0]['consigne_boost']
      case '11':
        set_temperature_in_fahrenheit = data[zone]['devices'][0]['consigne_eco']
      case _:
        set_temperature_in_fahrenheit = data[zone]['devices'][0]['consigne_confort']
    set_temperature = self.calculate_fahrenheit_to_celsius_degrees(set_temperature_in_fahrenheit)
    self.set_value('input_number.set_{}'.format(helper), round(set_temperature * 2) / 2)

  def set_heating_status(self, zone, sensor, data):
    heating_up = data[zone]['devices'][0]['heating_up']
    self.set_state('binary_sensor.{}'.format(sensor), state = 'on' if heating_up == '1' else 'off')

  def get_status(self, kwargs):
    access_token = self.fetch_token()
    if access_token != '':
      smarthome_id = self.args['smarthome_id']
      url = '{}/api/v0.1/human/smarthome/read'.format(self.args['url'])
      headers = { 'Authorization': 'Bearer {}'.format(access_token) }
      payload = { 'token': 'true', 'smarthome_id': smarthome_id, 'lang': 'nl_NL' }
      request = requests.post(url = url, headers = headers, data = payload)
      request_status_code = request.status_code
      if request_status_code == 200:
        result = request.json()
        code = result['code']['code']
        if code == '1':
          data_zones = result['data']['zones']
          self.set_temperature(zone= 0, helper = 'temperature_living_room', data = data_zones)
          self.set_temperature(zone= 1, helper = 'temperature_study_room', data = data_zones)
          self.set_temperature(zone= 2, helper = 'temperature_guest_room', data = data_zones)
          self.set_temperature(zone= 3, helper = 'temperature_bath_room', data = data_zones)
          self.set_temperature(zone= 4, helper = 'temperature_bed_room', data = data_zones)
          self.set_temperature(zone= 5, helper = 'temperature_attic_room', data = data_zones)
          self.set_temperature(zone= 6, helper = 'temperature_laundry_room', data = data_zones)
          self.set_heating_status(zone= 0, sensor = 'living_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 1, sensor = 'study_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 2, sensor = 'guest_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 3, sensor = 'bath_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 4, sensor = 'bed_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 5, sensor = 'attic_room_heating_up', data = data_zones)
          self.set_heating_status(zone= 6, sensor = 'laundry_room_heating_up', data = data_zones)
        else:
          error_message = result['code']['value']
          self.log('Reading temperature was unsuccessful: {}'.format(error_message))
      else:
        self.log('Reading temperature was unsuccessful.')

Update temperatures (set_watts_vision_temperature.py):

import appdaemon.plugins.hass.hassapi as hass
import requests

class SetWattsVisionTemperature(hass.Hass):
  def initialize(self):
    self.listen_state(self.value_changed, 'input_number.set_temperature_living_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_study_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_guest_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_bath_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_bed_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_attic_room')
    self.listen_state(self.value_changed, 'input_number.set_temperature_laundry_room')

  def fetch_token(self):
    access_token = ''
    username = self.args['username']
    password = self.args['password']
    client_id = self.args['client_id']
    url = '{}/auth/realms/watts/protocol/openid-connect/token'.format(self.args['url'])
    payload = { 'grant_type': 'password', 'username': username, 'password': password, 'client_id': client_id }
    request = requests.post(url = url, data = payload)
    request_status_code = request.status_code
    if request_status_code == 200:
      access_token = request.json()['access_token']
    else:
      self.log('Fetching access token was unsuccessful.')
    return access_token

  def calculate_celsius_degrees_to_fahrenheit(self, temperature_in_celsius_degrees):
    return int((float(temperature_in_celsius_degrees) * 1.8 + 32) * 10)

  def update_temperature(self, access_token, entity, temperature_in_celsius_degrees):
    temperature_in_fahrenheit = self.calculate_celsius_degrees_to_fahrenheit(temperature_in_celsius_degrees)
    smarthome_id = self.args['smarthome_id']
    url = '{}/api/v0.1/human/query/push/'.format(self.args['url'])
    headers = { 'Authorization': 'Bearer {}'.format(access_token) }
    payload = { 'token': 'true', 'context': 1, 'smarthome_id': smarthome_id, 'query[id_device]': self.device_id, 'query[time_boost]': 0, 'query[consigne_confort]': temperature_in_fahrenheit, 'query[consigne_manuel]': temperature_in_fahrenheit, 'query[gv_mode]': 0, 'query[nv_mode]': 0, 'peremption': 15000, 'lang': 'nl_NL' }
    request = requests.post(url = url, headers = headers, data = payload)
    request_status_code = request.status_code
    if request_status_code == 200:
      result = request.json()
      code = result['code']['code']
      if code == '8':
        self.log('Updating temperature of {} to {} was successful.'.format(entity, temperature_in_celsius_degrees))
      else:
        error_message = result['code']['value']
        self.log('Updating temperature of {} to {} was unsuccessful. {}'.format(entity, temperature_in_celsius_degrees, error_message))
    else:
      self.log('Updating temperature of {} to {} was unsuccessful.'.format(entity, temperature_in_celsius_degrees))

  def value_changed(self, entity, attribute, old, new, kwargs):
    access_token = self.fetch_token()
    if access_token != '':
      match entity:
        case 'input_number.set_temperature_living_room':
          self.device_id = 'C001-000'
        case 'input_number.set_temperature_study_room':
          self.device_id = 'C002-001'
        case 'input_number.set_temperature_guest_room':
          self.device_id = 'C003-002'
        case 'input_number.set_temperature_bath_room':
          self.device_id = 'C004-003'
        case 'input_number.set_temperature_bed_room':
          self.device_id = 'C005-004'
        case 'input_number.set_temperature_laundry_room':
          self.device_id = 'C006-005'
        case 'input_number.set_temperature_attic_room':
          self.device_id = 'C007-006'
      self.update_temperature(access_token, entity, new)

Did you use the appdeamon instead of the plugin or aside?
Where did you store the 2 py scripts?

Yes, this is by using the AppDeamon add-on instead of using the HACS plugin. The two scripts are stored in the apps subfolder of the appdeamon directory.

I am pretty new to HA and learning on the way. Managed to add many devices at home alreay:)

I have a Watts vision system for a few years now.
From what I read above there seems to be some integration in HA?
And I see a solution with a thing called appdeamon.
Which one should I use?
I did install the app deamon
I have no clue where to store the scripts suggested above.(in the appdeamon folder I see an apps.yaml, there is hello world. Must I copy the scripts in that yaml file?
And @witterholt how did you create all those helpers?

I created the helpers in Home Assistant. Just consult the documentation how to do this.

Ok Thanks.
And the the scripts suggested above.(in the appdeamon folder I see an apps.yaml), there is default a hello world. Must I just copy the scripts in that yaml file? and ofcourse edit the login data?

Yes, you should do that.

1 Like

@witterholt or others that got it working I feel a bit dummy and get confused when trying to get this in my HA
Sorry that I bother you again

grant_type: password
username: bert@mailaddress
password: The password I have set
client_id: app-front
I think i must use the URL: Watts Vision - Watts Electronics

But where do I find the smarthome ID?
Is that the ID that you see when you select acount end then preview?
22395aa8-04c0-42b1-b5b9-a874e2b4c7aa
or must I enter it between double quotes?

In which part of the 2 two scripts must I enter these credentials and where exactly?