Adventures in BLE with Node
Tags: ble, node, server
Published: 2019-08-06 19:24:11

---
title: Adventures in BLE with Node
published: true
description: 
series: BLE with NodeJS
tags: ble, nodejs, server
---

Out of curiosity, I decided that today would be the day I set up a node server that can control my YN360 (a Chinese LED wand meant for photography), so that I can start using it as an alarm clock, a remote light that I can turn on and off, a notification light, or to do fancy programmatic things for interesting videos/photos. 

My plan is to have a node server running on my Thinkpad x230 (which I'm gradually growing into a home server). I found that the x230 has a bluetooth chipset that can at least recognize my YN360, so hopefully it'll be able to write to it as well.

I'm kinda stuck at the moment, so writing this blog is part of my debugging process.

## BLE 
As far as I can understand from the [official documentation](https://www.bluetooth.com/blog/a-developers-guide-to-bluetooth/), a BLE device basically has a series of **attributes**, which come in a few different flavors: *Services*, *Characteristics*, and *Descriptors*.

A *Service* is a set of related *Characteristics*, which may represent a specific feature of the device (i.e. one *Service* might hold device info). *Characteristics* are current data that has to do with either internal state or external state as measured by a sensor.

The LED brightness / state of the YN360 should be handled by *Characteristics*, so we won't get further into it than that. Instead, let's talk about the YN360-specific stuff I found.

## YN360 hardware

On the YN360 side, I learned a lot from [Samuel Pinches's excellent blog](https://samuelpinches.com.au/hacking/hacking-yn360-light-wand/), but the main takeaways were that the YN360 takes a few commands that determine which LEDs to turn on and to what brightness.

* `0xAEAA01XXYY56` will turn on the white LEDs, where the cold LEDs have a brightness of `XX` and the warm LEDs have a brightness of `YY`.
* `0xAEA1RRGGBB56` does the same for the RGB LEDs, with `RR` being the red value, `BB` being blue, and `GG` being green.
* `0xAEEE00000056` turns off the light (but even when off, it'll still listen for BTLE commands)

I fired up LightBlue ([android](https://play.google.com/store/apps/details?id=com.punchthrough.lightblueexplorer&hl=en_US), [iOS](https://itunes.apple.com/us/app/lightblue-explorer/id557428110?mt=8)) to do a bit of investigation into the device.

I found a service with a UUID of `f000aa61-0451-4000-b000-00000000000000`, and within that service, I found two characteristics: `f000aa63-0451-4000-b000-00000000000000` and `f000aa61-0451-4000-b000-00000000000000`. I'm not sure exactly what this means, but I noticed that the latter (starting with `f000aa61`) supported writes. After sending it `AEAA01999956` (white LED string with a brigthness of 99), the light actually turned on!

Now, the goal is to get Node to send the signal, so that I can have routes on my home server to interact with the light over my local network.

## node

NodeJS was a bit harder, and I still haven't got it fully running yet. I found a library called [noble](https://github.com/noble/noble), which refused to install on my machine. The last commit was made on Jun 7, 2018. Luckily, there's an [abandonware fork](https://github.com/abandonware/noble) of it that was last updated on April 15, 2019. Luckily this one installs, and it was even able to detect my YN360 with a scan!

The flow is something like this:

discover device -> connect to device -> find services -> write to the appropriate service. The `discover`, `connect`, and `discoverAllServicesAndCharacteristics` methods are all callback-based, so they'd have to be nested inside of one another, or defined as named functions in an effort to reduce nesting.

I've gotten up to the point where I've found 2 *Characteristics* that can be written to. One has a name of `'Device Name'`, which I'm assuming ain't it. The other has an undefined name. By checking UUIDs, I can see that it matches the UUID of `f000aa61-0451-4000-b000-00000000000000` (without spaces), which should refer to the *Characteristic* we need to write to.

The last bit, now, is to try to actually write to the dang thing, then refactor my code into a more modular shape.