lucapinello / pyacaia

Python module to interact with Acaia scales via Bluetooth (BLE)
GNU Affero General Public License v3.0
52 stars 15 forks source link

Pyxis scale has different API #4

Closed danbodoh closed 2 years ago

danbodoh commented 3 years ago

I have done some work to figure out the new API on the Pyxis scale; most of the changes are related to UUIDs. Are you still maintaining pyacaia? I could submit a PR, but I've done all the work in bluepy and don't really want to replicate in pygatt - my first attempt at pygatt installation was not successful.

lucapinello commented 3 years ago

Hi there, good to know! I didn't know they have changed the API for the Pyxis. Sure please send a PR and thanks.

danbodoh commented 3 years ago

Lucapinello, the released version is 0.3.0, but the master head is 0.2.0. Did you forget to push an update to github?

lucapinello commented 3 years ago

Yeah, you are right. Just pushed 0.3.0

danbodoh commented 3 years ago

I've got the Pyxis working, but it only updates the AcaiaScale.weight property at the heartbeat rate. Is that the same way the older scales work? Or do I have more reverse engineering to do? The bluetooth log shows some kind of regular heartbeat-like activity that includes the Id being sent along with the same heartbeat from the old scales

lucapinello commented 3 years ago

No, with the old scale it is much faster. In bluepy the relevant method that triggers the updates is def handleNotification, in theory the notifications are independent from the heartbeat resolution. More on this method here: https://ianharvey.github.io/bluepy-doc/notifications.html

danbodoh commented 3 years ago

According the Wireshark log, notifications keep coming many times a second. Somewhere they are getting queued up and then released with the heartbeat; perhaps I should be running the polling of the weight property in a separate thread? Does handleNotification() get called from a separate thread created in bluepy? I'll take a look at the link you sent...

I've pushed the current code to my fork, if you are interested.

lucapinello commented 3 years ago

Yes this is weird. handleNotification() is a special method from bluepy to register an asynchronous callback and I think it should live in a separate thread.With the Lunar the weight property is updated as soon as this function is automatically called with each notification.

On Tue, Jan 5, 2021 at 11:03 PM danbodoh notifications@github.com wrote:

According the Wireshark log, notifications keep coming many times a second. Somewhere they are getting queued up and then released with the heartbeat; perhaps I should be running the polling of the weight property in a separate thread? Does handleNotification() get called from a separate thread created in bluepy? I'll take a look at the link you sent...

I've pushed the current code to my fork, if you are interested.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-755063673, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIH72TWI74K4CTITR25HSTSYPOHZANCNFSM4VS7OB6Q .

danbodoh commented 3 years ago

I've inspected the logs of the notifications from the Pyxis. It appears that the weight Message is not necessarily contained in a single bluetooth packet. I can see the header bytes in one short packet, and then the remainder of the message appears in the next packet. And there are some packets when notifications start that look to contain multiple messages (with multiple header bytes). Do you see this on the Lunar? I suspect that the reason that the early return from decode() on missing header is because of this issue. Of course, some messages are complete and so I sometimes get a valid weight.

So I'll have to keep a queue of bytes and construct a Message when it completely arrives. I assume I don't have to worry about out-of-order packets

lucapinello commented 3 years ago

I think the behaviour is similar but I am not sure about the multiple messages. The Queue class is essentially helping with this package reassembly before decoding the message. You may need to change the logic there based on what you see in the Pyxis protocol. In the Lunar you need to wait for 3 packets: https://github.com/lucapinello/pyacaia/blob/acb72f446689432cd4e89f196eda033e7219ed04/pyacaia/__init__.py#L295 and the packets are in order.

On Thu, Jan 7, 2021 at 9:38 PM danbodoh notifications@github.com wrote:

I've inspected the logs of the notifications from the Pyxis. It appears that the weight Message is not necessarily contained in a single bluetooth packet. I can see the header bytes in one short packet, and then the remainder of the message appears in the next packet. And there are some packets when notifications start that look to contain multiple messages (with multiple header bytes). Do you see this on the Lunar? I suspect that the reason that the early return from decode() on missing header is because of this issue.

So I'll have to keep a queue of bytes and construct a Message when it completely arrives. I assume I don't have to worry about out-of-order packets

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-756509284, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIH72T4Q4A4XZTLY2RTXGTSYZV4DANCNFSM4VS7OB6Q .

danbodoh commented 3 years ago

I rewrote decode() (see https://github.com/danbodoh/pyacaia/commit/1fb9741664ec9306f4a4792aa0be69a18d7416df ) . The existing decode() assumes that the Message starts at the beginning of a BLE packet and that a Message ends at the end of a packet (although it allows the Message to be distributed among several packets) Neither assumption is true, which leads to lots of "non-message" errors that the existing code ignores. With the new decode(), there are no more "non-message" errors except for a couple of packets right at the beginning of notifications. I'll bet that this new decode() improves even the Lunar behavior.

But I still see the problem where the BLE packets get queued up and released only around the heartbeat time.

danbodoh commented 3 years ago

Luca, are you calling scale.device.waitForNotifications(timeout) at the application level?

I looked at the bluepy code, and I'm convinced that bluepy has no threading that would allow it to get async notify events. IT only looks for notifications when the user makes an API call. In pyacaia, the heartbeat is one of those situations, so that's why I'm seeing notifications at the heartbeat rate. If I add in the waitForNotifications() call in a loop, then I get a realtime stream of weight data.

lucapinello commented 3 years ago

Hi Dan,

Yes I had a while loop calling the scale.device.waitForNotifications(timeout).

Thanks for creating the new version and for digging into their protocol more closely. I will test your version this weekend with the Lunar and I will let you know how it goes.

So we can merge and release a new version.

Thanks!

Luca

On Fri, Jan 8, 2021 at 10:51 PM danbodoh notifications@github.com wrote:

Luca, are you calling scale.device.waitForNotifications(timeout) at the application level?

I looked at the bluepy code, and I'm convinced that bluepy has no threading that would allow it to get async notify events. IT only looks for notifications when the user makes an API call. In pyacaia, the heartbeat is one of those situations, so that's why I'm seeing notifications at the heartbeat rate. If I add in the waitForNotifications() call in a loop, then I get a realtime stream of weight data.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-757090072, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIH72UVWJOJIXPI52QVJJ3SY7HE5ANCNFSM4VS7OB6Q .

danbodoh commented 3 years ago

Luca,

I've been busy - I have a whole host of new updates, which I can do a PR after you take a look at the first. I've added read and write control to the timer, and reading of some of the settings. I've also done some work to improve the stability of the connection - do you see disconnects sometimes?

Dan

On Tue, Jan 12, 2021 at 7:19 AM Luca Pinello notifications@github.com wrote:

Hi Dan,

Yes I had a while loop calling the scale.device.waitForNotifications(timeout).

Thanks for creating the new version and for digging into their protocol more closely. I will test your version this weekend with the Lunar and I will let you know how it goes.

So we can merge and release a new version.

Thanks!

Luca

On Fri, Jan 8, 2021 at 10:51 PM danbodoh notifications@github.com wrote:

Luca, are you calling scale.device.waitForNotifications(timeout) at the application level?

I looked at the bluepy code, and I'm convinced that bluepy has no threading that would allow it to get async notify events. IT only looks for notifications when the user makes an API call. In pyacaia, the heartbeat is one of those situations, so that's why I'm seeing notifications at the heartbeat rate. If I add in the waitForNotifications() call in a loop, then I get a realtime stream of weight data.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <https://github.com/lucapinello/pyacaia/issues/4#issuecomment-757090072 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAIH72UVWJOJIXPI52QVJJ3SY7HE5ANCNFSM4VS7OB6Q

.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-758649881, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABNI66VDPCN7JHC46TCU3BLSZRD6JANCNFSM4VS7OB6Q .

lucapinello commented 3 years ago

That's fantastic! Yes, I have seen disconnecting events but they are really rare.

Sounds great, I will try this weekend and I will let you know.

On Tue, Jan 12, 2021 at 8:37 AM Dan Bodoh notifications@github.com wrote:

Luca,

I've been busy - I have a whole host of new updates, which I can do a PR after you take a look at the first. I've added read and write control to the timer, and reading of some of the settings. I've also done some work to improve the stability of the connection - do you see disconnects sometimes?

Dan

On Tue, Jan 12, 2021 at 7:19 AM Luca Pinello notifications@github.com wrote:

Hi Dan,

Yes I had a while loop calling the scale.device.waitForNotifications(timeout).

Thanks for creating the new version and for digging into their protocol more closely. I will test your version this weekend with the Lunar and I will let you know how it goes.

So we can merge and release a new version.

Thanks!

Luca

On Fri, Jan 8, 2021 at 10:51 PM danbodoh notifications@github.com wrote:

Luca, are you calling scale.device.waitForNotifications(timeout) at the application level?

I looked at the bluepy code, and I'm convinced that bluepy has no threading that would allow it to get async notify events. IT only looks for notifications when the user makes an API call. In pyacaia, the heartbeat is one of those situations, so that's why I'm seeing notifications at the heartbeat rate. If I add in the waitForNotifications() call in a loop, then I get a realtime stream of weight data.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub < https://github.com/lucapinello/pyacaia/issues/4#issuecomment-757090072 , or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAIH72UVWJOJIXPI52QVJJ3SY7HE5ANCNFSM4VS7OB6Q

.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <https://github.com/lucapinello/pyacaia/issues/4#issuecomment-758649881 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/ABNI66VDPCN7JHC46TCU3BLSZRD6JANCNFSM4VS7OB6Q

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-758659425, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIH72WG6HLCUJOYT2BFPJDSZRGBVANCNFSM4VS7OB6Q .

lucapinello commented 3 years ago

Dan great job! You have improved this library so much. I have just tested your new features, very cool. I have also uploaded the package 0.4 https://pypi.org/project/pyacaia/0.4.0/. The only minor problem I have is that sometimes after you successfully disconnect the small led on the scale stays on. Is this happening also for you?

I am attaching a minimal script to test this: `from pyacaia import AcaiaScale import time

scale=AcaiaScale(mac='00:1C:97:17:FD:97') scale.auto_connect() time.sleep(1)

for i in range(30): print(scale.weight) # this is the property we can use to read the weigth in realtime time.sleep(0.1)

scale.disconnect() time.sleep(1) `

The first time you execute this script the led goes off after the disconnect, but the second time stays on.

danbodoh commented 3 years ago

Luca, I haven't been able to replicate the behavior you described. Maybe there's a race that prevents the heartbeat thread from not being killed? Can you get any logs, or maybe see if there's either a thread or bluepy-helper still running after the first invocation?

lucapinello commented 3 years ago

Thanks for the tips, the thread finishes but I will keep investigating. Anyway, this is not a big deal!

On Sun, Jan 17, 2021 at 5:27 PM Dan Bodoh notifications@github.com wrote:

Luca, I haven't been able to replicate the behavior you described. Maybe there's a race that prevents the heartbeat thread from not being killed? Can you get any logs, or maybe see if there's either a thread or bluepy-helper still running after the first invocation?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/lucapinello/pyacaia/issues/4#issuecomment-761891526, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIH72XXQIOBDEGC5SVX34TS2NP4FANCNFSM4VS7OB6Q .