home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
73.83k stars 30.91k forks source link

eq3btsmart Thermostat misbehaviour #3885

Closed alexxxo closed 7 years ago

alexxxo commented 8 years ago

Home Assistant release (hass --version): 0.30.2

Python release (python3 --version): Python 3.4.2

Component/platform: eq3btsmart

Description of problem: Thermostats show temperature, but valve does not open or close. Thermostats (at least the ones with latest firmware) need a disconnect after setting temperature. Also the datetime in the thermostats is set to 2030/2040 something with wrong time (month and day are correct).

Expected: Thermostats should react after changing temperature. Time should be set correctly.

Problem-relevant configuration.yaml entries and steps to reproduce:

### Climate ###
climate: !include includes/climate.yaml
- platform: eq3btsmart
  devices:
    eq3bt1:
      mac: '00:1A:22:xx:xx:xx'
  1. start hass
  2. try to change temperatur (manual or via automation does not matter)
  3. check datetime in thermostat
  4. notice "valve" (not sure in english) does not open or close

proof, that disconnect is needed: with a 2 hour quick and dirty hack, I have working thermostats, including correct time and date

"""
Support for eq3 Bluetooth Smart thermostats.

All temperatures in Celsius.

To get the current state, update() has to be called for powersaving reasons.
"""

import binascii
import syslog
import struct
import pexpect
from datetime import datetime
import time

PROP_WRITE_HANDLE = "0x0411"

PROP_INFO_QUERY = 3
PROP_TEMPERATURE_WRITE = 0x41

debug = True

def print_debug (msg):
    if debug:
        syslog.syslog(msg)

# pylint: disable=too-many-instance-attributes
class EQ3BTSmartThermostat:
    """Representation of a EQ3 Bluetooth Smart thermostat."""

    def __init__(self, mac):
        """Initialize the thermostat."""

        self._tool = None
        self._target_temperature = -1
        self._mode = -1
        self._vent = -1
        self._mac = mac

        self._set_time()

    def __str__(self):
        return "MAC: " + self.mac + " Mode: " + str(self.mode) + " Temp: " + str(self.target_temperature) + " Vent: " + str(self.vent)
        #return "MAC: " + self._mac + " Mode: " + str(self.mode) + " = " + self.mode_readable + " T: " + str(self.target_temperature) + " V: " + str(self.vent)

    def _set_time(self):
        """Set the correct time into the thermostat."""
        time = datetime.now()
        value = struct.pack('BBBBBB', PROP_INFO_QUERY, int(time.strftime("%y")),
                            time.month, time.day, time.hour,
                            time.minute)
        self._write_command_raw(PROP_WRITE_HANDLE, value)

    def _connect(self):
        print_debug('_connect')
        retry=0
        #starttime = time.time()
        while 1:
            self._tool = pexpect.spawn('gatttool -b ' + self.mac + ' --interactive')
            self.tool.timeout=20
            self.tool.expect('\[LE\]>')
            self.tool.sendline('connect')
            idx = self.tool.expect(['Connection successful', 'error', pexpect.TIMEOUT])
            if idx == 0:
                break

            retry+=1
            self.tool.sendline('exit')
            self.tool.expect(' ')
            if retry > 9:
                print_debug('_connection failed.')
                break;
            else:
                print_debug('__retrying to connect...')

    def _disconnect(self):
        if self.tool == None:
            return
        print_debug('_disconnect')
        self.tool.sendline('disconnect')
        self.tool.sendline('quit')
        self._tool = None
        time.sleep(5)

    def _write_command_raw(self, handle, value):
        if self.tool == None:
            self._connect()

        retry=0
        while 1:
            # write to the handle
            self.tool.sendline('char-write-req ' + handle + ' ' + binascii.b2a_hex(value).decode('utf-8'))
            # get back notifications
            idx = self.tool.expect(['Notification handle = .*', 'Failed', pexpect.TIMEOUT])
            if idx==0:
                print_debug(self.__str__() + ' >>> char-write-req ' + handle + ' ' + binascii.b2a_hex(value).decode('utf-8'))
                break;
            retry+=1
            self._disconnect()
            self._connect()
            if retry > 9:
                print_debug('_connection failed.')
                return;

        #print_debug('connect within ' + str((time.time()-starttime)*1000) + 'ms.')

        # make some nicer output
        #ret_handle = tool.after.split(b'\n')[0].split(b': ')[0].split()[3]
        values = self._tool.after.split(b'\n')[0].split(b': ')[1]

        self._mode = int(values.split()[2], 16)
        self._vent = int(values.split()[3], 16)
        self._target_temperature = int(values.split()[5], 16) / 2.0
        #print_debug(self.__str__())
        #print_debug("mode: " + str(self._mode))
        #print_debug("vent: " + str(vent))
        #print_debug("temp: " + str(self._target_temperature))

        # disconnect gatttool
        #tool.sendline('disconnect')
        #tool.sendline('quit')

    @property
    def tool(self):
        return self._tool

    @property
    def mac(self):
        """Return the MAC address of the connected device."""
        return self._mac

    @property
    def target_temperature(self):
        """Return the temperature we try to reach."""
        return self._target_temperature

    @target_temperature.setter
    def target_temperature(self, temperature):
        """Set new target temperature."""
        value = struct.pack('BB', PROP_TEMPERATURE_WRITE, int(temperature * 2))
        # Returns INFO_QUERY, so use that
        self._write_command_raw(PROP_WRITE_HANDLE, value)
        self._disconnect()

    @property
    def mode(self):
        """Return the mode (auto / manual)."""
        return self._mode

    @property
    def vent(self):
        """Return ventil %."""
        return self._vent

    @property
    def mode_readable(self):
        """Return a readable representation of the mode.."""
        return self.decode_mode(self._mode)

    @property
    def min_temp(self):
        """Return the minimum temperature."""
        return 4.5

    @property
    def max_temp(self):
        """Return the maximum temperature."""
        return 29.5

    @staticmethod
    def decode_mode(mode):
        """Convert the numerical mode to a human-readable description."""
        ret = ""
        if mode & 1:
            ret = "manual"
        else:
            ret = "auto"

        if mode & 2:
            ret = ret + " holiday"
        if mode & 4:
            ret = ret + " boost"
        if mode & 8:
            ret = ret + " dst"
        if mode & 16:
            ret = ret + " window"

        return ret

    def update(self):
        """Update the data from the thermostat."""
        self._write_command_raw(PROP_WRITE_HANDLE, struct.pack('B', PROP_INFO_QUERY))

Additional info: about the datetime bug, I think the PROP_INFO_QUERY (or a '03') is missing

#        value = struct.pack('BBBBBB', int(time.strftime("%y")),
#                            time.month, time.day, time.hour,
#                            time.minute, time.second)
        value = struct.pack('BBBBBB', PROP_INFO_QUERY, int(time.strftime("%y")),
                            time.month, time.day, time.hour,
                            time.minute)

Thank you.

alexxxo commented 8 years ago

the above approach seemed to work quite well with 3 thermostats. yesterday I bought a forth one and had the same issue again.. sometimes the thermostats set the correct temperature, but just don't open/close the valve. Currently I am testing to connect before every write and disconnect after every write.

I assume it is not a good idea to hold the BT connection, when multiple thermostats are in use.

DavidLP commented 8 years ago

Why don't we use this rather clean implementation of the eq3 protocol? It also does not seem to keep an open connection.

alexxxo commented 8 years ago

looks good. I digged around now for another few days.

It seems, that the main problem is, that HA reads the temperature every minute. So for this thermostat it does a write every 1 minute, even if inbetween a settemperature write was called. I assume the next write (for getting temperature) "disturbs" the thermostat and it does not open/close the valve. Also I got a lot of connection problems because I own 4 of these thermostats.

I implemented a delay in my testcode. After set temperature it sets nextupdate time delay to 2minutes, after update() it sets it to 15 minutes. Since I did this, the thermostats behave perfectly. just the time is still not correct.

DavidLP commented 8 years ago

Yes, that is another bug to my mind. Is temperature is set to target temperature. But for this device one cannot read the Is temperature. I would like to be able to take any other sensor values as Is temperature, otherwise it should not show up.

DavidLP commented 8 years ago

@bimbar Your implementation does not work well, I would go for a more or less complete rewrite. E.g. why do you use bluepy a difficult to install and unnecessary library?

alexxxo commented 8 years ago

for my testing I returned the valve state (in %) instead of current temperature. made it easier for digging out the problem :-)

just to give you an idea what I did to solve the problem.

WAIT_INITIAL = 30
WAIT_AFTER_WRITE = 120
WAIT_NEXT_UPDATE = 900
WAIT_NEXT_UPDATE_SLEEP = 3600

SLEEP_FROM_HOUR = 0
SLEEP_TO_HOUR = 6

...

    @target_temperature.setter
    def target_temperature(self, temperature):
        """Set new target temperature."""
        value = struct.pack(b'BB', PROP_TEMPERATURE_WRITE, int(temperature * 2))
        self._write_command_raw(PROP_WRITE_HANDLE, value)
        self._nextupdate = time.time() + WAIT_AFTER_WRITE`
...
    def update(self):
        """Update the data from the thermostat."""
        if time.time() > self._nextupdate:
            self._write_command_raw(PROP_WRITE_HANDLE, struct.pack(b'B', PROP_INFO_QUERY))

            SLEEP_START = datetime.time(SLEEP_FROM_HOUR,0)
            SLEEP_END = datetime.time(SLEEP_TO_HOUR,0)

            if SLEEP_START <= datetime.datetime.now().time() <= SLEEP_END:
                self._nextupdate = time.time() + WAIT_NEXT_UPDATE_SLEEP
            else:
                self._nextupdate = time.time() + WAIT_NEXT_UPDATE
fgi42 commented 8 years ago

I just bought some thermostats today, made the firmware update and run into the same problem.

Could anyone post his working eq3btsmart.py file? It seems to look different now in 0.31.1.

ronvl commented 8 years ago

I have also bought 3 of them (package) as the seemed the right choice for me at least.

If there is any prerelease available for testing I'm happy to help.

It seems in this forum https://forum.fhem.de/index.php/topic,39308.105.html they also start making some progress,

maunsen commented 8 years ago

I have four of these thermostats and it would be great if somebody could get them to work properly. I tried to exchange the eq3btsmart.py with your example above, but that did not work.

Could you pleas post the complete Code?

alexxxo commented 8 years ago

yes, sure. here you go. replace both eq3btsmart.py files. the location within your installation might differ from mine. I also added a file hcireset.sh. Copy to directory /home/hass/ or any convenient location and change accordingly in ....bluepy_devices/devices/eq3btsmart.py line 121.

if, for any reason, the script is not able to connect to one of your bt devices after 10 connection attempts, it resets the bluetooth controller. you need to add hass user to sudoers file.

hass ALL=(ALL:ALL) NOPASSWD: /home/hass/hcireset.sh

also please make sure you disconnect all your bt thermostats before starting homeassistant. in my case (debian jessie on raspberry3) /etc/systemd/system/home-assistant.service looks like

[Unit]
Description=Home Assistant
After=network.target

[Service]
Type=simple
User=hass
PermissionsStartOnly=true

ExecStartPre=/usr/bin/bt-device -d 00:1A:22:06:XX:XX
ExecStartPre=/usr/bin/bt-device -d 00:1A:22:06:XX:XX
ExecStartPre=/usr/bin/bt-device -d 00:1A:22:06:XX:XX
ExecStartPre=/usr/bin/bt-device -d 00:1A:22:07:XX:XX

ExecStart=/srv/hass/hass_venv/bin/hass -c "/home/hass/.homeassistant"

[Install]
WantedBy=multi-user.target

good luck!

the script writes some log entries in /var/log/messages. You can change the loglevel in ....bluepy_devices/devices/eq3btsmart.py to match your needs. for the istemperature it returns the valve open state (0-100%)

also keep in mind that you need to replace the files again after you upgraded homeassistant.

ha-eq3btsmart.zip

maunsen commented 8 years ago

Thank you very much, but in your zip is only one eq3btsmart.py from the components/climate folder. You wrote about exchanging anotherone, in the bluepy_devices/devices folder?

alexxxo commented 8 years ago

see ha-eq3btsmart.zip\home\hass\.homeassistant\deps\bluepy_devices\devices\eq3btsmart.py maybe .homeassistant is hidden (especially on windows)

fgi42 commented 8 years ago

Thank you. But I'm still having issues with an updated thermostat. The one with the original firmware works just fine.

After the connect and the char-write-req 0x0411 03100b120d3924 I don't get any answer.

So I inserted a time.sleep(5) before every sendline(...).

This is still not really stable but it seems to work most of the time.

jannau commented 7 years ago

The commits in https://github.com/jannau/bluepy_devices/tree/fixes fixes the current eq3 bt thermostat integration via bluepy_devices. I submitted a pull request: https://github.com/bimbar/bluepy_devices/pull/3

jannau commented 7 years ago

Ok, After spending more time with it I finally discovered the main issue with the time. The update request always needs to include the time. New pull request submitted.

alexxxo commented 7 years ago

Thank you for your effort.

The main issue with this component is IMHO, that the update is called to frequently and there are more and more issues connecting to devices. Besides battery drain this might be ok for one, maybe two thermostats. I own 4 and it was almost never possible to set the temperatures, or when the temperature was set, the thermostat did not change valve state, because it was interrupted with the next update call before it changed the valve. with the code i attached above i have almost no issues. maybe once per two weeks 1 of 4 thermostats does misbehave or not change the valve.

Maybe you can add something similar like i did (update delay). Also it would be nice to see the valve state in home assistant.

Thank you again.

jannau commented 7 years ago

I mostly agree and I have already implemented most of the missing functionality in bluepy_devices locally. The only major thing I haven't implemented is reading and writing the internal program. I'm now looking at integrating the added features in home-assistant.

I tried to increase the scan interval (via setting SCAN_INTERVAL in the component) but for some reason that's not working. The valve status could actually justify a shorter scan interval than the 15 minutes you're using. I think that's a sensible interval.

DavidLP commented 7 years ago

@jannau: I guess it is better not to use the bluepy_devices library since the back-end decision is bad (bluepy) and the maintainer is not responsive. Also the last code change to bluepy is more than 8 month ago and no unit tests are in place ... We should make a simple eq3btsmart library based on the pygatt python package. This package addresses multiple BLE connections, does not require a compilation during installation, is well tested, and provides a windows back-end.

jannau commented 7 years ago

@DavidLP: I have no almost full support for the thermostat in bluepy_devices' PR #5. That work is not in vain even if I or someone else exchanges the bluetooth/gatt backend. The device logic and the interface towards home-assistant will only need small changes. I thought of using BlueZ DBus backend but I'll look at pygatt first.

jannau commented 7 years ago

And here are my changes to home-assistant to use the eq3btsmart enhancements in https://github.com/bimbar/bluepy_devices/pull/5. Auto, Manual, Boost , Closed and Open are available as operation mode. Home-assistant's away mode is also supported. It currently programs the thermostat's holiday or party mode for 30 days at 12 degree Celsius. It also reports the low battery warning and valve state as attributes.

@alexxxo I suspect the problems you had with setting the temperatures could be the broken update command. Are your thermostats in the 'auto' or 'manual' mode?

rytilahti commented 7 years ago

I just peeked into the available btle wrappers as I was also tinkering with bluepy support for bt le tracker (while waiting for my eq3 to arrive), a short (and very superficial) summary of findings:

pygattlib

+ used already in homeassistant by bluetooth le tracker.
- requires setcap on python binary, which is not very nice. 
- huge dependencies incl. boost.
- not actively maintained.

bluepy

+ requires caps just for the shipped utility binary
+ nice pythonic api + good docs.
- just few dependencies.
- Unfortunately unmaintained, there are a few pull requests without comments, oldest from 2015.
(- Errored now and then on some actions during testing. Didn't debug if it was its or my phone's fault)

pygatt

Note: uses https://github.com/jrowberg/bglib for windows support (only bluegiga?), which could be used with other libs too.

+ no setcap'ing python, just gatttool?
+ seems to be the most active from all of these.
+ has some unit tests.
- executes gatttool instead of more proper ways.
- requires sudo without password set-up (calls ["sudo", "systemctl", "restart", "bluetooth"] and ["sudo", "hciconfig", self._hci_device, "reset"] on startup)

gatt dbus api

+ from upstream bluez directly
+ as bluetooth service has already access caps etc, no need for anything extra
- is very recent (http://www.bluez.org/release-of-bluez-5-42/ - since 5.30 feature complete apparently)
- due to its freshness no nice api wrappers?

Other:

Conclusion: In the future gatt's dbus api sounds the sanest option, needs wrapping though. For the time being, hard to decide as all of those have their pros and cons.. bluepy sounds however nicer than pygatt API-wise, and nicer than gattlib due to its fewer requirements.

DavidLP commented 7 years ago

@rytilahti: This is a very nice overview / review of the possible ways to use bluetooth with Python. I agree to all points. Generally we should maybe think about a bluetooth hub for home assistant to serialize bluetooth calls. This would circumvent the issue we have if several devices use bluetooth at the same time. Or is the gatt dbus api thread safe amd can handle more device connections then the hardware supports?

jannau commented 7 years ago

I've modified example-gatt-client to speak with the eq-3 bluetooth thermostat. It is indeed a little annoying without wrapping. I wouldn't expect thread-safety problems with the dbus api considering that dbus is explicitly a many to many message bus. I'm however unclear how the requirement for the glib main loop (event loop to receive callbacks) interacts with the rest of HA.

Devices still need to be connected for communication and if one would like to drop the connection if it's not in use that has to be done manually. So there would be use for a central arbitration to share the limited resource of bluetooth connections (4 on my laptop).

Bluez's example-gatt-client (and server) are of course bad examples since the use the deprecated dbus-python instead of pydbus.

rytilahti commented 7 years ago

@DavidLP: I'm not sure about the bluetooth specifics, but if one "requests" to be notified by the devices, is there still a need for a connection, or just when queries are made from the client to the device?

Anyway, I agree with the notion of having a centralized bluetooth hub, even if active connections are needed, as it it easier to support other platforms. Plus in principle the components wanting to use bluetooth should not care about low-level details where possible, or that's my opinion anyway for what it's worth.

@jannau: cool, I'm receiving my eq3 test piece tomorrow, I'll hope to give it a whirl then. I don't see a problem with the event-loop, in worst case it's blocking and with asyncio it can be made non-blocking where needed, it's just an event-loop like any other, right?

jannau commented 7 years ago

eq3bt_gatt_dbus.py is example-gatt-client adapted for the eq3 bt thermostat.

There is one insteresting thing in the bluez gatt dbus API. It's possible to register profiles (client equivalent of gatt services) and Bluez would then auto-connect. Probably not useable due the connection limitation.

rytilahti commented 7 years ago

Ok, so I received one thermostat today and I'm currently testing it, seems to work just fine without applying your updates @jannau.

However, can't connect at the same time with the app (probably because the connection is being held like indicated before), looking into the code, is there some specific reason why the connection needs to be active all the time? I would just create a context manager for doing connect & disconnect around calls, would that work?

edit: on another (happy) note, bluepy seems to have gotten new commits just yesterday from the original author, so it's not completely inactive :)

edit: yet another note, bluetooth le is marketed as connectionless, but that isn't the case? Btw, how come the mobile app needs pairing with a pin, but it works just fine through the plugin without it?

jannau commented 7 years ago

@rytilahti Bluetooth LE devices support only one concurrent connection. Wrapping each write request with connect()/disconnect() works fine. I tried that before I discovered that the short update()/set_time() is responsible. That seemed to work. Apart from occasional connection issues my two thermostats work fine too. My main and probably only problem was running the thermostats in the 'auto' mode with a backup program in the thermostat. The thermostat needs a the correct time for that.

rytilahti commented 7 years ago

I changed the behaviour of polling by not holding the connection open but making it connect whenever it requires send data and receive updates. This will 1) allow usage of mobile app or the debug client and 2) will get rid of potential "hanging socket" problems. Let's try to get it merged back to the upstream (https://github.com/bimbar/bluepy_devices/pull/6) as that would be the easiest way to handle it.

I created a couple of WIP pull reqs: https://github.com/home-assistant/home-assistant/pull/4959 https://github.com/home-assistant/home-assistant.github.io/pull/1618

jannau commented 7 years ago

Good, I merged the connection manager and commented on the homeassistant WIP PR. Do we have a backup plan if @bimbar remains elusive? He also owns the package on pypi.

I guess the next step would be to handle unavailable devices more gracefully than passing exceptions down.

rytilahti commented 7 years ago

Let's wait over the holidays and figure out the plan after that. In worst case we will have to create a fork & probably rename it too to avoid problems with pypi & others.

I'm also wondering whether it really makes sense to have a separate "collection" package like bluepy_devices, but simply just have something like python-eq3btsmart which uses bluepy (or whatever backend will be chosen) directly, the bluepy_devices library itself is just a small <100LOC wrapper for bluepy..

rytilahti commented 7 years ago

I have forked the library and it's hosted now in https://github.com/rytilahti/python-eq3bt/ . Due to an unfortunate mistake the release used by homeassistant 0.3.6 points to a broken release, fix is in https://github.com/home-assistant/home-assistant/pull/5353 . In the meanwhile changing required version to 0.1.4 in components/climate/eq3btsmart.py will help.

jannau commented 7 years ago

While I haven't yet upgraded to python-eq3bt / homeassistant 0.36.1 yet I think all issues mentioned in this issue are resolved and it should be closed

DavidLP commented 7 years ago

I just peeked into the available btle wrappers as I was also tinkering with bluepy support for bt le tracker (while waiting for my eq3 to arrive), a short (and very superficial) summary of findings: pygattlib

  • used already in homeassistant by bluetooth le tracker.
  • requires setcap on python binary, which is not very nice.
  • huge dependencies incl. boost.
  • not actively maintained.

bluepy

  • requires caps just for the shipped utility binary
  • nice pythonic api + good docs.
  • just few dependencies.
  • Unfortunately unmaintained, there are a few pull requests without comments, oldest from 2015. (- Errored now and then on some actions during testing. Didn't debug if it was its or my phone's fault)

pygatt

Note: uses https://github.com/jrowberg/bglib for windows support (only bluegiga?), which could be used with other libs too.

  • no setcap'ing python, just gatttool?
  • seems to be the most active from all of these.
  • has some unit tests.
  • executes gatttool instead of more proper ways.
  • requires sudo without password set-up (calls ["sudo", "systemctl", "restart", "bluetooth"] and ["sudo", "hciconfig", self._hci_device, "reset"] on startup)

gatt dbus api

  • from upstream bluez directly
  • as bluetooth service has already access caps etc, no need for anything extra
  • is very recent (http://www.bluez.org/release-of-bluez-5-42/ - since 5.30 feature complete apparently)
  • due to its freshness no nice api wrappers?

Other:

pybluez is just importing pygattlib for its bt le support, wraps bt and btle access into a single interface.

Conclusion: In the future gatt's dbus api sounds the sanest option, needs wrapping though. For the time being, hard to decide as all of those have their pros and cons.. bluepy sounds however nicer than pygatt API-wise, and nicer than gattlib due to its fewer requirements.

There is hope that we will have a nice maintained and working BLE library for python soon. The maintainer of the pygatt package told me that they are going to include a wrapper for the new gatt dbus api. Then we can finally get rid of pygattlib.

alexxxo commented 7 years ago

tried 0.36.1 again a lot of connection issues to the thermostats. also misbehaviour like mentioned before.

After I set all 4 thermostats to manual. one thermostat changed to 30 degrees (showing UNKNOWN).

back to my quickhack good working solution.

rytilahti commented 7 years ago

@alexxxo could you please create a bug report (with attached debug log, by adding eq3bt: debug in your homeassistant logger config) in https://github.com/rytilahti/python-eq3bt and I'll fix it.

Do you have the latest firmware on your thermostats?

edit: I can see the problem with manual mode, the state is not reported properly and I'm going to fix this. For connection issues it's a bit harder, I have 3 thermostats which are working just fine (with occasional "unable to connects").

@DavidLP that's great news! A centralized solution for whole homeassistant similar to mqtt "dependency" would be nice.

rytilahti commented 7 years ago

@alexxxo https://github.com/rytilahti/python-eq3bt/tree/construct_refactor branch has now a fix for manual mode. Temperature is reported back normally and changing the manual temperature works too.

ronvl commented 7 years ago

Upgraded to 36.1 today but can't see that it is working... it is still installing bluepy and not the special lib so what am I doing wrong? The documentation doesn't really give you any clue...

rytilahti commented 7 years ago

@ronvi, it is still using bluepy in the background, but python-eq3bt should be installed.

How exactly it is not working? Are you getting any errors? It's really hard to try to help without more information.

Can you try the console tool to see if it's working for you? See https://github.com/rytilahti/python-eq3bt command-line tool section for usage.

maunsen commented 7 years ago

Thank's for the great work. The thermostats have become way more reliable.

But sometimes my Pi still can't connect. The only error messages I get, are these: bluepy.btle.BTLEException: Failed to connect to peripheral <macaddress>, addr type: public eq3cli temp works and can read information from all my thermostats, but home assistant refuses to do so. But after several successfull connections, it suddenly stops working with: Current target temp: Mode.Unknown

One Bug I found in eq3cli: I have set all my Thermostats to Manual. When I do eq3cli I get the error, AttributeError: 'NoneType' object has no attribute 'MANUAL'

rytilahti commented 7 years ago

@maunsen sometimes homeassistant can't connect to the device for unknown reasons, I've seen it happening, but I'm unsure what causes it. (Too many concurrent connections? Adapter not allowing any more connections? Something else?)

However, I'll fix the failed to connect error by letting homeassistant to know that the device is currently not available, when I get some time to do that.

The manual mode is only possible with the restructure branch from git at the moment, it's still work in progress, but that's how I'm driving a couple of my thermostats and it seems to be working just fine.

teamdif commented 7 years ago

Hello All!

About a month ago I setup brand new RPI3 + HASS installed with All-In-One installer (version before 36.1). Somehow I managed my eq3btsmart to work (I did several manual installs). After upgrade to 36.1 it stopped working (I have no logs from this).

I cleaned my RPI3 and installed HASS from beging using Manual "mode".

Now HASS works ok, but it cannot initiallize eq3btsmart.py while starting. The problem is with installation of python-eq3bt (v 0.1.4).

I understood after reading 2017 messages above, that with HASS 36.1 + python-eq3bt 0.1.4 it should work.

This is what I see on this subject in HASS init logs:

INFO:homeassistant.loader:Loaded climate.eq3btsmart from homeassistant.components.climate.eq3btsmart
INFO:homeassistant.util.package:Attempting install of python-eq3bt==0.1.4
Command "/srv/homeassistant/homeassistant_venv/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-23vq4mwl/bluepy/setup.py';f=getattr(tokenize, 'open', op
en)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-u_uufd3q-record/install-record.txt --single-versio
n-externally-managed --compile --install-headers /srv/homeassistant/homeassistant_venv/include/site/python3.4/bluepy --home=/tmp/tmp2lv4e4o9" failed with error code 1 in /tmp/
pip-build-23vq4mwl/bluepy/
ERROR:homeassistant.bootstrap:Not initializing climate.eq3btsmart because could not install dependency python-eq3bt==0.1.4
INFO:homeassistant.core:Bus:Handling <Event call_service[L]: domain=persistent_notification, service_data=message=The following components and platforms could not be set up:
* climate.eq3btsmart
Please check your config, notification_id=invalid_config, title=Invalid config, service=create, service_call_id=1978343280-1>
INFO:homeassistant.core:Bus:Handling <Event state_changed[L]: entity_id=persistent_notification.invalid_config, old_state=None, new_state=<state persistent_notification.invali
d_config=The following components and platforms could not be set up:
* climate.eq3btsmart
Please check your config; title=Invalid config @ 2017-01-28T01:00:56.627652+01:00>>
INFO:homeassistant.core:Bus:Handling <Event service_executed[L]: service_call_id=1978343280-1>

Can you help me?

bimbar commented 7 years ago

Sorry, somehow my notification settings on github were wrong, so I slept through all of that.

I concur that bluepy is not the perfect solution and we should standardize on a common BTLE library.

So, if you want, I can merge your pull into bluepy_devices, or we change over to @rytilahti fork of it, at least in the interim, until we can ditch bluepy altogether (which I always have to build manually when updating HA, for some reason). I'm probably not the perfect maintainer anyway, since I only have one EQ3BT Smart thermostat and don't really use it actively.

rytilahti commented 7 years ago

@teamdif it's unable to install bluepy for some reason, but there's not enough information in that error message.. Can you try to manually install it with pip into your virtualenv and see the logs?

@bimbar it's unfortunate that I didn't notice to write an e-mail before doing the fork. I wrote you an email now, let us find out how to proceed from here.

fpedd commented 7 years ago

Hey I am all new to github. I have just recently setup a raspberry pi with ha on it and wanted to use it with my eq3 thermostat. I am not sure if this is the right spot to post something like this, but I am kinda lost.

when I run pip install python-eq3bt i get error: could not create '/usr/local/lib/python2.7/dist-packages/eq3bt': Permission denied

If i run the command sudo pip install python-eq3bt, it seems to install just fine.

However, when i then try to run eq3cli --mac 00:11:22:33:44:55

i get Traceback (most recent call last): File "/usr/local/bin/eq3cli", line 9, in <module> load_entry_point('python-eq3bt==0.1.5', 'console_scripts', 'eq3cli')() File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 356, in load_entry_point return get_distribution(dist).load_entry_point(group, name) File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2476, in load_entry_point return ep.load() File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2190, in load ['__name__']) File "/usr/local/lib/python2.7/dist-packages/eq3bt/__init__.py", line 2, in <module> from .eq3btsmart import Thermostat, TemperatureException, Mode File "/usr/local/lib/python2.7/dist-packages/eq3bt/eq3btsmart.py", line 14, in <module> from enum import IntEnum ImportError: No module named enum

I have tried it on "clean" hass images, same result. I am running python 2.7.9.

Do you guys have any idea what could be wrong with my setup? Thank you very much!

Cheers, Fabian

rytilahti commented 7 years ago

It is better to use virtualenv than installing anything as root, see http://docs.python-guide.org/en/latest/dev/virtualenvs/ . The easiest way to fix your problem is to use python3 instead of python2, homeassistant does not even work with python2.

On hassbian you can use the same virtualenv as homeassistant is using, see https://home-assistant.io/getting-started/installation-raspberry-pi-image/#update-home-assistant-on-hassbian - the parts you need to activate the environment are lines 2 and 3.

fpedd commented 7 years ago

ohh thank you very much. It now at least gives me the error it cant connect to the device. So it seems to work just fine

fpedd commented 7 years ago

I can see the device in bluetoothctl. I have successfully paired and connected to it but I cant seem to get the command eq3cli --mac 00:1A:22:06:50:0B

working.

`WARNING:eq3bt.connection:Unable to connect to the device 00:1A:22:06:50:, retrying: Failed to connect to peripheral 00:1A:22:06:50:, addr type: public ERROR:eq3bt.connection:Second connection try to 00:1A:22:06:50: failed: Failed to connect to peripheral 00:1A:22:06:50:, addr type: public ERROR:eq3bt.connection:Got btle exception: Failed to connect to peripheral 00:1A:22:06:50:, addr type: public Traceback (most recent call last): File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/connection.py", line 36, in enter self._conn.connect(self._mac) File "/srv/homeassistant/lib/python3.4/site-packages/bluepy/btle.py", line 367, in connect "Failed to connect to peripheral %s, addr type: %s" % (addr, addrType)) bluepy.btle.BTLEException: Failed to connect to peripheral 00:1A:22:06:50:, addr type: public

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/connection.py", line 71, in make_request with self: File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/connection.py", line 40, in enter self._conn.connect(self._mac) File "/srv/homeassistant/lib/python3.4/site-packages/bluepy/btle.py", line 367, in connect "Failed to connect to peripheral %s, addr type: %s" % (addr, addrType)) bluepy.btle.BTLEException: Failed to connect to peripheral 00:1A:22:06:50:, addr type: public Traceback (most recent call last): File "/srv/homeassistant/bin/eq3cli", line 11, in sys.exit(cli()) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 722, in call return self.main(args, kwargs) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 697, in main rv = self.invoke(ctx) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 1043, in invoke return Command.invoke(self, ctx) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 895, in invoke return ctx.invoke(self.callback, ctx.params) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 535, in invoke return callback(args, kwargs) File "/srv/homeassistant/lib/python3.4/site-packages/click/decorators.py", line 17, in new_func return f(get_current_context(), *args, kwargs) File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/eq3cli.py", line 27, in cli ctx.invoke(state) File "/srv/homeassistant/lib/python3.4/site-packages/click/core.py", line 535, in invoke return callback(*args, *kwargs) File "/srv/homeassistant/lib/python3.4/site-packages/click/decorators.py", line 17, in new_func return f(get_current_context(), args, kwargs) File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/eq3cli.py", line 149, in state click.echo(dev) File "/srv/homeassistant/lib/python3.4/site-packages/click/utils.py", line 221, in echo message = text_type(message) File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/eq3btsmart.py", line 97, in str self.mode_readable, File "/srv/homeassistant/lib/python3.4/site-packages/eq3bt/eq3btsmart.py", line 267, in mode_readable if mode.MANUAL: AttributeError: 'NoneType' object has no attribute 'MANUAL' `

fpedd commented 7 years ago
teamdif commented 7 years ago

@rytilahti I will do what you recommend and share feedbak - thanks! (PS. I use manually installend Jessie Lite + RPI3 + VirtualEnv).

Just to be sure on what I will do: I will log in to my "pi" user, switch to virtual env + activate it and than I will do "pip" with do: "pip install python-eq3bt" and share output here...

rytilahti commented 7 years ago

@teamdif yes, although if the install is successful, just try to use eq3cli --mac <your device's mac> to see if it works already.