The new LEGO Powered Up Remote Control

This post is part 1 of 2 of  LEGO Powered Up Remote Control

This week I got a question from Nathan Kunicki about using the BOOST Tacho Motor with the new Powered Up hub.

He already succeeded with the other WeDo 2 and BOOST devices so the motor was the last challenge. So I tried a few ideas but nothing.

I told him that probably the motor was not supported by the current firmware… and then he told me that when we use the new Remote it works (as if a WeDo 2 motor, just ON or OFF).

Well… my lovely wife just gave me this weekend my future birthday gift: the new LEGO Cargo Train. And it has a Powered Up remote so… let me try it.

No, we couldn’t find a way to control the motor. But I learned a bit about the Remote (thanks Nathan!) Enough to use it as a standalone BLE controller without the LEGO Powered Up “HUB NO.4″… it’s so easy that any BLE master can use it.

And, of course, the MINDSTORMS EV3 when running ev3dev:

to be continued…

 

The BLE properties

This post is part 2 of 2 of  LEGO Powered Up Remote Control

First things first: the Remote Control BT Address and friendly name:

A4:34:F1:CE:DC:A2  “Handset”

The BT address is not a LEGO one like the BOOST (00:16:53, “LEGO System A/S IE Electronics Division”) or the Powered Up (90:84:2B, “LEGO System A/S”). It’s a Texas Instruments chipset, probably something like the CC2640, a ARM microcontroller with embedded BLE functions.

The usual browsing of properties with gatttool reveals 3 primary services and a few characteristics:

primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0xffff uuid: 00001623-1212-efde-1623-785feabcd123
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: 0x1c, char value handle: 0x000b, uuid: 00001624-1212-efde-1623-785feabcd123
char-desc 
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0008, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000a, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000b, uuid: 00001624-1212-efde-1623-785feabcd123
handle: 0x000c, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 00002901-0000-1000-8000-00805f9b34fb

More details from the Nordic nRF Connect app:

The first primary service (1800, Genneric Access) has 3 chars:
Device Name: Handset
Appearance: Unknown
Peripheral Preferred Connection Parameters: Connection Interval: 100.00ms-200.00ms, Slave Latency:0, Supervision Timeout Multiplier: 1000

The second primary service (1801, Generic Attribute) is empty. Not unusual since it is optional.

The last primary service has the same UUID already present on BOOST and Powered Up hubs (i.e. “00001624-1212-efde-1623-785feabcd123”). And like those it has only one characteristic, “LWP ProtocolChar”.

(side note: LWP might mean Light Weight Process or LEGO Wireless Protocol or just Lets Worsen your Pain)

Thats good: since this “Handset” shares the same primary service UUID of the other PF2 / Powered Up devices, it might also work in the same way.

So lets enable notifications and see what we got:

char-write-req 0x0c 0100
Notification handle = 0x000b value: 0f 00 04 00 01 37 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 01 01 37 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 34 01 17 00 00 00 00 10 00 00 00 10 
Notification handle = 0x000b value: 0f 00 04 3b 01 14 00 02 00 00 00 02 00 00 00 
Notification handle = 0x000b value: 0f 00 04 3c 01 38 00 00 00 00 10 00 00 00 10

Yeap! 4 devices on 5 different ports:

  • Device ’37’ on ports ’00’ and ’01’
  • Device ’17’ present on port ’34’
  • Device ’14’ present on port ‘3B’
  • Device ’38’ present on port ‘3C’

Nathan already told me that device ’37’ is associated to the buttons. So two “pads” of buttons, one on port ’00’ and other on port ’01’.

Device ’17’ is the RGB LED on the BOOST. I’ll look to it later.

Device ’14’ and ’38’, like Nathan pointed, seem Voltage and Current readings. We can activate each with:

char-write-req 0x0b 0a0041[3B/3C]000100000001

The first (3B) will generate regular messages like ’06 00 45 3b a5 0b’ and the second (3C) also generates regular messages like ’05 00 45 3c cc’

So the payload is ‘3B A5 0B’ and ‘3C CC’, reverting and converting to decimal it gives

0BA53B = 763195 = 7.63  Volt ? hard to believe with just 4 AAA batteries

converting to float = 0.00503671 = 5.037 Volt? Perhaps

CC 3C = 52284 = 52 mA ? Why just two bytes and not 4? Hmm….

We can also deactivate with

char-write-req 0x0b 0a0041[3B/3C]000100000000

Really not important, at least for now. Let’s look to the button pads and the RGB LED and give them a good use:

char-write-req --handle 0x0b --value 080081341151000X

The command works like the BOOST (just changed the port, ’32’ to ’34’) and it accepts the same 10 values:

OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

Once again, not sure about the color names but those above are good enough for me…

Now the buttons, we activate them with:

char-write-req 0x0b 0a004100000100000001 (Left or 'A')
char-write-req 0x0b 0a004101000100000001 (Right or 'B')

so we now receive a notification each time there is a state change:

Left or A+ on then off:

05 00 45 00 01
05 00 45 00 00

Left or A- on then off:

05 00 45 00 ff
05 00 45 00 00

Left or A Red on then off:

05 00 45 00 7f
05 00 45 00 00

And the same happens for Right or B, just the fourth byte is now ’01’ instead of ’00’.

So we can use our new ‘Handset’ with whatever BLE capable device we want.

Next bash shell loops through the 10 RGB possible values:

#!/usr/bin/env bash

#colors
OFF=0
PINK=1
PURPLE=2
BLUE=3
LIGHTBLUE=4
LIGHTGREEN=5
GREEN=6
YELLOW=7
ORANGE=9
RED=9
WHITE=A

function remoteLED () {
    gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 080081341151000$1
}

# activate notifications and keep changing colors
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0c --value 0100

while :
do
    for color in $OFF $PINK $PURPLE $BLUE $LIGHTBLUE $LIGHTGREEN $GREEN $YELLOW $ORANGE $RED $WHITE; do
        remoteLED $color
        sleep 1
    done
done

And the bash script for ev3dev from the last post:

#!/usr/bin/env bash

# identify motors
MOTORA=$(ls /sys/class/lego-port/port4/ev3-ports\:outA\:lego-ev3-l-motor/tacho-motor/)
MOTORB=$(ls /sys/class/lego-port/port5/ev3-ports\:outB\:lego-ev3-l-motor/tacho-motor/)

echo "outA:"$MOTORA
echo "outB:"$MOTORB

MOTORSPEED=1050
MOTORDELAY=0.1

# reset motor positions and initialize
echo reset > /sys/class/tacho-motor/$MOTORA/command
echo reset > /sys/class/tacho-motor/$MOTORB/command
echo brake > /sys/class/tacho-motor/$MOTORA/stop_action
echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
echo brake > /sys/class/tacho-motor/$MOTORB/stop_action
echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp


function finish {
    # terminate all subshells
    kill 0
    # reset all motors
    echo reset > /sys/class/tacho-motor/$MOTORA/command
    echo reset > /sys/class/tacho-motor/$MOTORB/command
}
trap finish EXIT

# activate left pad
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 0a004100000100000001
# activate right panel
gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0b --value 0a004101000100000001

# activate notifications and keep listening
while read -r line; do
    message=$( echo "$line" | cut -f2 -d: )
    
#    echo "Line: $line"
#    echo "Msg: $message"

    if  [[ $message = *"05 00 45 00 01"* ]]; then
        echo "L+ ON"
        echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 00 7f"* ]]; then
        echo "Lr ON"

    elif [[ $message = *"05 00 45 00 ff"* ]]; then
        echo "L- ON"
        echo -$MOTORSPEED > /sys/class/tacho-motor/$MOTORB/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 00 00"* ]]; then
        echo "L  Off"
        echo stop > /sys/class/tacho-motor/$MOTORB/command

    elif [[ $message = *"05 00 45 01 01"* ]]; then
        echo "R+ ON"
        echo $MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORA/command

    elif [[ $message = *"05 00 45 01 7f"* ]]; then
        echo "Rr ON"

    elif [[ $message = *"05 00 45 01 ff"* ]]; then
        echo "R- ON"
        echo -$MOTORSPEED > /sys/class/tacho-motor/$MOTORA/speed_sp
        echo run-forever > /sys/class/tacho-motor/$MOTORA/command

    elif [[ $message = *"05 00 45 01 00"* ]]; then
        echo "R  Off"
        echo stop > /sys/class/tacho-motor/$MOTORA/command

    fi

done < <(gatttool -b A4:34:F1:CE:DC:A2 --char-write-req --handle 0x0c --value 0100 --listen)

[edit]
Ooops, forgot that EV3 already has an internal BT interface. Sometimes this script works, sometimes don’t. That’s because I don’t specify which BT interface will be used by gatttool command. We should use ‘-i hci0’ or ‘-i hci1’ but sometimes the kernel decides that hci0 is the internal one, sometimes it decides that it is the USB one.

Perhaps a udev rule can force hci0 to always be the USB one, don’t know. Bad quickfix: remove the USB BT adapter and insert it again, this forces ev3dev to switch hci devices.