Yesterday I returned to Snap! to fast write a LEGO WeDo 1.0 extension.
It just requires two files:
A python script that implements a very basic HTTP server that exposes the WeDo 1.0 methods from WeDoMaster library.
A xml file containg 3 Snap! custom blocks (motor, tilt sensor and distance sensor)
It works on Raspberry Pi so anyone that wants to use the LEGO WeDo 1.0 just need an RPi and a browser with internet access. I used a Raspberry Pi Zero W so just a USB Hub with microUSB port and a power source is needed.
Great news – LEGO Eduction released the WeDo 2.0 SDK today!
After digging into it, I found the information needed to control the Piezo: as expected, it’s controlled by the same handle that is used for controlling the motor and the RGB LED (0x003d). The “port” is “05” and the “command” to activate the Piezo is “02”, followed by a payload of “04” bytes containing:
the Frequency in Hz (2 bytes, reversed)
the duration in ms (2 bytes, reversed)
So to play a “C” (or “Do”, 261 Hz) during 1/8 of a second (125 ms) we use this command:
This post tries to gather all the information I collected in the last weeks related to the WeDo 2.0.
I’m not a programmer but I’m a very stubborn guy so after I managed to get my linux systems (my Ubuntu laptop, some Raspberry Pi’s and my two Mindstorms EV3) controlling the SBrick I told to myself: I’m gonna make the same with this new WeDo 2.0 system no matter what it takes.
So first things first: let’s use my Android mobile to inspect the WeDo 2.0 Hub. Nordic has a very good (and free) app that I like to use: nRF Master Control Panel (recently renamed to nRF Connect). After connecting to the Hub we find 6 services:
Some of this services, like “Battery Service” are known BLE services so [hopefully] it will be easy to use.
There’s also a very important finding at the top:
“U0001 A0:E6:F8:1E:58:57
“A0:E6:F8:1E:58:57” is the Bluetooth address of my Hub (similar to the MAC Address of every network device). It will be used *a lot* in the rest of this post.
And “U0001” is the friendly name that the Hub advertises – that’s the name that shows up in the LEGO Education WeDo 2.0 App when connecting to the Hub:
A note about this name: before I finally managed to make the LEGO Education WeDo 2.0 App work in my Android phone, my Hub advertised itself as “LPF2 Smart Hub 2 I/O”. So the LEGO App changed it to “u0001”, probably at the first time it connected to it (but since my Hub was first used by 3 other AFOL’s at Paredes de Coura I’m not sure if the process is automatic or the user is given some kind of option).
So the default (factory set) name of the Hub is “LPF2 Smart Hub 2 I/O” – LEGO Power Functions 2 Smart Hub 2 I/O”. Not much to speculate here: LEGO announced that Power Functions and Mindstorms will adopt a new plug type so new devices are expected, this is just the first one. But “Smart Hub 2 I/O” is interesting… does that means that there will be other Smart Hubs? Perhaps even a “Smart Hub 4 I/O”? That would answer some of the points I have been discussing with Fernando Conchas like “what’s the use for a 4.5 Volt device in LEGO Technic unless there’s also another device with better power features just waiting to come out”?
Now let’s look deeper to those BLE services…
I can use the nRF App and take a lot of screenshots but now that I know the BT address I will switch to my Ubuntu laptop and use 2 of the available BlueZ (the native Linux Bluetooth stack) functions, ‘hcitool’ and ‘gatttool’
The ‘gatttool’ command is a powerfull tool for BLE – in the past, without a proper BLE library for python, I used it (through python system calls) to talk with the SBrick. Clumsy but… hey, I said I’m not a programmer 😉
The ‘gatttool’ can run in an interactive mode that allows us to establish a connection and keep it until we disconnect instead of making a new connection each time we want to test a command:
$ sudo gatttool -i hci0 -I
[ ][LE]> connect A0:E6:F8:1E:58:57
Attempting to connect to A0:E6:F8:1E:58:57
Connection successful
[A0:E6:F8:1E:58:57][LE]>
In this “interactive” session we just send ‘primary’ to get the same output as using the command with ‘–primary’ option [but sometimes the commands differ a bit, so use ‘help’ and ‘–help’ to know what to use.
So the ‘primary’ command gets a list of the primary services offered by the WeDo 2.0 Hub. Of course, those are the same 6 services found by the Nordic app but that screenshot looks much better as Nordic developers added lots of intelligence to it.
So this service has 7 handles assigned (from 0x0001 to 0x0007) and serves a well know service (the ‘Generic Access‘) so it’s UUID is shortened to just 0x1800 instead of ‘00001800-0000-1000-8000-00805f9b34fb’.
Bluetooth specification for ‘Generic Access’ defines 5 properties:
From these list, only ‘Device Name’ and ‘Appearance’ are defined as ‘Mandatory’.
With the gatttool we read these properties with command ‘char-read-uuid’:
[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A00
handle: 0x0003 value: 75 30 30 30 31
[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A01
handle: 0x0005 value: 00 00
[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A02
Error: Read characteristics by UUID failed: No attribute found within the given range
[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A03
Error: Read characteristics by UUID failed: No attribute found within the given range
[A0:E6:F8:1E:58:57][LE]> char-read-uuid 0x2A04
handle: 0x0007 value: 50 00 a0 00 00 00 e8 03
So ‘Peripheral Privacy Flag’ and ‘Reconnection Address’ were not implemented by LEGO. But what’s the meaning of this hexadecimal values?
‘Device Name‘ is a string so we just convert it to ASCII (we can use an online tool like RapidTables):
75 30 30 30 31 -> u0001
Ah-ha!
‘Appearance‘ is two-byte value “composed of a category (10-bits) and sub-categories (6-bits)” that classifies the device. Since it is ‘0’, it’s not classified in any known category (so it is ‘Unknown’).
Now that I can finally use LEGO Education WeDo 2.0 app let’s use my latest crazy aquisition: the Ubertooth One (an open source Bluetooth sniffer).
I used a simple project to change the WeDo 2.0 Hub color to ‘pink’ (‘1’) each time I click the ‘Play’ block:
After capturing a few packets I selected just the interesting part:
1 0.000000000 LE LL 33 Empty PDU
2 0.037564000 ATT 44 UnknownDirection Write Command, Handle: 0x003d
3 0.074999800 LE LL 33 Empty PDU
4 0.187500200 LE LL 33 Empty PDU
5 0.225000800 LE LL 33 Empty PDU
6 0.262503000 LE LL 33 Empty PDU
7 0.262732400 LE LL 33 Empty PDU
8 0.375069400 ATT 44 UnknownDirection Write Command, Handle: 0x003d
9 0.412505800 LE LL 33 Empty PDU
Most frames are empty but 2 frames (‘2’ and ‘8’) show some writing to the 0x003d handle (the same handle that is used to control the motors). Let’s inspect those frames:
Frame 2: 44 bytes on wire (352 bits), 44 bytes captured (352 bits) on interface 0
PPI version 0, 24 bytes
DLT: 147, Payload: btle (Bluetooth Low Energy Link Layer)
Bluetooth Low Energy Link Layer
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
Opcode: Write Command (0x52)
0... .... = Authentication Signature: False
.1.. .... = Command: True
..01 0010 = Method: Write Request (0x12)
Handle: 0x003d
Value: 06040101
Frame 8: 44 bytes on wire (352 bits), 44 bytes captured (352 bits) on interface 0
PPI version 0, 24 bytes
DLT: 147, Payload: btle (Bluetooth Low Energy Link Layer)
Bluetooth Low Energy Link Layer
Bluetooth L2CAP Protocol
Bluetooth Attribute Protocol
Opcode: Write Command (0x52)
0... .... = Authentication Signature: False
.1.. .... = Command: True
..01 0010 = Method: Write Request (0x12)
Handle: 0x003d
Value: 06040103
So the App is writing “06040101” to the handle and then “06040103”.
I already know something about this handler from the motor control examples I found before:
first byte is the “port” identifier (’01’ and ’02’ are the physical plugs to connect motors or sensors so ’06’ is the LED port)
second byte is the command sent to the port so ’04’ means “change color”
third byte is the length of the arguments of the command so ’01’ means that the color is just one byte length – the fourth
So ’01’ and ’03’ must be some colors right? And I already know that ‘1’ in the App means ‘red’ so probably “06040101” means “change color to pink” and “06040103” means “change color to blue” (blue is the color of the WeDo Hub while waiting for commands).
So let’s test it with gatttool:
char-write-cmd 3d 06040101
Yes! It turns red indeed!
After testing other values I got these 11 values:
00 off
01 pink
02 purple
03 blue
04 cyan
05 light green
06 green
07 yellow
08 orange
09 red
0A light blue
(the real color labels may differ as I’m not very good with colors)
Now a small python script to cycle through all those colors:
#!/usr/bin/python
from gattlib import GATTRequester
from time import sleep
colors = ['\x00','\x01','\x02','\x03','\x04','\x05','\x06','\x07','\x08','\x09','\x0A']
req = GATTRequester("A0:E6:F8:1E:58:57",True,"hci0")
while True:
for color in colors:
req.write_by_handle(0x3d, "\x06\x04\x01" + color)
sleep(2)