8000 Проблемы с Lite. · Issue #7 · TionAPI/tion_python · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Проблемы с Lite. #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mozoh opened this issue Nov 28, 2020 · 21 comments
Closed

Проблемы с Lite. #7

mozoh opened this issue Nov 28, 2020 · 21 comments
Labels
bug Something isn't working
Milestone

Comments

@mozoh
Copy link
mozoh commented Nov 28, 2020
pi@raspberrypi:~ $ python3 ./tion_python/tests/lite.py fb:fa:3b:ae:82:0d
DEBUG:tion_btle.tion:Enabling notification
DEBUG:tion_btle.tion:Notify handler is 18
DEBUG:tion_btle.tion:Will write b'\x01\x00' to 19 handle
DEBUG:tion_btle.tion:Result is {'rsp': ['wr']}
Traceback (most recent call last):
File "./tion_python/tests/lite.py", line 15, in <module>
result = device.get()
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/tion.py", line 215, in get
response = self._get_data_from_breezer(keep_connection)
TypeError: _get_data_from_breezer() takes 1 positional argument but 2 were given

Если руками добавить лишний аргумент, то начинает работать, но как-то нестабильно: инфу получается достать примерно один из пяти раз, в остальных получаю:

pi@raspberrypi:~ $ python3 ./tion_python/tests/lite.py fb:fa:3b:ae:82:0d
DEBUG:tion_btle.tion:Enabling notification
DEBUG:tion_btle.tion:Notify handler is 18
DEBUG:tion_btle.tion:Will write b'\x01\x00' to 19 handle
DEBUG:tion_btle.tion:Result is {'rsp': ['wr']}
DEBUG:tion_btle.tion:Doing _try_write. Attempt 1/3
DEBUG:tion_btle.tion:Writing 8010003a0232120dd71f8f48d3c31abbaa to 98f00002-3788-83ea-453e-f52244709ddb
DEBUG:tion_btle.lite:Collecting data
DEBUG:tion_btle.tion:Got data in 18 response 0049003a6e31120dd71f8ff5bccd2ccdd8020a01
DEBUG:tion_btle.lite:Got 0049003a6e31120dd71f8ff5bccd2ccdd8020a01 from tion
DEBUG:tion_btle.tion:Got data in 18 response 40f90a1580e521009a791f0066d4cd0018e85200
DEBUG:tion_btle.lite:Got 40f90a1580e521009a791f0066d4cd0018e85200 from tion
DEBUG:tion_btle.tion:Got data in 18 response 4000000000000000000000000000000000000000
DEBUG:tion_btle.lite:Got 4000000000000000000000000000000000000000 from tion
DEBUG:tion_btle.lite:Waiting too long for data
DEBUG:tion_btle.tion:Got data in 18 response c000000000000a1419020406061c005a73
Traceback (most recent call last):
File "./tion_python/tests/lite.py", line 15, in <module>
result = device.get()
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/tion.py", line 215, in get
response = self._get_data_from_breezer(keep_connection)
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/lite.py", line 174, in _get_data_from_breezer
raise TionException("Lite _get_data_from_breezer", "Could not get breezer state")
tion_btle.tion.TionException: ('Lite _get_data_from_breezer', 'Could not get breezer state') 

или

pi@raspberrypi:~ $ python3 ./tion_python/tests/lite.py fb:fa:3b:ae:82:0d
WARNING:tion_btle.tion:Got Failed to connect to peripheral fb:fa:3b:ae:82:0d, addr type: random exception
Traceback (most recent call last):
File "./tion_python/tests/lite.py", line 15, in <module>
result = device.get()
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/tion.py", line 214, in get
self._connect()
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/tion.py", line 308, in _connect
raise e
File "/home/pi/.local/lib/python3.7/site-packages/tion_btle/tion.py", line 297, in _connect
self._btle.connect(self.mac, btle.ADDR_TYPE_RANDOM)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 445, in connect
self._connect(addr, addrType, iface)
File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 439, in _connect
raise BTLEDisconnectError("Failed to connect to peripheral %s, addr type: %s" % (addr, addrType), rsp)
bluepy.btle.BTLEDisconnectError: Failed to connect to peripheral fb:fa:3b:ae:82:0d, addr type: random
@IATkachenko
Copy link
Collaborator

Версия 1.0.0, как понимаю. Про функцию понял, проверю и поправлю.

Про стабильность: как далеко у вас то что опрашивает бризер от самого бризера? Многие жалуются на стабильность связи, если расстояние "большое".
И, на всякий случай, уточню: в момент работы с бризером через модуль к нему не пытается подключаться приложение или пульт, или что-нибудь еще?

Хотя первый лог довольно странный: последний пакет он все же получил. Видимо это было не очень быстро.

@IATkachenko IATkachenko added the bug Something isn't working label Nov 28, 2020
@IATkachenko
Copy link
Collaborator

Первая часть исправлена в v1.0.1,
А про стабильность еще вот тут можно почитать:

Компонент использует этот модуль и все что обсуждалось там применимо и к использованию модуля без HomeAssistant.

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

Про pair еще вопрос: для Lite использовать pair.py? У меня 2 Lite бризера, для одного использовал, но он завершается с ошибкой (видимо, потому что код для s3), и с ним худо бедно удается связаться (на логах выше), для второго не вызывал, с ним только:

WARNING:tion_btle.tion:Got Failed to connect to peripheral d6:a7:26:09:47:21, addr type: random exception 

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

Протестировал, максимально поднеся raspberry к тиону (50 сантиметров), при этом убив приложение на смартфоне и немного подождав: результаты те же.

@IATkachenko
Copy link
Collaborator

Нет, для lite специальный tion-pair не нужен, но нужен обычный BT pairing.
Я пока не знаю как это оформить на уровне bluepy. И не уверен что вообще буду его решать: сейчас в приоритете переход на асинхронный режим работы, а bleak BT pairing умеет сам по себе.

На малине можно параллельно запустиь bluetoothctl -- будет видно как модуль подключается/отключается к/от бризера.
"Waiting too long for data" означает что за 10 секунд бризер не прислал ничего по каналу уведомлений. Обычно это происходит если модуль отключается (на уровне BT) от бризера раньше, чем получает все данные.
Но вот дальше у вас сразу идет "Got data in 18 response ..." -- это как раз маркер того, что данные пришли, те отключения не было.

У меня пока нет идей, на тему того что происходит, кроме как проблем с радиоканалом. Но ваш эксперимент, с поднесением малины близко к бризеру, эту догадку опровергает.

Можно попробовать добавить вот такую конструкцию

logging.basicConfig(
    format='%(asctime)s %(levelname)-8s %(message)s',
    level=logging.DEBUG,
    datefmt='%Y-%m-%d %H:%M:%S')

вместо logging.basicConfig(level=logging.DEBUG) в lite.py
Тогда в логах будут видны timestamp и может быть будет видно что на самом деле он отваливается не по timeout'у.

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

image
По bluetoothctl так же видно, что он [CHG] Device FB:FA:3B:AE:82:0D Connected: no происходит после вылета из скрипта.

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

Повторил все в "чистых" условиях со вторым Lite: запейрил через bluetoothctl, все успешно, положил в метре - скрипт валится точно так же, и ни разу инфу до конца получить не удалось. Причем в bluetoothctl все хорошо - пейрится, коннектится и т.д. без проблем.
Возможно дело в usb-донгле, который я использую (c raspberry b+ первого поколения). Попробую раздобыть малинку поновее, zero w например.
image

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

Немного покопался в коде:
image
Если сделать так, то по прошествии 10 секундной паузы все парсится и выдается правильный json. Видимо все таки ошибка в алгоритме.

@IATkachenko
Copy link
Collaborator

_btle.waitForNotifications(1.0) -- штука которая секунду ждет, когда бризер пришлет данные по каналу уведомлений.
Когда по каналу уведомлений приходят данные, то вызывается callback def handleNotification(self, handle: int, data: bytes):, который в _delegation.data кладет данные.
И в этот момент waitForNotifications должна прерываться и возвращать true. И именно эта часть у вас не работает.

Ваш вариант не корректен, поскольку обращение к self._data, без успешного завершения _collect_message некорректен: в _data будет или предыдущий запрос или непойми что.

Я сейчас в dev залью альтернативный вариант работы с Notification, по аналогии с тем, как это было сделано для bleak.
Попробуйте его, пожалуйста.

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

Но я как раз добавил _collect_message в случай когда "Waiting too long for data" после notify.read().
Мне показалось, что по логу видно, что данные приходят после этих событий.
Заранее извиняюсь, в теме не разбираюсь. Обязательно попробую обновление.

IATkachenko added a commit that referenced this issue Nov 29, 2020
In #7 we faced up with bug: we have real data in notification channel, but waitForNotifications don't returns True.
@IATkachenko
Copy link
Collaborator

Готово.

С collect_message за пределами цикла все сложно: lite посылает ответ из нескольких пакетов. Наиболее интересный -- первый и второй. Все остальное можно, в принципе, игнорировать. А collect_message собирает _data только если получен полный пакет: установлен маркер мультипакета и пришел последний пакет.

ps. Извиняться не нужно: вы помогаете сделать модуль лучше, за что вам спасибо.

@mozoh
Copy link
Author
mozoh commented Nov 29, 2020

image
К сожалению это не исправило ситуацию, снова Waiting too long for data.

@IATkachenko
Copy link
Collaborator

Тут что-то не так пошло с новым алгоритмом: _collect_message должен при вызове сообщать что он от Tion'a что-то получил, а этих сообщений нет. Те в ветку if self._delegation.haveNewData: он не заходит...
Сейчас поковыряюсь на тему того почему так происходит.

@IATkachenko
Copy link
Collaborator

Обновил dev. Код не обрабатывал callback'и пока находился в цикле.
Поправил это.
Сейчас должно все корректно обрабатывать.

@mozoh
Copy link
Author
mozoh commented Nov 30, 2020

image
Вернулись к началу, часть приходит нормально, часть после notify.read() вне цикла.

@mozoh
Copy link
Author
mozoh commented Nov 30, 2020

image
Если добавить вот сюда self.notify.read() все срабатывает без ошибок, и с верыми данными (совпадает с состоянием тиона).

@mozoh
Copy link
Author
mozoh commented Nov 30, 2020

Решил заодно потестировать set() функцию, добавил `device.set({'fan_speed':2}) в тест.
image

Похоже, что опечатка и должно быть state вместо status.

@mozoh
Copy link
Author
mozoh commented Nov 30, 2020

В общем, с двумя этими фиксами, все работает замечательно. Я написал маленькую mqtt обвязку и счастлив, что могу наконец управлять этим добром из node-red.

IATkachenko added a commit that referenced this issue Nov 30, 2020
It should prevent situation when breezer don't send new data and waiting for something like in #7
@IATkachenko
Copy link
Collaborator

Выложите mqtt на git, в соседний репозиторий? Под TionAPI сделаем отдельный репозиторий, на подобии python-server'a.
Я думаю многим это будет полезно.

Касательно read -- поправил основной код более корректным образом. Можете проверить что все работает правильно? На моем S3 полет нормальный, но он умещает всю информацию в один пакет.

@mozoh
Copy link
Author
mozoh commented Nov 30, 2020

Проверил обновление - теперь все работает правильно, без проблем.

Про mqtt - я набросал максимально простой сервис с paho.mqtt и захадкожеными маками моих тионов. Нужно будет его допилить до удобоваримого состояния: неизвестные модели и кол-во устройств и т.д.

import json
import logging
import paho.mqtt.client as mqtt
from tion_btle.lite import Lite

logging.basicConfig(level=logging.DEBUG)
_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel("DEBUG")

mac1 = 'YOUR_DEVICE_1_MAC'
mac2 = 'YOUR_DEVICE_2_MAC'
deviceTopic1 = 'tion/'+mac1
deviceTopic2 = 'tion/'+mac2
refreshTopic1 = deviceTopic1+'/refresh'
refreshTopic2 = deviceTopic2+'/refresh'
setTopic1 = deviceTopic1+'/set'
setTopic2 = deviceTopic2+'/set'

maxTries = 3

device1 = Lite(mac1)
device2 = Lite(mac2)
client = mqtt.Client()

def on_connect(client, userdata, flags, rc):
    client.subscribe(refreshTopic1)
    client.subscribe(refreshTopic2)
    client.subscribe(setTopic1)
    client.subscribe(setTopic2)

def on_message(client, userdata, msg):
    success = False
    tryCount = 0

    while not success and tryCount < maxTries:
        if msg.topic == refreshTopic1:
            try:
                client.publish(deviceTopic1, json.dumps(device1.get(True)))
                success = True
            except Exception as e:
                print(e)

        elif msg.topic == refreshTopic2:
            try:
                client.publish(deviceTopic2, json.dumps(device2.get(True)))
                success = True
            except Exception as e:
                print(e)

        elif msg.topic == setTopic1:
            try:
                device1.set(json.loads(msg.payload))
                client.publish(deviceTopic1, json.dumps(device1.get(True)))
                success = True
            except Exception as e:
                print(e)

        elif msg.topic == setTopic2:
            try:
                device2.set(json.loads(msg.payload))
                client.publish(deviceTopic2, json.dumps(device2.get(True)))
                success = True
            except Exception as e:
                print(e)

        tryCount += 1

client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set('YOUR_MQTT_USERNAME', 'YOUR_MQTT_PASSWORD')
client.connect('YOUR_MQTT_HOST', YOUR_MQTT_PORT, 60)
client.loop_forever()

@IATkachenko
Copy link
Collaborator

Можно это оформить хоть в каком-то читаемом виде и закинуть в репозиторий, чтобы люди не начинали с чистого листа.
Репозиторий сделал, права дал. Если будет желание и время -- действуйте! ;)

А это issue я закрываю. Релиз модуля будет в ближайшее время.

@IATkachenko IATkachenko added this to the v1.0.2 milestone Nov 30, 2020
IATkachenko added a commit that referenced this issue Nov 30, 2020
In #7 we faced up with bug: we have real data in notification channel, but waitForNotifications don't returns True.
IATkachenko added a commit that referenced this issue Nov 30, 2020
It should prevent situation when breezer don't send new data and waiting for something like in #7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
3568
Development

No branches or pull requests

2 participants
0