Controlling LEGO hubs: a mqtt2pybricks gateway

This post is part 1 of 1 of  mqtt2pybricks gateway

We finally moved to a new home. Not an apartment on a 6th floor with dozens of crazy and noisy neighbors but a real house with a garden and a garage.

I also quit my job and I am taking a rest. So I finally have both time and opportunity to look into domotics.

I installed OpenHAB on a Raspberry Pi and started adding ‘things’ to get familiar with it. The first was a Nedis dehumidifier I bought a few months after moving – we moved to a place with its own micro-weather, lots of humidity, and my wife and the younger kid have allergies problems so I’m trying to keep humidity levels low.

Although the dehumidifier has builtin wi-fi we were using it just on manual mode but since it was easy to integrate with OpenHAB I started with it.

OpenHAB offers ‘bridges’ for several types of devices. This dehumidifier is a Tuya device so I added a Tuya bridge and found that I could read humidity and temperature values even when the dehumidifier was in standby mode (previously, to know the humidity level of the room I needed to turn it on to be shown on the display and just humidity, no temperature readings).

So I ordered two Tuya humidity+temperature sensors to monitor our bedroom and the #2 bedroom.

And then I added a older humidifier to OpenHAB through an also older wi-fi power plug. The humidifier has a ‘mechanic’ power switch so I left it always ON and control it from the power plug.

And then the third humidifier. But this one has a ‘digital’ power switch so you need to press it to turn it ON/OFF. And no builtin wi-fi. So a fingerbot-like gadget was needed. I chose a Switchbot Bot:

It is a Bluetooth BLE device, is supposed to be used with the SwitchBot Hub that works as a wi-fi to BLE gateway but I found a description of its API so used python to control it and created my own mqtt2switchbot gateway with a Raspberry Pi Zero 2W (using ‘bleak’ and ‘pahoo-mqtt’) and adding a MQTT broker to my OpenHAB server.

So I can control Bluetooth BLE devices from my domotics central.

And LEGO Hubs are BLE devices.

So the next obvious step was controlling LEGO from my domotics central 😀

LEGO MIDI Percussion Toolkit

Serching for “MIDI” + “percussion” + “LEGO” is training my search engine cookies. A few weeks ago I found this video of “Dada Machines” kickstarter campaign:

Such a great idea! I already knew about commercial MIDI adapter for playing just one drum and several “makers” or DIY projects using Arduinos and servo motors but Dada Machines idea of selling pre-made “modules” make things much more “clean” and interesting – each module can work as a solenoid or a mallet and can even be adapted to fit LEGO elements with studs so it really looks “plug and play”.

Now let’s think more about it:

  • a MIDI controller with several outputs is something I already been doing, a Technic Hub has 4 ports, looks like a nice start… and it can scale out quite well as I already found out with the LEGO Bagpiper
  • there are so many ways of mounting LEGO Technic… a few “actuator modules” look very feasible
  • and some of those percussion instruments on the video look really possible to achieve with LEGO parts (yes, that table with marbles, I am looking at you!)

But I was on holidays and had not enough Technic parts with me for a proof of concept (“I knew I should have brought more LEGO!”) so had to wait until back home.

I decided to use a BOOST motor for a solenoid-like module and copied Yoshihito Isogawa ‘Reciprocating Mechanism #63’ from his excellent “The LEGO MINDSTORMS EV3 Idea Book”. And since I had 2 of this motors available and a also a City Hub…

Then I found myself picking up all kind of objects at home to see how they sound when “banged” with those solenoids (“boy, this is addictive!”). I went to my #2 kid and took back those IKEA BYGGLEK boxes he was no longer using… nice sound, but for a drum-like sound a mallet actuator is better… and a stronger and faster motor is also better… so the second version of the Percussion Toolkit needed a more powerful hub for all those power bangs… and also found enough GBC balls to make that percussion table from Dada Machines:

Then I focused a little more on the software side. I was already parsing a MIDI stream and playing each percussion instrument according to the MIDI event I wanted (like “Note on 9 35” i.e. “Acoustic Drum” because on the MIDI Percussion Channel each note is mapped to a specific instrument) but without the remaining instruments most musics I played sounded very strange. So I wanted to split the MIDI stream in two – the percussion instruments would be parsed by the current setup and the remaining instruments would be forwarded to a Synth so I could listen them in a speaker.

Turns out this is very easy to achieve in linux with ‘qmidiroute’.

So after some minor adjustments and the addition of a fourth instrument, I now have a 4-instrument 100% LEGO MIDI Percussion Toolkit:

And all the micropython and python and bash scripts are available: https://github.com/JorgePe/randomideas/tree/master/MIDI-Percussion-Kit

As soon as I get more hubs will try to scale it out (the U2’s Sunday Bloody Sunday song uses 5 percussion instruments and I now have this crazy idea that a basic bass would sound great with Queen’s Another One Bites the Dust).

Then I will try to settle down on a few modules standard so this can be adapted easily to other instruments.

Then… I know… the software needs some attention.

LEGO Air Drums

This is a quick holiday project.

I had some LEGO Move Hubs with me with a new Pybricks firmware image and a new version of ‘pybricksdev’ python library that works with them.

Move Hub has an internal IMU sensor. And batteries. And wireless communication. So I could make a kind of wireless game controller.

But Facebook keeps hitting me with ads of wireless MIDI drumsticks. I can do this with LEGO:

It wasn’t difficult – the Pybricks script is very short, inspired on an Arduino project from Andrea Richetta (‘Air Drum with Arduino Nano 33 IoT‘) – I just calculate the size of the acceleration vector (in fact it’s square since Move Hub doesn’t support float numbers so no complex math functions) and print something out whenever it changes ‘suddenly’:

from pybricks.hubs import MoveHub
from pybricks.tools import wait

ACC_THRESHOLD = 170
ACC_MARGIN = 50
TIME = 40
KEY = '1'

hub = MoveHub()
max_v = 0

while True:
    x,y,z = hub.imu.acceleration()
    v = x*x+y+y+z+z
    
    if v > ACC_THRESHOLD:
        max_v = v
    elif v < max_v-ACC_MARGIN:
        print(KEY)
        max_v = 0
        wait(TIME)

Then I just used ‘pybricksdev’ library in a pyhton script on my laptop to capture the output of the Move Hub and redirect it with ‘xdotool’ to a MIDI controller (VMPK) that generates MIDI events usable by Hydrogen (a MIDI drum engine).

I could have used something on python to directly generate the MIDI events instead of using VMPK… but I’m a lazy guy on holidays (or call it ‘Agile’ 😀 )

So I finally made a kind of tutorial:

All the source code available at github as usual.

Committed to Pybricks

So I committed 2 files to the Pybricks project:

not really to the project code but with a demo project that shows how to use the new ‘getchar’ function to pass commands from the Pybricks Chrome IDE to the hub in runtime.

getchar‘ works like the standard ‘input’ function but is doesn’t wait for ENTER so it is non-blocking. I already used ‘input’ to send commands to the Top Gear Rally Car and from the ‘client’ side (my EV3 python script) the only difference is not having to send a carriage return any more but from the hub side the responsiveness of the code should be now much better.

from pybricks.experimental import getchar

while True:
    c = getchar()
    if c == ord('a'):
        print('You pressed a! Now drive forwards...')
    elif c == ord('b'):
        print('You pressed b! Self destruct in 3, 2, 1...')

Another advantage of ‘getchar’ is allowing me to use Nordic nRF Toolbox UART tool to send commands to the hub:

The tool always send a termination code (we can choose LF / CR / CR+LF) but now ‘input’ considers it as just another character.

The usual companion video: