Week 12: Networking

With networking, we talked about bluetooth, which reminded me of a half-finished project that I decided to tackle for the next two assignments: connecting to my Bluetooth exercise bike. I acquired the exercise bike in late 2020 when gyms were closed and it was getting too cold to run, and I’ve used it consistently since.

I’ve tried a few different apps: I started with Peloton, then Zwift, and now I use Kinetic, which is really barebones but free. You take a training test to set this “FTP” score, and then there are custom classes that help increase that base level without totally exhausting you. You know going into each workout how you’re going to feel after.

So I’m going to use this for a two-part work. This week, I connected the bicycle to a pico w, into what will become the bike controller, which can also choose classes. Even though it’s bluetooth input device, I’m not sure if that counts as networked since it’s only one of my devices, so I’ll set up a wireless second device with LEDs to wirelessly connect. I’m thinking that second device can eventually become my hub for my apartment.

Next week I’m planning to work a bit more on the application, and finish the bits I didn’t get working this week.

Designing the bike device 🔗

So the bike device, I’d like to have a OLED to view some information, and some buttons to go through a menu to pick the workout. I designed a board with these, along with a few options for the interface. For now I’ll start with 4 buttons (up, down, next previous), but I have another connector that adds in ADC pins if I want to swap the up-down keys with an encoder.

The OLED will be mounted to the back of the board. I also added in an extra SPI in case I want to do something else with it.

And here’s the second board with buttons (and a missed connection between GND and the rest, argh)

Designing the Hub 🔗

As for the hub, I thought about it and actually I just need the same connections as my devboard. But I’m busy using that one, so I made a second one.

I also figured I’ll eventually want a MicroSD reader. From the inventory, it looks like we have shields, so I designed a breakout board for that.

Programming 🔗

For the hub, I started with the code I used from the group project. I have plenty of work on the bike controller, so I figured this was fine.

Now for the bike controller. The Pico sites recommended MicroPython, so I thought I’d try it out (now I have three different environments I’m working in, whee).

I didn’t want to use thonny, so I read up and saw I can just upload code with mpremote. But actually for this assignment, I think the REPL will work great.

So last time I tried to get the Bluetooth bike connected, I managed to get as far as reading weird hex numbers. This time I know a bit more about bluetooth.

So I start by finding some code to scan. aioble is a library that turns bluetooth into object oriented, which sounds great to me, so I tried it out. mpremote mip install aioble can put libraries like these onto the device.

import asyncio
import aioble
import time

def get_connection_with_bike():
    # scan for 15 seconds
    async with aioble.scan(duration_ms=5000) as scanner:
        async for result in scanner:
            if result.name() == "IC Bike":
                print(result, result.name(), result.rssi, list(result.services()))
                connection = await aioble.connect(result.address)
                break

    return connection


async def main():
    while True:
        bike_connection = await get_connection_with_bike()
        if bike_connection is not None:
            break
    print("connected!")
    print(bike_connection)




try:
    while True:
        asyncio.run(main())
        time.sleep(5)
except KeyboardInterrupt:
    print("\nLoop stopped by user.")

I let it run for a few seconds to detect all the random devices (last time I did this, I was in a place that used bluetooth to unlock doors, so I got to see everyone’s door).

Then I went over to the bike and turned it on, and came back to watch for anything new.

It turned out a lot easier, because it was called IC Bike.

Scan result: Device(ADDR_RANDOM, c9:fb:9e:92:23:4b) -83 IC Bike -83 [UUID(0x180a), UUID(0x1816), UUID(0x1826)]

Then I can go over to Bluetooth’s assigned numbers, and see that 0x180a is “Device Information service”, 0x1816 is “Cycling Speed and Cadence service” and 0x1826 is “Fitness Machine service”.

I can then pull open the Bluetooth Service Spec for the Fitness Machine service, and find the “Indoor Bike Data”.

  • updated once per second
  • might be sent in multiple messages

Then i got to the flag bits, and actually this seems like it’d have everything I need.

Given that, I wonder what the 0x1816 Cycling Speed and Cadence service has. It is much shorter. I think I’ll be able to ignore it unless I realize I’m missing data about speed.

now connecting it…

  • addr changes randomly, so that doesn’t work
  • rssi is signal strength
  • probably checking that the name is “IC Bike” is the best bet.

I start to try to get code to connect to the bike. I do connect to it successfully, but still need to do some work to read out the data…

This is a little slow to work with, because I need to work in async blocks, which means I have to copy-paste (Ctrl+E paste, Ctrl+D) blocks of code instead of just checking things line-by-line. I might want to switch back to something more synchronous so I can iterate faster here…

(I also need to read some data and send it to the hub device, but I ran out of time..)

Group project 🔗

Cyrus had a project with a potentiometer and I had a LED strip, so we connected them wirelessly.

We needed the devices to join the same network, so we started by trying to get onto MLDev. That didn’t pan out, so instead I had my device become an AP. This was super easy with WiFi.softAP(ssid, password); (and some help from ChatGPT). We also need to know the IP address of my device on my network, so we printed out Serial.println(WiFi.softAPIP());.

Next I set up a little server.

server.on("/", handleInput);
server.begin();

and then

void handleInput() {
    String huestr = server.arg("state");
    uint8_t r, g, b;

    Serial.print(huestr);

    int hue = huestr.toInt();

    Serial.print(hue);

    hsv2rgb(hue * 255 , 255, 50, r, g, b);
    show_color(hue);
    server.send(200, "text/plain", "OK");
}

Now anyone could connect to my WIFI and trigger the LEDs to change color. Wow!

It took us a while to get the potentiometer sending data correctly. What it came down to was Kye pointing out we need to send the port number :80 (because websites and curl will automatically assume that), and that we were missing the / in the url, which apparently mattered.

You've found my documentation of the Fall 2024 class for how to make (almost) anything at MIT. At the time of writing, I am a first year MAS student (MIT Media Lab) in the Future Sketches lab. When I'm not making almost anything, I'm making specific other things, like making cool-looking things with code, which I sometimes pen plot or live code.