Show HN: A simple app to collect people's info at events (bluetooth)
by fcpguru | 2025-11-04 20:32:12+00:00
I was at a networking event. About 40 people at a bar/restaurant in Culver City and it was great! Lots of interesting people. Great conversations but when it was over, I had no way to contact any of these people. So I started writing this bluetooth app. Using CBCentralManager on ios and BluetoothManager on android. Each phone broadcasts as a peripheral but also connects as central. Rooms full of phones running the app gossip.

Think of the term "peripheral" as server and "central" as client. Yes there are differences in bluetooth and reasons for those terms, but my life got much easier thinking: client server. So in a room with just two phones, which one is which? It can't be a coin toss. If 50% of the time both phones act as the server and neither client, bad. Or if both phones act as clients, bad. So how do you break the tie? You start up your server AND act as a client looking for servers. Just be careful not to connect to yourself!

With bluetooth your server advertises and when you connect it tells you what characteristics it has. Think of characteristics as "endpoints". They are not the same as http endpoints at all but again my life got easier thinking of them like this. Our app has two characteristics PROFILE_CHAR and PHOTO_CHAR and step one is a client hits PROFILE_CHAR and gets back json with device_id, first_name, photo_hash, instagram. It could be binary or Protocol Buffers but I went with json.

So with my 200 OK from PROFILE_CHAR I look at the photo_hash which is a 256 sha from the binary data of the user photo. If I have this file cached, I'm good and disconnect. If not I hit PHOTO_CHAR and get the image data in chunks and save as hash.jpg locally. Then disconnect. After I disconnect I place that bluetooth server id on a cooldown list. I have other phones in the room to connect with! All this time I'm also acting as a server. Sometimes when I'm busy being a client getting a photo I'll pause my server actions. It depends on ios vs android. There is lots of complexity in the BLE stack. This loop of find server, connect, get info, disconnect, repeat works great. But there are limits and GATT errors and queue buffers and MTU (max transmission unit) issues that can make two phones next to each other take a while to find each other.

So I made github.com/andrewarrow/auraphone-blue which is a BLE stack simulator written in golang. If you look at the wire package you'll see a BLE implementation using the file system and domain sockets to mock the radio. The swift package and kotlin package should look familiar to anyone who has worked on ios or android BLE. My plan was to run many mock phones and test all the weird BLE differences between ios and android. It did not work. The only thing this golang repo did was help me understand how bluetooth works. This BLE stack I made doesn't fix ios and android bugs, it introduces its own subtle golang filesystem ble bugs!

In the end nothing fixed bugs better than running two real ios phones and two real android phones and having them write very thorough logs PLUS ble specific json files showing exactly what each operation was doing and what info it got back. I ended up writing logic to zip up the entire local directory of the phone with all these files and logs and doing an HTTP POST to my local mac just to get all the data off all 4 phones quickly after each run.

But now after your conversation is done and you move around the room, you have a record of who that person was. The list is sorted by last updated_at desc so whoever you are near will be at the top. Great for when you met someone earlier and forget their name. Now you just look down at your auraphone app and say oh hey jessie!

ios app store:

https://apps.apple.com/us/app/auraphone/id6752836343

or download the android apk:

https://andrewarrow.dev/auraphone/

Looking to try it now in a room full of people!