Changing an RGB LED from a Mendix app

The Nordic Thingy:52 is a compact multi-sensor prototyping platform. It exposes a variety of configurable sensors and actuators over Bluetooth.

Modern versions of the Google Chrome browser support the Web Bluetooth API. This means we can write JavaScript that runs in a web browser to talk to Bluetooth devices. We can use this to get Chrome to talk to a Nordic Thingy:52.

The guys at Timeseries created a quick primer on How to get started with IoT using Mendix. Willem Van Zantvoort also gave a webinar that included using a Nordic Thingy:52. This demo only showed how to read data, not write.

Timeseries have released the Bluetooth (BLE) Connector module to the Mendix App Store. This allows developers to connect and write to Bluetooth devices from a Mendix app. These are exposed as JavaScript actions.

If we want to change the colour of the Nordic Thingy:52’s LED, how do we do this from a Mendix app?

We can use the DeviceConnect JavaScript Action in a Nanoflow to connect to a Nordic Thingy:52. The Bluetooth (BLE) Connector module doesn’t allow data to be written to a device. We need this functionality to tell the Nordic Thingy:52 what colour we want to the LED to show. So we will need to write our own JavaScript Action to do this.

Create the SetLED JavaScript Action

JavaScript Actions in Mendix are very easy to write. We create a JavaScript Action called SetLED. This needs to take 3 String parameters. A “primaryServiceUUID”, a “characteristicUUID”, and “mycolour”. The “primaryServiceUUID” describes what type of service we want to talk to. The “characteristicUUID” is the specific characteristic, in this case the LED. Finally, “mycolour” is the colour we want to show described as a CSS style rgb string (e.g. “rgb(10, 255, 10)”).

A Mendix JavaScript Action works by using a JavaScript promise to return data to a Nanoflow. Mendix has created a small scaffolded bit of JavaScript for us to change.

The first thing we need to do is to see if Bluetooth is supported. We do this by trying to access the window.gattServer. If it’s not available, we need to reject the Promise.

var gattServer = window.gattServer;
  if(gattServer){
    // Bluetooth available
  } else {
    return Promise.reject("No gatt server found");
  }

Now we need to try to access the LED characteristic on the device. We do this by creating a new Promise within which we get the primary service, then the LED characteristic. At this point we should be able to talk to the device and issue an instruction for the LED.

return new Promise((resolve, reject) => {
    gattServer.getPrimaryService(primaryServiceUUID)
    .then( (s) => {
        return s.getCharacteristic( characteristicUUID );
    })
    .then( (c) => {
        characteristic = c;
        return c;
    })
    .then(characteristic => {
        // do something with the LED
        resolve(true);
    });
});

The data is sent as binary using the writeValue method of the characteristic. We need to convert our RGB string into binary values before we send this. We can extract the individual values for R, G, and B using a regular expression. We can then insert these into a JavaScript Uint8ClampedArray. The Uint8ClampedArray prevents values under 0 and over 255. This helps us avoid buffer overflows which could cause bugs.

const match = mycolour.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d(?:\.\d?))\))?/);
let buffer = new Uint8ClampedArray(4);
buffer.set([1, match[1], match[2], match[3]], 0);

characteristic.writeValue(buffer);

Our final action should look like this…

 // This file was generated by Mendix Studio Pro.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the code between BEGIN USER CODE and END USER CODE
// Other code you write will be lost the next time you deploy the project.

/**
 * @param {string} primaryServiceUUID
 * @param {string} characteristicUUID
 * @param {string} mycolour
 * @returns {boolean}
 */
function SetLED(primaryServiceUUID, characteristicUUID, mycolour) {
 // BEGIN USER CODE
 var gattServer = window.gattServer;
 if(gattServer){
 return new Promise((resolve, reject) => {
            gattServer.getPrimaryService(primaryServiceUUID)
            .then( (s) => {
 return s.getCharacteristic( characteristicUUID );
            })
            .then( (c) => {
                characteristic = c;
 return c;
            })
            .then(characteristic => {
 const match = mycolour.match(/rgba?\((\d{1,3}), ?(\d{1,3}), ?(\d{1,3})\)?(?:, ?(\d(?:\.\d?))\))?/);
 let buffer = new Uint8ClampedArray(4);
                buffer.set([1, match[1], match[2], match[3]], 0);

                characteristic.writeValue(buffer);
                resolve(true);
            });
        });
    } else {
 return Promise.reject("No gatt server found");
    }
 // END USER CODE
}

Now we have our JavaScript action, we can wire it into a Mendix app.

Using the SetLED JavaScript Action

We need to add a non persistable entity to hold our RGB string. We’ll call this “LED”, and add one String attribute “RGBString”.

Add a Data view to the page, and set its data source to the a new Nanoflow called CreateLED. All the Nanoflow needs to do is create an instance of our LED entity.

Mendix have provided an excelled RGB colour picker in the App Store called Color Picker. We can drop this into our Data view setting the Color Attribute field to the RGB string in our new LED entity. Set the Color Format to RGB. In the Appearance Tab set the Picker type to Hue. Now when we use the colour picker, it will save the selected value to our LED entity. That’s great, but we want to actually change the colour on Nordic Thingy:52. To do this, we need to go to Events and On change call a new Nanoflow we’ll call ChangeLED.

ChangeLED needs to first connect to the Nordic Thingy:52. We do this using the DeviceConnect JavaScript action from the Bluetooth (BLE) Connector. This takes a Primary service UUID of ” ef680100-9b35-4933-9b10-52ffa9740042″. It also takes an Optional service UUID of ” ef680300-9b35-4933-9b10-52ffa9740042″. I found these values in the example JavaScript code on Nordic’s GitHub account. When this is called it will trigger a prompt to connect to a Bluetooth device.

Once we are connected, we call our SetLED JavaScript action. The Primary service UUID is ” ef680300-9b35-4933-9b10-52ffa9740042″. This was the value we used as the optional UUID when we connected. For the Characteristic UUID we use the value “ef680301-9b35-4933-9b10-52ffa9740042” for the LED. For Mycolour we use the value in the RGBString attribute in our LED entity.

We can now run the App.

Running the App

The first time the ChangeLED Nanoflow is run it will prompt to connect to a Bluetooth device. This is where we look for our Nordic Thingy:52. Future requests are not prompted for while in the same session.

If we’ve connected to our device the LED should now be changing colour to match the value in the colour picker.

Thingy LED change from a Mendix App

Conclusion

Hopefully this should be enough information to get you connecting to a Bluetooth device and sending data.

If you aren’t using Mendix at the moment it’s free to get started, you just need to signup for a Mendix account.