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?

1 Like

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)
1 Like

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

1 Like

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?