TionAPI / HA-tion

Home assistant integration for Tion breezers
Apache License 2.0
72 stars 6 forks source link

В логах много сообщений WARNING (MainThread) [tion_btle.tion] Got BTLEDisconnectError:Failed to connect to peripheral #65

Closed IATkachenko closed 2 years ago

IATkachenko commented 2 years ago

Общая информация

Краткое описание

При подключении к бризеру периодически проскакивают ошибки

WARNING (MainThread) [tion_btle.tion] Got BTLEDisconnectError:Failed to connect to peripheral

После чего, при переподключении, компонент подключается к бризеру нормально.

Debug-log

Немного дополненный:

2022-01-12 14:44:32 DEBUG (MainThread) [tion_btle.tion] Connecting
2022-01-12 14:44:32 DEBUG (MainThread) [tion_btle.tion] Connection_status is disc
2022-01-12 14:44:32 WARNING (MainThread) [tion_btle.tion] Got BTLEDisconnectError:Failed to connect to peripheral ..., addr type: random
2022-01-12 14:44:32 DEBUG (MainThread) [tion_btle.tion] Will try again.
2022-01-12 14:44:34 DEBUG (MainThread) [tion_btle.tion] Connecting
2022-01-12 14:44:34 DEBUG (MainThread) [tion_btle.tion] Connection_status is disc
2022-01-12 14:44:35 DEBUG (MainThread) [tion_btle.tion] Connected
2022-01-12 14:44:35 DEBUG (MainThread) [tion_btle.tion] found notify

tion_btle.tion, который дал такой лог:

   def _connect(self, need_notifications: bool = True):                
        _LOGGER.debug("Connecting")                                     
        if self.connection_status == "disc":            
            _LOGGER.debug("Connection_status is disc")                  
            try:                                                        
                self._btle.connect(self.mac, btle.ADDR_TYPE_RANDOM)
                _LOGGER.debug("Connected")                              
                for tc in self._btle.getCharacteristics():              
                    if tc.uuid == self.uuid_notify:                     
                        _LOGGER.debug("found notify")                   
                        self.notify = tc                                
                    if tc.uuid == self.uuid_write:                                    
                        _LOGGER.debug("found write")                    
                        self.write = tc                                 
                if need_notifications:                             
                    self._enable_notifications()                   
                else:                                              
                    _LOGGER.debug("Notifications was not requested")                                
                self.__failed_connects = 0                          
            except btle.BTLEDisconnectError as e:                   
                _LOGGER.warning("Got BTLEDisconnectError:%s", str(e))
                if self.__failed_connects < 1:                       
                    self.__failed_connects += 1                      
                    _LOGGER.debug("Will try again.")                 
                    time.sleep(2)                                    
                    self._connect(need_notifications)                       
                else:                                                
                    raise e                                          

Как можно воспроизвети вашу проблему

  1. Запустить HA с интеграцией
  2. Немного подождать

Дополнительное описание

Начало обсуждения в #60.

Сама проблема на стороне python-модуля и должна исправляться там.

IATkachenko commented 2 years ago

Используется bluepy 1.3.0, у которого connect простой

        self._writeCmd("conn %s %s\n" % (addr, addrType))
        rsp = self._getResp('stat')
        while rsp['state'][0] == 'tryconn':
            rsp = self._getResp('stat')
        if rsp['state'][0] != 'conn':
            self._stopHelper()
            raise BTLEDisconnectError("Failed to connect to peripheral %s, addr type: %s" % (addr, addrType), rsp)

Судя по exception, в какой-то момент прилетает rsp = None. В master у bluepy есть более продвинутая версия connect, но, нам она не доступна, поскольку нет модуля.

IATkachenko commented 2 years ago

С версией _connect из master'a тоже ничего не поменялось, хотя я ожидал что будут timeout'ы, вместо обычного Failed to connect. Позже еще посмотрю в эту сторону.

IATkachenko commented 2 years ago

Все происходит относительно честно: внутри _connect bluepy получает от helper'a state disc. Так что python видит именно то, что происходит с BTLE.

Так что можно пробовать переподключатся.

ИТОГО: проблема на стороне bluepy и реализации BTLE малины. На нашем уровне с ней справиться не получится, так что придется маскировать :(

kizill commented 2 years ago

Ага, у меня тоже есть ощущение, что bluepy косячит - я пользуюсь bluetooth встроенным в Intel NUC, у меня помимо этих, есть еще несколько эксепшнов странных.

2022-01-07 21:01:00 WARNING (ThreadPoolExecutor-0_0) [tion_btle.tion] Got Device disconnected while read in handleNotification. May continue working.
2022-01-07 21:01:00 CRITICAL (MainThread) [custom_components.tion] Response is {}
2022-01-07 21:01:00 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/home/homeassistant/.homeassistant/custom_components/tion/climate.py", line 409, in _async_update_state
await self._tion_entry.async_update_state(time, force, keep_connection)
File "/home/homeassistant/.homeassistant/custom_components/tion/__init__.py", line 129, in async_update_state
raise e
File "/home/homeassistant/.homeassistant/custom_components/tion/__init__.py", line 106, in async_update_state
response = await btle_exec_helper(self.__tion.get, keep_connection)
File "/home/homeassistant/.homeassistant/custom_components/tion/__init__.py", line 19, in btle_exec_helper
return await asyncio.wrap_future(_BTLE_COMMAND_EXECUTOR.submit(method, *args, **kwargs))
File "/usr/lib/python3.8/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/srv/homeassistant/lib/python3.8/site-packages/tion_btle/tion.py", line 257, in get
self.get_state_from_breezer(keep_connection)
File "/srv/homeassistant/lib/python3.8/site-packages/tion_btle/tion.py", line 234, in get_state_from_breezer
response = self._get_data_from_breezer()
File "/srv/homeassistant/lib/python3.8/site-packages/tion_btle/tion.py", line 643, in _get_data_from_breezer
self._btle.waitForNotifications(1.0)
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 560, in waitForNotifications
resp = self._getResp(['ntfy','ind'], timeout)
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 416, in _getResp
self.delegate.handleNotification(hnd, data)
File "/srv/homeassistant/lib/python3.8/site-packages/tion_btle/tion.py", line 41, in handleNotification
self.__topic.read()
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 197, in read
return self.peripheral.readCharacteristic(self.valHandle)
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 530, in readCharacteristic
resp = self._getResp('rd')
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 407, in _getResp
resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
File "/srv/homeassistant/lib/python3.8/site-packages/bluepy/btle.py", line 338, in _waitResp
if self._helper.poll() is not None:
AttributeError: 'NoneType' object has no attribute 'poll'

Тут видно 2 проблемы - одну с недоставленным эксепшном я отлажу, но видно, что тут причина в кишках bluepy:

if self._helper.poll() is not None:
AttributeError: 'NoneType' object has no attribute 'poll'

https://github.com/IanHarvey/bluepy/issues/172 - вот ишью от 2017😸 года

Там упоминали хотфикс: https://github.com/IanHarvey/bluepy/issues/172#issuecomment-741627380 , возможно стоит его тоже попробовать.

IATkachenko commented 2 years ago

@kizill, я могу обернуть disconnect от blupy в такую обертку в tion_btle модуле. Если это нужно -- откройте, пожалуйста, issue в репозитории модуля. Может с #33 кстати быть связано...

kizill commented 2 years ago

@IATkachenko Мне кажется, сначала нужно проверить работоспособность  ~костыля~хотфикса. Я могу на выходных попробовать подхачить, отпишусь если поможет или просто сделаю PR в tion_python если сработает.

IATkachenko commented 2 years ago

Хорошо. У меня ваш exception ('NoneType' object has no attribute 'poll') не проявляется, так что помочь смогу только с review. Когда отлаживал connect -- сделал отдельный класс, который наследуется от bluepy.btle.Phereperial и в нем переопределял методы. Его будет смысл вынести в tion_python в отдельный файл, чтобы было проще поддерживать изменения.