Besmart custom_components climate

Do You think it would be possible to pull domestic hot water heating info from besmart same way as central heating? I would love to see some history chart how long did it take for boiler to prepare DHW.

yes, I think so but I don’t have this feature on my system

I can share the python script that I use to pull some information then if it works for you I can include on HA component.

We can try that, but I would need some info how to run it, I am not a pro when it comes to HA.

Hello,

I have moved the besmart integration script into a separate github repository in order to avoid confusion with other stuff.

Link https://github.com/muchasuerte/ha-besmart

I have done a pull request to include it on HACS repository list

Hi @etreus ,

I am trying to integrate this and I am getting an error on configuration.yaml check that beretta does not exist. I have added the same lines as in your example on github (chaning the username and password of course) and moved the custom _components folder on my installation
Error is Platform error climate.Besmart - Integration ‘Besmart’ not found.
can you help me out? I could not find the integration on HACS.

Thanks a lot

You need to add https://github.com/muchasuerte/ha-besmart into custom repositories in HACS options.

For me it is working perfectly, I can control all of my 3 besmarts from HA and I can see which of them and when were calling boiler for heating. I only miss info for domesitc heat water, I would love to have info when and for how long boiler was preparing DHW to adjust some other thing basing on that. On besmart preparing DHW is indicated by blinking faucet:
Przechwytywanie.PNG

@vlad.avramescu25 ,

the steps are:

  • download the files from git https://github.com/muchasuerte/ha-besmart/archive/main.zip
  • make a folder under HA dir e.g. /home/homeassistant/.homeassistant/custom_components/
  • copy extract the main.zip and copy the folder custom_components/besmart under /home/homeassistant/.homeassistant/custom_components/

I’m using HA 0.113 which version are you using?

@etreus, thanks for your answer, I already copied what you have in the custom_components under a new folder called besmart. I already had custom_components created from other integrations instaled via HACS. I cannot find yours in HACS. I am getting the error described above
Platform error climate.Besmart - Integration ‘Besmart’ not found.
:frowning:
I am using 0.118

Hi @Gutek,

Thanks for your answer
I cannot find HACS options…in HACS I have Integrations to install and I cannot find this one there. I tried what @etreus suggested below before asking here but I still get that error. whcat do you mean by adding into custom repositories in HACS? adding to custom_component folder in homeassistant/config? as a folder next to the other components installed via HACS? because I already did that.

Thanks,
Vlad

3 4

1 Like

Thanks, that really helped. Now I have the integration found in HACS after the restart (I cannot see it in HA -> Integration)
The next step was to go on the configuration.yaml and add:
climate:

  • platform: Besmart
    name: Besmart Thermostat
    username:
    password:
    room: Soggiorno
    scan_interval: 10

with my own user and password of course. saved the file and when I go to check configuration I get the same:
Platform error climate.Besmart - Integration ‘Besmart’ not found.

Is it because of the HA version or I am still missing something?

the solution was simple…the platform is with a lower b so besmart not Besmart :crazy_face:

now I am checking why I am seeing -17.8 - Off and Idle even though I have 22 degrees and it’s on…I checked the logs and it was because of the room, you have to set the same as the one in your Besmart phone application
thanks for this integration @etreus

Hi @etreus, there is no way to control the thermostat locally and not through their cloud?
the WI-FI BOX does not expose a local server?

thanks.

1 Like

Hi, i just found that the only opened port of the box is 80.
You can reach it via browser but it asks for a user and password , nothing i tryed worked.

hello e treus thanks for having done this integration, I’m new to Home assistant, could you explain better how to upload your integration?
where should i create the folder?
Why can’t I find the home / homeassistant path …
thanks for the help

hello @nicolamodo88,

you can install the component in 2 ways:

  1. by using HACS (there is a pretty good step by step guide made by @Gutek here Besmart custom_components climate )
  2. manually by following the steps listed here Besmart custom_components climate

then you have to configure

climate:
  - platform: besmart
    name: Besmart Thermostat
    username: <my-username>
    password: <my-password>
    room: <name assigned using BeSmart Application>
    scan_interval: 10

@faxbio

I did several check but I did not found how manage the communication locally, sniffing the box traffic I have found that it is doing polling here http://api.besmart-home.com/fwUpgrade/PR06549/version.txt then I have found the firmware and using this you can find the username and password strings -n 10 be_smart_0654917080101.bin > string.out but is quite useless since the webUI is working bad and has no smart function

if someone would like play whit his thermostat herewith the standalone version just set CONF_USERNAME and CONF_PASSWORD copy it in a file (you need requests module installed)

#! /usr/bin/env python

import logging
from datetime import datetime, timedelta
import requests

_LOGGER = logging.getLogger(__name__)

logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)

# pylint: disable=abstract-method
# pylint: disable=too-many-instance-attributes
class Besmart(object):
    """Representation of a Besmart thermostat."""

    BASE_URL = "http://www.besmart-home.com/Android_vokera_20160516/"
    LOGIN = "login.php"
    ROOM_MODE = "setRoomMode.php"
    ROOM_LIST = "getRoomList.php?deviceId={0}"
    ROOM_DATA = "getRoomData196.php?therId={0}&deviceId={1}"
    ROOM_PROGRAM = "getProgram.php?roomId={0}"
    ROOM_TEMP = "setRoomTemp.php"
    ROOM_ECON_TEMP = "setEconTemp.php"
    ROOM_FROST_TEMP = "setFrostTemp.php"
    ROOM_CONF_TEMP = "setComfTemp.php"
    GET_SETTINGS = "getSetting.php"
    SET_SETTINGS = "setSetting.php"

    def __init__(self, username, password):
        """Initialize the thermostat."""
        self._username = username
        self._password = password
        self._lastupdate = None
        self._device = None
        self._rooms = None
        self._timeout = 30
        self._s = requests.Session()

    def _fahToCent(self, temp):
        return str(round((temp - 32.0) / 1.8, 1))

    def _centToFah(self, temp):
        return str(round(32.0 + (temp * 1.8), 1))

    def login(self):
        try:
            resp = self._s.post(
                self.BASE_URL + self.LOGIN,
                data={"un": self._username, "pwd": self._password, "version": "32"},
                timeout=self._timeout,
            )
            if resp.ok:
                self._device = resp.json()
        except Exception as ex:
            _LOGGER.warning(ex)
            self._device = None

    def rooms(self):
        if not self._device:
            self.login()

        try:
            if self._device:
                resp = self._s.post(
                    self.BASE_URL + self.ROOM_LIST.format(self._device.get("deviceId")),
                    timeout=self._timeout,
                )
                if resp.ok:
                    self._lastupdate = datetime.now()
                    self._rooms = dict(
                        (y.get("name").lower(), y)
                        for y in filter(lambda x: x.get("id") != None, resp.json())
                    )
                    _LOGGER.debug("rooms: {}".format(self._rooms))
                    if len(self._rooms) == 0:
                        self._device = None
                        self._lastupdate = None
                        return None

                    return self._rooms
                else:
                    _LOGGER.debug("get rooms failed!")
        except Exception as ex:
            _LOGGER.warning(ex)
            self._device = None

        return None

    def roomdata(self, room):
        self.login()
        try:
            if self._device:
                resp = self._s.get(
                    self.BASE_URL
                    + self.ROOM_DATA.format(
                        room.get("therId"), self._device.get("deviceId")
                    ),
                    timeout=self._timeout,
                )
                if resp.ok:
                    return resp.json()
                else:
                    _LOGGER.debug("refresh roomdata failed for: {}".format(room))
        except Exception as ex:
            _LOGGER.warning(ex)
            self._device = None

        return None

    def program(self, room):
        self.login()
        try:
            resp = self._s.get(
                self.BASE_URL + self.ROOM_PROGRAM.format(room.get("id")),
                timeout=self._timeout,
            )
            if resp.ok:
                return resp.json()
        except Exception as ex:
            _LOGGER.warning(ex)
            self._device = None
        return None

    def roomByName(self, name):
        if self._lastupdate is None or datetime.now() - self._lastupdate > timedelta(
            seconds=120
        ):
            _LOGGER.debug("refresh rooms state")
            self.rooms()

        if self._rooms:
            return self.roomdata(self._rooms.get(name.lower()))
        return None

    def setRoomMode(self, room_name, mode):
        room = self.roomByName(room_name)

        if self._device and room:
            data = {
                "deviceId": self._device.get("deviceId"),
                "therId": room.get("roomMark"),
                "mode": mode,
            }

            resp = self._s.post(
                self.BASE_URL + self.ROOM_MODE, data=data, timeout=self._timeout
            )
            if resp.ok:
                msg = resp.json()
                _LOGGER.debug("resp: {}".format(msg))
                if msg.get("error") == 1:
                    return True

        return None

    def setRoomConfortTemp(self, room_name, new_temp):
        return self.setRoomTemp(room_name, new_temp, self.ROOM_CONF_TEMP)

    def setRoomECOTemp(self, room_name, new_temp):
        return self.setRoomTemp(room_name, new_temp, self.ROOM_ECON_TEMP)

    def setRoomFrostTemp(self, room_name, new_temp):
        return self.setRoomTemp(room_name, new_temp, self.ROOM_FROST_TEMP)

    def setRoomTemp(self, room_name, new_temp, url=None):
        url = url or self.ROOM_TEMP
        room = self.roomByName(room_name)
        if room and self._device.get("deviceId"):
            new_temp = round(new_temp, 1)
            _LOGGER.debug("room: {}".format(room))

            if room.get("tempUnit") in {"N/A", "0"}:
                tpCInt, tpCIntFloat = str(new_temp).split(".")
            else:
                tpCInt, tpCIntFloat = self._fahToCent(new_temp).split(".")

            _LOGGER.debug(
                "setRoomTemp: {} - {} - {}".format(new_temp, tpCInt, tpCIntFloat)
            )

            data = {
                "deviceId": self._device.get("deviceId"),
                "therId": room.get("roomMark"),
                "tempSet": tpCInt + "",
                "tempSetFloat": tpCIntFloat + "",
            }
            _LOGGER.debug("url: {}".format(self.BASE_URL + url))
            _LOGGER.debug("data: {}".format(data))
            resp = self._s.post(self.BASE_URL + url, data=data, timeout=self._timeout)
            if resp.ok:
                msg = resp.json()
                _LOGGER.debug("resp: {}".format(msg))
                if msg.get("error") == 1:
                    return True
        else:
            _LOGGER.warning("error on get the room by name: {}".format(room_name))

        return None

    def getSettings(self, room_name):
        room = self.roomByName(room_name)

        if self._device and room:
            data = {
                "deviceId": self._device.get("deviceId"),
                "therId": room.get("roomMark"),
            }

            resp = self._s.post(
                self.BASE_URL + self.GET_SETTINGS, data=data, timeout=self._timeout
            )
            if resp.ok:
                msg = resp.json()
                _LOGGER.debug("resp: {}".format(msg))
                if msg.get("error") == 0:
                    return msg

        return None

    def setSettings(self, room_name, season):
        room = self.roomByName(room_name)

        if self._device and room:
            old_data = self.getSettings(room_name)
            if old_data.get("error") == 0:
                min_temp_set_point_ip, min_temp_set_point_fp = str(
                    old_data.get("minTempSetPoint", "30.0")
                ).split(".")
                max_temp_set_point_ip, max_temp_set_point_fp = str(
                    old_data.get("maxTempSetPoint", "30.0")
                ).split(".")
                temp_curver_ip, temp_curver_fp = str(
                    old_data.get("tempCurver", "0.0")
                ).split(".")
                data = {
                    "deviceId": self._device.get("deviceId"),
                    "therId": room.get("roomMark"),
                    "minTempSetPointIP": min_temp_set_point_ip,
                    "minTempSetPointFP": min_temp_set_point_fp,
                    "maxTempSetPointIP": max_temp_set_point_ip,
                    "maxTempSetPointFP": max_temp_set_point_fp,
                    "sensorInfluence": old_data.get("sensorInfluence", "0"),
                    "tempCurveIP": temp_curver_ip,
                    "tempCurveFP": temp_curver_fp,
                    "unit": old_data.get("unit", "0"),
                    "season": season,
                    "boilerIsOnline": old_data.get("boilerIsOnline", "0"),
                }

                resp = self._s.post(
                    self.BASE_URL + self.SET_SETTINGS, data=data, timeout=self._timeout
                )
                if resp.ok:
                    msg = resp.json()
                    _LOGGER.debug("resp: {}".format(msg))
                    if msg.get("error") == 0:
                        return msg
        return None

if __name__ == "__main__":
    CONF_USERNAME=""
    CONF_PASSWORD=""
    client = Besmart(CONF_USERNAME, CONF_PASSWORD)
    client.rooms()

thanks i managed to install everything, now it works perfectly, it was my problem on hacs.
excellent application, I am a beretta technician forced to use BeSmart … unfortunately the owner app occasionally leaves something to be desired …

Since few HA updates I am getting this warning. Is this something that can be easly fixed by You etreus?

2021-04-26 11:29:25 WARNING (MainThread) [homeassistant.loader] No ‘version’ key in the manifest file for custom integration ‘Besmart’. As of Home Assistant 2021.6, this integration will no longer be loaded. Please report this to the maintainer of ‘Besmart’

I love Your component but I don’t want to be stuck on version 2021.5 forever :frowning:

Also did You have time to check if there is possibility to somehow track DHT heating time (indicated on besmart by blinking faucet and in mobile app by glowing faucet + fire) same as I am tracking central heating time?