tgillbe / flymo2mqtt

3 stars 0 forks source link

Where to start… #1

Open nodecentral opened 2 years ago

nodecentral commented 2 years ago

Hi

Thanks so much for posting this, are you still using it yourself, is it working well ? I have a Flymo Easilife Go 150, and would love to get this working, but not exactly sure where to start (a bit of an idiots guide if poss) ?

it looks like I start here.. https://github.com/shmuelzon/esp32-ble2mqtt and get this set up ?

tgillbe commented 2 years ago

Sorry, but this project is not properly functional (so I'm not using it) - I uploaded it only for reference for others who may want to build on it. The problem I ran into was that I couldn't establish a reliable BLE connection to the lawnmower, but if you can maintain a connection then I'd love to know how! I tried both esp32-ble2mqtt and a USB BLE dongle but neither one was reliable for me. Really annoying as the project is 99% of the way to a MVP.

It does work for a minute or so if you get it set up. It should connect and print out the model / software version number of the lawnmower on start. After it will read the current state of the lawnmower and update the mqtt server once every 60 seconds for as long as it stays connected.

If you want to get it set up anyway knowing that, you'll need to ether set up that project or get a usb ble dongle (needs to be bluetooth 4.2 or above). The password is hardcoded as 1234 (power, calendar, start, home button) which you will need to change.

nodecentral commented 1 year ago

Still planning to come back to this so adding this here for future reference

https://esphome.io/components/bluetooth_proxy.html

esticle commented 1 year ago

Just came across this admitedly-shelved project whilst wondering if I can pull some of the state info via the Bluetooth connection of the mower. I'm therefore not too worried about the MQQT potion (although have a mosquito instance at hand) but more on the BLE portion even-if-unreliable...

Python (and BLE) noob here but would appreciate some help in achieving this - not sure how to replace mqtt for ble (and how to handle pygatt) myself...

totalitarian commented 1 year ago

Not having much luck connecting... any tips?

2023-04-10 09:54:50,697 - __main__ - DEBUG - Configuring packet interface
DEBUG:__main__:Configuring packet interface
2023-04-10 09:54:50,698 - __main__ - DEBUG - Sending connect
DEBUG:__main__:Sending connect
DEBUG:mower.packet_interface:Sending ConnectRequest
DEBUG:mower.mqtt_packet_interface:TX: 02fd160000000000002e1490a1795d000000004d
DEBUG:mower.mqtt_packet_interface:TX: 61696e004c03
DEBUG:mower.packet_interface:Sending ConnectRequest
DEBUG:mower.mqtt_packet_interface:TX: 02fd160000000000002e1490a1795d000000004d
DEBUG:mower.mqtt_packet_interface:TX: 61696e004c03
DEBUG:mower.packet_interface:Sending ConnectRequest
DEBUG:mower.mqtt_packet_interface:TX: 02fd160000000000002e1490a1795d000000004d
DEBUG:mower.mqtt_packet_interface:TX: 61696e004c03
2023-04-10 09:54:59,730 - __main__ - ERROR - Failed connecting
Traceback (most recent call last):
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\run.py", line 69, in <module>
    response = cast(ConnectResponse, interface.send(ConnectRequest(1568252304, 0, "Main")))
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\mower\mqtt_packet_interface.py", line 49, in send
    return self.interface.send(packet)
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\mower\packet_interface.py", line 41, in send
    data = self.receive_queue.get(block=True, timeout=3)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\queue.py", line 179, in get
    raise Empty
_queue.Empty
ERROR:__main__:Failed connecting
Traceback (most recent call last):
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\run.py", line 69, in <module>
    response = cast(ConnectResponse, interface.send(ConnectRequest(1568252304, 0, "Main")))
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\mower\mqtt_packet_interface.py", line 49, in send
    return self.interface.send(packet)
  File "C:\Users\lfixt\Downloads\flymo2mqtt-master\flymo2mqtt-master\src\mower\packet_interface.py", line 41, in send
    data = self.receive_queue.get(block=True, timeout=3)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\queue.py", line 179, in get
    raise Empty
_queue.Empty
esticle commented 1 year ago

Not having much luck connecting... any tips?

Blind leading the blind here but I think one has to start outside of the python script and get the Flymo pairing on the OS-side first, I finally got this going with bluetoothctl...

First get the mower's Bluetooth MAC, I picked it up from my phones Bluetooth device connections list, spin up 'bluetoothctl', replace 60:98:66:EF:61:F0 with whatever your device's MAC is.

In bluetoothctl:

agent KeyboardDisplay
pairable on
trust 60:98:66:EF:61:F0

You now need to get your Flymo into pairing mode, you do that (as per the manual) by powering it off and then on again, it will be in a 'pairable' state for 3 minutes, then in bluetoothctl issue:

pair 60:98:66:EF:61:F0
<you will hopefully be prompted for a pin - work it out as per the 1st reply in this Git issue>
connect 60:98:66:EF:61:F0

You should get a affirmative messgae, the bluetoothctl prompt should also change to "[EasiLife GO 500]" or whatever model you have. If not, give a shout as I've reverted to bt-agent which seems to work OK. The info command is also very useful to understand the state:

info 60:98:66:EF:61:F0
Device 60:98:66:EF:61:F0 (public)
        Name: EasiLife GO 500
        Alias: EasiLife GO 500
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (98bd0001-0b0e-421a-84e5-ddbf75dc6de4)

Now that I am able to pair I have been able to browse the characteristics like this:

$ gatttool -b 60:98:66:EF:61:F0 --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x000a, char properties = 0x04, char value handle = 0x000b, uuid = 98bd0002-0b0e-421a-84e5-ddbf75dc6de4
handle = 0x000d, char properties = 0x12, char value handle = 0x000e, uuid = 98bd0003-0b0e-421a-84e5-ddbf75dc6de4
handle = 0x0011, char properties = 0x02, char value handle = 0x0012, uuid = 98bd0004-0b0e-421a-84e5-ddbf75dc6de4

However unable to figure out how/what I should pull to translate for example the battery level or mower state, so guidance would be fantastic.

totalitarian commented 1 year ago

Great, i've managed to get connect via home assistant cli

        Name: EasiLife GO 250
        Alias: EasiLife GO 250
        Paired: no
        Trusted: yes
        Blocked: no
        Connected: no
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (98bd0001-0b0e-421a-84e5-ddbf75dc6de4)
        ManufacturerData Key: 0x0426

Next step is to install flymo2mqtt container and have a play

totalitarian commented 1 year ago

OK I can't connect using gattool, seems my pairing isn't working

Paired: no

tgillbe commented 1 year ago

Great to see you've made some progress @esticle

The mower communicates by writing to the write characteristic (98BD0002-0B0E-421A-84E5-DDBF75DC6DE4) and reading from the read characteristic (98BD0003-0B0E-421A-84E5-DDBF75DC6DE4). Once you've got a BLE connection you need to unlock the mower before you can read the battery level and state. Take a look at the code for how it's done: https://github.com/tgillbe/flymo2mqtt/blob/ea8e369280b2f5673777512e342e4ad938e0fc51/src/run.py#L68-L81

Basically you send a connect request, setup the protocol version then send the pin. The connection request has a hardcoded parameter 1568252304 in the code which may vary depending on the mower, I'm not sure it'll work for you but it works for me. The pin that needs to be sent is the same as what you press into the mower to unlock it, it's hardcoded as 1234 (power, calendar, start, home button).

If you want to take a look at the protocol messages to see how it works and you've got an android phone, you can use logcat. The official app outputs loads of great logging messages.

@totalitarian you've got to bond to the mower first, @esticle put a great guide up above. Problems with reliability of the bluetooth link was why I shelved the project though!

esticle commented 1 year ago

Great to see you've made some progress @esticle

Thanks for letting us abuse your shelved project's issue list :)

The mower communicates by writing to the write characteristic (98BD0002-0B0E-421A-84E5-DDBF75DC6DE4) and reading from the read characteristic (98BD0003-0B0E-421A-84E5-DDBF75DC6DE4). Once you've got a BLE connection you need to unlock the mower before you can read the battery level and state. Take a look at the code for how it's done:

Basically you send a connect request, setup the protocol version then send the pin. The connection request has a hardcoded parameter 1568252304 in the code which may vary depending on the mower, I'm not sure it'll work for you but it works for me. The pin that needs to be sent is the same as what you press into the mower to unlock it, it's hardcoded as 1234 (power, calendar, start, home button).

I cannot really read Python but figured you must have pulled 1568252304 from somehwere so I was hoping to get gatttoool equivelents of these commands. Similairly so for the '4586' for mower_activity, really appreciate the pointers as it appears I was roughly going in the right direction - but first attempts are failing... (b = write, e = read for me)

$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
connect to 60:98:66:EF:61:F0: Function not implemented (38)
$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
Characteristic Write Request failed: Request attribute has encountered an unlikely error
$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
Characteristic Write Request failed: Request attribute has encountered an unlikely error
$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
connect to 60:98:66:EF:61:F0: Function not implemented (38)
$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
connect to 60:98:66:EF:61:F0: Connection timed out (110)
$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 1568252304 
Characteristic value was written successfully
$ gatttool -b 60:98:66:EF:61:F0 --char-read -a 0x000e 
Characteristic value/descriptor: 
$ gatttool -b 60:98:66:EF:61:F0 --char-read -a 0x000e 
Characteristic value/descriptor: 
$ gatttool -b 60:98:66:EF:61:F0 --char-read -a 0x000e 
Characteristic value/descriptor: 

If you want to take a look at the protocol messages to see how it works and you've got an android phone, you can use logcat. The official app outputs loads of great logging messages.

Thanks for confirming - I was just going to start looking at that and was wondering if it logs the BLE messages, it will be interesting to confirm if I see 1568252304 as well (and I have a different pin which I figured out how to derive from your efforts).

@totalitarian you've got to bond to the mower first, @esticle put a great guide up above.

Yep @totalitarian in bluetootctl issue a 'connect MAC_ADDRESS' at which point it should ask for the PIN (if not, give a shout and we can look at bt-agent) - just make sure your mower is in pairing mode (recently turned on) before attempting this.

Problems with reliability of the bluetooth link was why I shelved the project though!

Yeah, it is very hit and miss even when parked as shown in the gatttool above, however I'm quite ok to get some-state-some-of-the-time, ie. a notification when stuck would be way better than myself currently monitoring power draw and where I have notification if I have NOT seen the mower charging for more than 8 hours :)

Thanks again for the tips, I'll report back on what I see.

totalitarian commented 1 year ago

So this is what I get after turning the mower on

pi@raspberrypi:~ $ bluetoothctl connect D8:71:4D:6C:E2:B4
Attempting to connect to D8:71:4D:6C:E2:B4
[CHG] Device D8:71:4D:6C:E2:B4 Connected: yes
Failed to connect: org.bluez.Error.Failed
tgillbe commented 1 year ago

The mower communicates by writing to the write characteristic (98BD0002-0B0E-421A-84E5-DDBF75DC6DE4) and reading from the read characteristic (98BD0003-0B0E-421A-84E5-DDBF75DC6DE4). Once you've got a BLE connection you need to unlock the mower before you can read the battery level and state. Take a look at the code for how it's done: Basically you send a connect request, setup the protocol version then send the pin. The connection request has a hardcoded parameter 1568252304 in the code which may vary depending on the mower, I'm not sure it'll work for you but it works for me. The pin that needs to be sent is the same as what you press into the mower to unlock it, it's hardcoded as 1234 (power, calendar, start, home button).

I cannot really read Python but figured you must have pulled 1568252304 from somehwere so I was hoping to get gatttoool equivelents of these commands. Similairly so for the '4586' for mower_activity, really appreciate the pointers as it appears I was roughly going in the right direction - but first attempts are failing... (b = write, e = read for me)

1568252304 is just a parameter in one of the packets (i.e. link_id, which in hex is 0x5D79A190). You need to send the whole packet to the characteristic - the connect packet looks like this (annotated with what I think each byte does):

0x02, // Start
0xFD, // Header?
0x16, 0x00, // Length
0x00, 0x00, 0x00, 0x00, // Channel ID
0x00, // Flag
0x2E, // Header CRC
0x14, // ConnectRequest.get_head()
0x90, 0xA1, 0x79, 0x5D, // ConnectRequest.link_id
0x00, 0x00, 0x00, 0x00, // ConnectRequest.node_type
0x4D, 0x61, 0x69, 0x6E, 0x00, // ConnectRequest.name
0x4C, // Full CRC
0x03 // End

The packet is split into chunks 20 bytes long. You can see it in the log messages from @totalitarian above:

DEBUG:mower.packet_interface:Sending ConnectRequest DEBUG:mower.mqtt_packet_interface:TX: 02fd160000000000002e1490a1795d000000004d DEBUG:mower.mqtt_packet_interface:TX: 61696e004c03

You could try sending this and see if you get anything back, I'm not certain of gatttool's endianness though:

gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 0x02fd160000000000002e1490a1795d000000004d gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 0x61696e004c03

You should get the following bytes in response:

0x02, // Start
0xFD, // Header?
0x0D, 0x00, // Length
0x00, 0x00, 0x00, 0x00, // Channel ID
0x00, // Flag
0x63, // Header CRC
0x15, // Packet type
0x90, 0xA1, 0x79, 0x5D, // New channel ID
0x30, // Full CRC
0x03 // End

A channel ID is sent in the response which needs to be included in future communications. If you provide an invalid CRC I don't think the lawnmower will respond.

esticle commented 1 year ago

So this is what I get after turning the mower on

Try it a number of times (like 10) - it should either (finally) connect or complain about Auth failing.

totalitarian commented 1 year ago

So this is what I get after turning the mower on

Try it a number of times (like 10) - it should either (finally) connect or complain about Auth failing.

So i'm confused about the flow here...

1) do I need to press anything on the mower - i.e enter the pin on the mower control panel? 2) Is this the correct sequence?

agent KeyboardDisplay
pairable on
trust D8:71:4D:6C:E2:B4
pair D8:71:4D:6C:E2:B4
**_I never get a prompt here at all_**
connect D8:71:4D:6C:E2:B4
esticle commented 1 year ago

Thanks for the reply!

1568252304 is just a parameter in one of the packets (i.e. link_id, which in hex is 0x5D79A190). You need to send the whole packet to the characteristic - the connect packet looks like this (annotated with what I think each byte does): The packet is split into chunks 20 bytes long. You can see it in the log messages from @totalitarian above:

Yep - so from logcat I see similair packets starting 02 FD - my PIN is 3333 fwiw and I think I lifted the relevant sections of just connecting and loading up the main screen.

04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinRequest@9f9e047
04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: Parameter [name=pin, type=uint16, length=0, boolValue=null, intValue=3333, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:11.091  3756  3857 V Sending:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D 
04-11 12:48:11.092  3756  3773 V Data written:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D 
04-11 12:48:11.092  3756  3857 V Sending:: 44 03 
04-11 12:48:11.093  8148  8982 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:11.093  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:11.093  3756  3773 V Data written:: 44 03 
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 38 12 04 00 00 00 00 AB 
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03 
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinResponse@731c99d
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$IsOperatorLoggedInRequest@80ede12
04-11 12:48:12.186  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 38 12 03 00 00 00 01 03 
04-11 12:48:12.187  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.187  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.188  3756  3774 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 38 12 03 00 00 00 01 03 
04-11 12:48:12.279  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 12 00 8C C9 C1 19 01 62 01 AF 38 12 03 00 00 01 00 01 
04-11 12:48:12.280  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: FF 03 
04-11 12:48:12.280  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.280  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$IsOperatorLoggedInResponse@9ea39e3
04-11 12:48:12.280  3756  3756 D AutomowerLinkedProtocol: Parameter [name=operatorLoggedIn, type=bool, length=0, boolValue=true, intValue=null, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:12.282  3756  3858 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.282  3756  3858 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.CalendarCommands$GetTimeRequest@eefffe0
04-11 12:48:12.283  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 52 12 02 00 00 00 82 03 
04-11 12:48:12.285  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.286  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.287  3756  3774 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 52 12 02 00 00 00 82 03 
04-11 12:48:12.374  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 15 00 8C C9 C1 19 01 D1 01 AF 52 12 02 00 00 04 00 0B 
04-11 12:48:12.374  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 57 35 64 70 03 
04-11 12:48:12.375  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.375  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.CalendarCommands$GetTimeResponse@3666299
04-11 12:48:12.375  3756  3756 D AutomowerLinkedProtocol: Parameter [name=time, type=tUnixTime, length=0, boolValue=null, intValue=null, longValue=1681217291, stringValue=null, dataValue=null]
04-11 12:48:12.436  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.436  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@10cd059
04-11 12:48:12.436  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.438  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.439  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.440  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.611  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F 
04-11 12:48:12.611  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03 
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@9c21434
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@e02a25d
04-11 12:48:12.614  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.615  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.615  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.616  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.708  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F 
04-11 12:48:12.709  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03 
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@585a7d2
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@176a0a3
04-11 12:48:12.709  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.710  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.711  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:62:B4
04-11 12:48:12.711  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.802  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F 
04-11 12:48:12.802  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03 
04-11 12:48:12.802  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.802  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@5863fa0
04-11 12:48:12.802  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.802  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@74c0759
04-11 12:48:12.803  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.805  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.807  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.808  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.896  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F 
04-11 12:48:12.896  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03 
04-11 12:48:12.896  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.897  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@d726f1e
04-11 12:48:12.897  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.897  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@6c8a3ff
04-11 12:48:12.897  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 
04-11 12:48:12.899  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.899  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.900  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03 

I cannot however make any heads-or-tails of where the equivelent of 0x5D79A190 factors in here

DEBUG:mower.packet_interface:Sending ConnectRequest DEBUG:mower.mqtt_packet_interface:TX: 02fd160000000000002e1490a1795d000000004d DEBUG:mower.mqtt_packet_interface:TX: 61696e004c03

I've never gotten anything but a 'Failed connecting' even though I have addressed the PIN value appropriately in your code - so maybe there is some uniqueness here.

You could try sending this and see if you get anything back, I'm not certain of gatttool's endianness though:

gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 0x02fd160000000000002e1490a1795d000000004d gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 0x61696e004c03

You should get the following bytes in response:

0x02, // Start
0xFD, // Header?
0x0D, 0x00, // Length
0x00, 0x00, 0x00, 0x00, // Channel ID
0x00, // Flag
0x63, // Header CRC
0x15, // Packet type
0x90, 0xA1, 0x79, 0x5D, // New channel ID
0x30, // Full CRC
0x03 // End

A channel ID is sent in the response which needs to be included in future communications. If you provide an invalid CRC I don't think the lawnmower will respond.

Thanks for this! I was hoping something like this would get me going - sadly:

$ gatttool -b 60:98:66:EF:61:F0 --char-write-req -a 0x000b -n 0x02fd160000000000002e1490a1795d000000004d
Characteristic Write Request failed: Attribute value length is invalid

If gatttool is a no-go and makes the conversion hard Python is probably the way to go although I have no idea of where to begin with replacing yours with ble_packet_interface - darn, more questions than answers now! :)

totalitarian commented 1 year ago

I can get connected but not paired for some reason

[EasiLife GO 250]# info
Device D8:71:4D:6C:E2:B4 (public)
        Name: EasiLife GO 250
        Alias: EasiLife GO 250
        Paired: no
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (98bd0001-0b0e-421a-84e5-ddbf75dc6de4)
        ManufacturerData Key: 0x0426
        ManufacturerData Value:
totalitarian commented 1 year ago

OK maybe I don't need to be paired?

pi@raspberrypi:~ $ gatttool -b D8:71:4D:6C:E2:B4 --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0006, char properties = 0x02, char value handle = 0x0007, uuid = 00002a04-0000-1000-8000-00805f9b34fb
handle = 0x000a, char properties = 0x04, char value handle = 0x000b, uuid = 98bd0002-0b0e-421a-84e5-ddbf75dc6de4
handle = 0x000d, char properties = 0x12, char value handle = 0x000e, uuid = 98bd0003-0b0e-421a-84e5-ddbf75dc6de4
handle = 0x0011, char properties = 0x02, char value handle = 0x0012, uuid = 98bd0004-0b0e-421a-84e5-ddbf75dc6de4
esticle commented 1 year ago

Try it a number of times (like 10) - it should either (finally) connect or complain about Auth failing.

So i'm confused about the flow here...

  1. do I need to press anything on the mower - i.e enter the pin on the mower control panel?

Nope, just turn it off and on again, if you enter the 'connect' bit within 3 minutes when it is in 'pair' mode you should be good.

  1. Is this the correct sequence?
agent KeyboardDisplay
pairable on
trust D8:71:4D:6C:E2:B4
pair D8:71:4D:6C:E2:B4
**_I never get a prompt here at all_**
connect D8:71:4D:6C:E2:B4

I had 'power on' as well, but the above should do. Depending on version of bluetoothctl some people have different outcomes - IF you get AuthFailed as a response you can use bt-agent like this:

$ echo "D8:71:4D:6C:E2:B4 1234" > ~/pincodes
$ bt-agent -d -c KeyboardOnly ~/pincodes

Change your pin from 1234 to whatever yours is depending on the buttons as per @tgillbe 's comments above.

I would not encourage to make the sitsuation 'messy' in doing the above until you confirm you get a failed Auth condition with using 'connect' - especially since tgillbe's code uses the PIN anyway.

Hope that helps!

esticle commented 1 year ago

OK maybe I don't need to be paired?

You can grab the characteristics and you will get some responses but not be able to read (and possibly write) all values when NOT paired.

totalitarian commented 1 year ago

I'm lost then, nothing I do lets me pair, I don't get any prompt. Can connect all day long though

pi@raspberrypi:~ $ bluetoothctl connect D8:71:4D:6C:E2:B4
Attempting to connect to D8:71:4D:6C:E2:B4
[CHG] Device D8:71:4D:6C:E2:B4 Connected: yes
Connection successful
esticle commented 1 year ago

I'm lost then, nothing I do lets me pair, I don't get any prompt. Can connect all day long though

pi@raspberrypi:~ $ bluetoothctl connect D8:71:4D:6C:E2:B4
Attempting to connect to D8:71:4D:6C:E2:B4
[CHG] Device D8:71:4D:6C:E2:B4 Connected: yes
Connection successful

Run 'bluetoothctl' on it's own so it is in interactive mode and run the 'connect' again - once it connects the prompt should change to [Flymo 500] or similair - then issue the 'info D8:71:4D:6C:E2:B4' command - if 'Connected' stays it should say it is paired as well.

totalitarian commented 1 year ago

Tried that, seems to work but doesn't say paired

pi@raspberrypi:~ $ bluetoothctl
Agent registered
[bluetooth]# connect D8:71:4D:6C:E2:B4
Attempting to connect to D8:71:4D:6C:E2:B4
[CHG] Device D8:71:4D:6C:E2:B4 Connected: yes
Connection successful
[CHG] Device D8:71:4D:6C:E2:B4 ServicesResolved: yes
[EasiLife GO 250]# info
Device D8:71:4D:6C:E2:B4 (public)
        Name: EasiLife GO 250
        Alias: EasiLife GO 250
        Paired: no
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
tgillbe commented 1 year ago

@esticle

I cannot however make any heads-or-tails of where the equivelent of 0x5D79A190 factors in here

You've snipped off the ConnectRequest from the start of the log! Scroll up a bit. Your log starts at EnterOperatorPinRequest but that gets sent after the connection is initialised. Search for ConnectRequest in the log file. As shown from my code above, the sequence is:

If gatttool is a no-go and makes the conversion hard Python is probably the way to go although I have no idea of where to begin with replacing yours with ble_packet_interface - darn, more questions than answers now! :)

You may be able to use gatttool, but the problem you're going to encounter is that a channel ID is generated by the lawnmower when you connect which needs to be put into future messages to get the lawnmower to respond. This channel ID is included in two CRCs, so you'll need to use some sort of programming to incorporate the channel ID and to calculate the CRCs.

@totalitarian

If I recall correctly, you need to bond within the first 3 minutes of the lawnmower being turned on. Are you restarting the lawnmower before attempting to connect? You should be able to use paired-devices to see the device if you've paired it correctly.

esticle commented 1 year ago

Tried that, seems to work but doesn't say paired

I assume you get the same within bluetoothctl in interactive mode if you do 'pair MAC' followed by 'connect MAC' and then the 'info' ? All within 3 minutes of power-on as mentioned as step 2 in the documentation.

image

esticle commented 1 year ago

Thanks @tgillbe

You've snipped off the ConnectRequest from the start of the log! Scroll up a bit. Your log starts at EnterOperatorPinRequest but that gets sent after the connection is initialised. Search for ConnectRequest in the log file. As shown from my code above, the sequence is:

Thanks for spelling it out - I think I fished them out from the previous test on Android...

  • ConnectRequest
04-11 12:48:10.046  3756  3756 D AutomowerLinkedProtocol: com.husqvarnagroup.dss.amc.blelib.bluetooth.hcp.linkmanagercommands.LinkManagerCommands$ConnectRequest@8a7a1dc
04-11 12:48:10.046  3756  3756 D AutomowerLinkedProtocol: Parameter [name=linkId, type=uint32, length=0, boolValue=null, intValue=null, longValue=432130444, stringValue=null, dataValue=null]
04-11 12:48:10.046  3756  3756 D AutomowerLinkedProtocol: Parameter [name=nodeType, type=uint32, length=0, boolValue=null, intValue=null, longValue=0, stringValue=null, dataValue=null]
04-11 12:48:10.046  3756  3756 D AutomowerLinkedProtocol: Parameter [name=name, type=ascii, length=0, boolValue=null, intValue=null, longValue=null, stringValue=Main, dataValue=null]
04-11 12:48:10.047  3756  3857 V Sending:: 02 FD 16 00 00 00 00 00 00 2E 14 8C C9 C1 19 00 00 00 00 4D
04-11 12:48:10.049  3756  3773 V Data written:: 02 FD 16 00 00 00 00 00 00 2E 14 8C C9 C1 19 00 00 00 00 4D
04-11 12:48:10.049  3756  3857 V Sending:: 61 69 6E 00 15 03
04-11 12:48:10.049  8148  9819 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:10.050  3756  3773 V Data written:: 61 69 6E 00 15 03
04-11 12:48:10.378  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 0D 00 00 00 00 00 00 63 15 8C C9 C1 19 C9 03
04-11 12:48:10.379  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:10.379  3756  3756 D AutomowerLinkedProtocol: com.husqvarnagroup.dss.amc.blelib.bluetooth.hcp.linkmanagercommands.LinkManagerCommands$ConnectResponse@d33d1ba
04-11 12:48:10.379  3756  3756 D AutomowerLinkedProtocol: Parameter [name=responseId, type=uint8, length=0, boolValue=null, intValue=21, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:10.379  3756  3756 D AutomowerLinkedProtocol: Parameter [name=newLinkId, type=uint32, length=0, boolValue=null, intValue=null, longValue=432130444, stringValue=null, dataValue=null]
04-11 12:48:10.379  8148  9819 I BluetoothAdapterService: getActiveDevices: A2dp device: null
04-11 12:48:10.380  3756  3756 D AutomowerLinkedProtocol: Sending
  • SetProtocolVersionRequest
04-11 12:48:10.380  3756  3756 D AutomowerLinkedProtocol: com.husqvarnagroup.dss.amc.blelib.bluetooth.hcp.linkmanagercommands.LinkManagerCommands$SetProtocolVersionRequest@8d3286b
04-11 12:48:10.380  3756  3756 D AutomowerLinkedProtocol: Parameter [name=protocol, type=uint8, length=0, boolValue=null, intValue=1, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:10.381  3756  3857 V Sending:: 02 FD 0A 00 8C C9 C1 19 00 36 08 01 28 03
04-11 12:48:10.382  8148  1239 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:10.382  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:10.382  3756  3773 V Data written:: 02 FD 0A 00 8C C9 C1 19 00 36 08 01 28 03
  • EnterOperatorPinRequest
04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinRequest@9f9e047
04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: Parameter [name=pin, type=uint16, length=0, boolValue=null, intValue=3333, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:11.091  3756  3857 V Sending:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D
04-11 12:48:11.092  8148  8982 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:11.092  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:11.092  3756  3773 V Data written:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D
04-11 12:48:11.092  3756  3857 V Sending:: 44 03
04-11 12:48:11.093  8148  8982 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:11.093  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:11.093  3756  3773 V Data written:: 44 03
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 38 12 04 00 00 00 00 AB
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinResponse@731c99d
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Sending
  • IsOperatorLoggedInRequest
04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinRequest@9f9e047
04-11 12:48:11.090  3756  3756 D AutomowerLinkedProtocol: Parameter [name=pin, type=uint16, length=0, boolValue=null, intValue=3333, longValue=null, stringValue=null, dataValue=null]
04-11 12:48:11.091  3756  3857 V Sending:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D
04-11 12:48:11.092  8148  8982 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:11.092  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:11.092  3756  3773 V Data written:: 02 FD 12 00 8C C9 C1 19 01 62 00 AF 38 12 04 00 02 00 05 0D
04-11 12:48:11.092  3756  3857 V Sending:: 44 03
04-11 12:48:11.093  8148  8982 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:11.093  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:11.093  3756  3773 V Data written:: 44 03
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 38 12 04 00 00 00 00 AB
04-11 12:48:12.185  3756  3774 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.AuthenticationCommands$EnterOperatorPinResponse@731c99d
04-11 12:48:12.185  3756  3756 D AutomowerLinkedProtocol: Sending

I then see some others, like KeepAliveRequest:

04-11 12:48:12.436  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.436  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@10cd059
04-11 12:48:12.436  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03
04-11 12:48:12.438  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.439  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.440  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03
04-11 12:48:12.611  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F
04-11 12:48:12.611  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@9c21434
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.613  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@e02a25d
04-11 12:48:12.614  3756  3857 V Sending:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03
04-11 12:48:12.615  8148  8161 D BtGatt.GattService: writeCharacteristic() - trying to acquire permit.
04-11 12:48:12.615  8148  8182 D BtGatt.GattService: onWriteCharacteristic() - increasing permit for address=60:98:66:EF:61:F0
04-11 12:48:12.616  3756  3773 V Data written:: 02 FD 10 00 8C C9 C1 19 01 18 00 AF 42 12 02 00 00 00 D9 03
04-11 12:48:12.708  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 02 FD 11 00 8C C9 C1 19 01 25 01 AF 42 12 02 00 00 00 00 6F
04-11 12:48:12.709  3756  3773 V com.husqvarnagroup.dss.amc.blelib.bluetooth.BleDevice@ed922e5 Received:: 03
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: Received OK Response
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveResponse@585a7d2
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: Sending
04-11 12:48:12.709  3756  3756 D AutomowerLinkedProtocol: com.gardena.libraries.bluetooth_mower.bluetooth_mower.mowerconnection.commands.SystemPowerCommands$KeepAliveRequest@176a0a3

GetBatteryLevelRequest and other niceities!

If gatttool is a no-go and makes the conversion hard Python is probably the way to go although I have no idea of where to begin with replacing yours with ble_packet_interface - darn, more questions than answers now! :)

You may be able to use gatttool, but the problem you're going to encounter is that a channel ID is generated by the lawnmower when you connect which needs to be put into future messages to get the lawnmower to respond. This channel ID is included in two CRCs, so you'll need to use some sort of programming to incorporate the channel ID and to calculate the CRCs.

In contrast, I don't mind some bash (would have to for the retry-handling anyhow) - so from your packet structure it appears after the IsOperatorLoggedInRequest section that the channelID above was 8C C9 C1 19 ? Need to figure out how to make it spit that out...

tgillbe commented 1 year ago

If gatttool is a no-go and makes the conversion hard Python is probably the way to go although I have no idea of where to begin with replacing yours with ble_packet_interface - darn, more questions than answers now! :)

You may be able to use gatttool, but the problem you're going to encounter is that a channel ID is generated by the lawnmower when you connect which needs to be put into future messages to get the lawnmower to respond. This channel ID is included in two CRCs, so you'll need to use some sort of programming to incorporate the channel ID and to calculate the CRCs.

In contrast, I don't mind some bash (would have to for the retry-handling anyhow) - so from your packet structure it appears after the IsOperatorLoggedInRequest section that the channelID above was 8C C9 C1 19 ? Need to figure out how to make it spit that out...

Good progress! Agreed that your link ID seems to be 8C C9 C1 19 (or 432130444), so you'll need to change that too if you try and use my code. No idea where it gets this from - maybe the app creates it and saves it? There is a CreateLinkRequest packet after all, but I've never seen it sent (didn't log the setup process in the app). I haven't observed it changing the link ID so you could try and just hardcode it.

If you can find a setup which reliably keeps a BLE connection (or can be automatically reconnected without touching the mower) then please let me know! It would be great to get this working. I think I had to restart the mower to get the connection back.

totalitarian commented 1 year ago

Tried that, seems to work but doesn't say paired

I assume you get the same within bluetoothctl in interactive mode if you do 'pair MAC' followed by 'connect MAC' and then the 'info' ? All within 3 minutes of power-on as mentioned as step 2 in the documentation.

image

Afraid so. Think i'm going to just fit a contact sensor and motion sensor and be done with it. Good luck, hopefully one day i'll be back to congratulate you both on a home assistant addon :)

esticle commented 1 year ago

Thanks @tgillbe

Good progress! Agreed that your link ID seems to be 8C C9 C1 19 (or 432130444), so you'll need to change that too if you try and use my code. No idea where it gets this from - maybe the app creates it and saves it? There is a CreateLinkRequest packet after all, but I've never seen it sent (didn't log the setup process in the app). I haven't observed it changing the link ID so you could try and just hardcode it.

Somewhat confused as I have replaced all instances of 1568252304 to my 432130444 (and of course the PIN) and having no go at all with your run.py.

I've also had a stab at re-playing my Android version of ConnectRequest with bluetoothctl and not having much luck - does not matter what I write to it, it disconnects immediately.

[bluetooth]# connect 60:98:66:EF:61:F0
Attempting to connect to 60:98:66:EF:61:F0
[CHG] Device 60:98:66:EF:61:F0 Connected: yes
Connection successful
[CHG] Device 60:98:66:EF:61:F0 ServicesResolved: yes
[EasiLife GO 500]# menu gatt
[EasiLife GO 500]# select-attribute 98BD0002-0B0E-421A-84E5-DDBF75DC6DE4
[EasiLife GO 500:/service0009/char000a]# attribute-info
Characteristic - Vendor specific
        UUID: 98bd0002-0b0e-421a-84e5-ddbf75dc6de4
        Service: /org/bluez/hci0/dev_60_98_66_EF_61_F0/service0009
        Flags: write-without-response
[EasiLife GO 500:/service0009/char000a]# write "0x02 0xFD 0x16 0x00 0x00 0x00 0x00 0x00 0x00 0x2E 0x14 0x8C 0xC9 0xC1 0x19 0x00 0x00 0x00 0x00 0x4D"
Attempting to write /org/bluez/hci0/dev_60_98_66_EF_61_F0/service0009/char000a
[CHG] Device 60:98:66:EF:61:F0 ServicesResolved: no
[CHG] Device 60:98:66:EF:61:F0 Connected: no
[bluetooth]#

No different with the integer version or if I inject my 8C C9 C1 19 as the channelID, so hoping it's something obvious - however thought your script would give something up now too! :)

If you can find a setup which reliably keeps a BLE connection (or can be automatically reconnected without touching the mower) then please let me know! It would be great to get this working. I think I had to restart the mower to get the connection back.

With bt-agent described above I can (with some retries) get the paired/trusted/connected flags all to 'yes' without touching the mower - it seems to disconnect about ~60 seconds after the 'info' command below so maybe it does that KeepAlive stuff we saw every few seconds in a real connection...

esticle@bluepi:~/flymo2mqtt $ bluetoothctl
Agent registered
[bluetooth]# connect 60:98:66:EF:61:F0
Attempting to connect to 60:98:66:EF:61:F0
Failed to connect: org.bluez.Error.Failed
[bluetooth]# connect 60:98:66:EF:61:F0
Attempting to connect to 60:98:66:EF:61:F0
[CHG] Device 60:98:66:EF:61:F0 Connected: yes
Failed to connect: org.bluez.Error.Failed
[CHG] Device 60:98:66:EF:61:F0 Connected: no
[bluetooth]# connect 60:98:66:EF:61:F0
Attempting to connect to 60:98:66:EF:61:F0
[CHG] Device 60:98:66:EF:61:F0 Connected: yes
Connection successful
[CHG] Device 60:98:66:EF:61:F0 ServicesResolved: yes
[EasiLife GO 500]# info
Device 60:98:66:EF:61:F0 (public)
        Name: EasiLife GO 500
        Alias: EasiLife GO 500
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (98bd0001-0b0e-421a-84e5-ddbf75dc6de4)
[bluetooth]#
...1 min later...
[CHG] Device 60:98:66:EF:61:F0 ServicesResolved: no
[CHG] Device 60:98:66:EF:61:F0 Connected: no
[bluetooth]# 
totalitarian commented 1 year ago

How are you calculating the channel id? I think mine is fab8276b