Imagine you are a mobile software developer that’s been tasked with implementing support for a new BLE device. But there’s one catch: The device doesn’t exist yet.
Not a problem! You can use bleno, a Node.js module, to mock out a BLE peripheral and get started on the mobile software implementation right away.
Sound like something you could use? Follow along, and you’ll have a simulated BLE peripheral running in minutes.
This article will tell you how to install Node JS and NPM(node package manager) on MacOS step by step. There are three ways to install it on mac, run the official installer, install node binary for macOS directly or use mac Homebrew package manager. Why are Node.js developers so sought-after, you may ask. It is because Node.js requires much less development time and fewer servers, and provides unparalleled scalability.In fact, LinkedIn uses it as it has substantially decreased the development time. Netflix uses it because Node.js has improved the application’s load time by 70%. The V8 JavaScript Engine Run Node.js scripts from the command line How to exit from a Node.js program How to read environment variables from Node.js How to use the Node.js REPL Node.js, accept arguments from the command line Output to the command line using Node.js Accept input from the command line in Node.js Expose functionality from a Node.
Why Use bleno Instead of Another Module?
While this post will focus on bleno, there are multiple ways you can mock a BLE peripheral. Here are a few:
LightBlue® is super useful when you need to test something quickly. It’s very easy to clone a real peripheral you’ve scanned and create a virtual copy of it, to create a virtual peripheral from a standard GATT specification, or to create a custom virtual peripheral. But LightBlue doesn’t offer the ability to script functionality into your virtual ATT server to configure the behavior of your peripheral. That’s where the following options excel.
BlueZ is a Bluetooth stack for Linux. There are multiple python libraries or projects you can use to interface with BlueZ and mock a BLE peripheral, such as python-gatt-server from Jumper Labs or python-bluezero. The python + BlueZ approach offers the flexibility of writing code so that your peripheral can perform some more complex logic and data manipulation. BlueZ is widely supported across Linux distributions, but it isn’t available on other operating systems.
Bleno is a Node.js module, and Node.js can run on macOS, Windows, or Linux. If you’re working with a team where multiple developers could benefit from being able to run the virtual peripheral for development or testing, bleno is an excellent option. You can easily add the javascript code to a version control system, such as git, so that your whole team can easily run their own instance of the virtual peripheral.
Depending on your background, working with Javascript may be an easier point of entry than the Linux/python/BlueZ route. And like the python/BlueZ approach, bleno allows you to script additional logic into the behavior of your virtual peripheral, such as computing data to send on read and notify events or reacting to write events. Due to wide platform support, ease of installation, and low barrier of entry with javascript, bleno makes a strong case as the best option when mocking BLE peripherals.
Why is it Useful to Mock a Peripheral?
There are multiple reasons why you may want to mock a BLE peripheral. As a mobile developer, you may be involved in a project where other members of your team, or another vendor, are actively working on the development of hardware/firmware while you need to get moving on mobile software. If your BLE device’s services and characteristics are already defined, you can quickly mock up a virtual peripheral and get moving on integrating your mobile software without being held up by hardware or firmware development.
Alternatively, you may be involved in a project where you’re designing the ATT server architecture. With bleno, you can rapidly prototype and make adjustments as you lock down the architecture definition. A mock peripheral can also be used for testing mobile software. By adding some code to your mock device, you can manually cause some edge cases, such as forcing a disconnection, to test how your mobile software handles the situation. Knowing how to set up a simulated BLE peripheral is a valuable tool for a mobile developer working with BLE devices.
Getting Set Up
To get started mocking BLE peripherals with bleno, you’ll first need to install Node.js. Click here to download the installer for your platform.
Once you have Node.js installed, create a new folder and name it
bleno . This folder will be used to store your virtual peripheral code as well as the bleno installation. From the command line, navigate into your new bleno folder.
Next, install the bleno module with the command
npm install bleno or npm install github:notjosh/bleno-mac *
*NOTE: If you want to run bleno on macOS, you should install
bleno-mac . While you can use bleno on mac, this fork is a safer option for mac as it uses the official CoreBluetooth APi.At the moment, there appears to be an issue causing an incompatibility on macOS 10.15.2. Keep an eye on the GitHub page if you are impacted by this issue. 5/1/20 Update: I was able to get bleno working on macOS Catalina (10.15.4) by utilizing the following node packages: bleno github:notjosh/bleno#inject-bindings bleno-mac github:notjosh/bleno-mac xpc-connection github:sandeepmistry/node-xpc-connection#pull/26/head I had to delete my project’s “node_modules” folder, then delete “~/.node-gyp”, then install each of the 3 above packages (ie. “npm i github:notjosh/bleno-mac”). After installing those three packages, I am able to run bleno on macOS Catalina.
Once you’ve finished those installations, we can get started with configuring your custom BLE peripheral.
If you’re already comfortable with javascript, there are more complex examples of mock peripherals. Configuring the Simulated Peripheral Service
Let’s get started on the javascript code to create a service for your simulated peripheral. Create a new file named
service.js inside your bleno folder.
Add the following code to
service.js :
This imports the bleno module and makes the bleno PrimaryService available for use.
Now, let’s add a state change handler:
This sets up a handler that will fire when there’s a state change to the system’s bluetooth state. You can alter the
CustomService service name and the UUID that follows it if you’d like.
Let’s try that out now to make sure everything is working.
From a terminal window that is navigated to the folder where your
service.js file is, run the following command:
node service.js
This will start the service, and if your Bluetooth is already on, you’ll see a log statement indicating your service has started advertising. You can toggle your system’s Bluetooth on or off to see your new BLE service start or stop advertising.
Your custom BLE service is set up!
Next, we’ll move on to defining a custom characteristic for our new service. But for now, you can stop the service by entering
ctrl-c in your terminal.
Configuring a Simulated Peripheral Characteristic
To add a characteristic to your service, create another file in your
bleno folder and name it characteristic.js .Then add these lines to characteristic.js :
This makes the ‘util’ and ‘bleno’ node modules available, and gives us a reference to the bleno Characteristic model.
Next, let’s begin our characteristic by adding these lines:
Here we’re defining our characteristic. In this example, I named it “CustomCharacteristic,” but you could use whatever you prefer. We’re giving it a UUID, and a list of properties which includes “read,” “write,” and “notify.” We’ll expand more on those properties in a moment.
It then sets the current value to an empty Buffer, and sets the updateValueCallback to null. Then, we specify that our CustomCharacteristic shall inherit from the BlenoCharacteristic object. The final line makes our CustomCharacteristic available as a module.
Now that our characteristic has been defined, the next step is to add some handlers for the read, write, and notify properties.
Configuring Characteristic Event HandlersRead
For this tutorial, we’re going to configure our characteristic to return the value 42 when read.
To configure the “read” handler, add the following to
characteristic.js :
This code will run when a read is performed on this characteristic. It’ll write to the console log, create a buffer with a length of one byte, write a single byte with a value of ‘42’ to that buffer, and finally call the callback function that was passed into the handler with two parameters. The first is a success indicator, and the second is the data buffer with our value of ‘42’.
Write
Next we’lll configure the “write” handler to log written values to the console.
Add the following to
characteristic.js :
This code will run when a write is performed to this characteristic. It’ll take in the value that was written, print the value to the log as a hex value String, and call the callback indicating it was a success.
Notify
We’re going to configure the “notify” property to send the current time once every 5 seconds. To support notifications, we need two handlers. One for the subscription, and one for unsubscription.
First, we’ll need a couple variables and a function that we’ll use with the notify handlers.
Add the following to
characteristic.js :
The first line here adds a variable where we can track whether the notify subscription is active. The next variable is the interval at which we want to fire notifications in seconds. You can alter this value depending on how frequently you’d like notifications to fire.
Then, we define a function called
delayedNotification . The function has one parameter named callback . Inside the function, we use setTimeout to delay the execution of some code by our notifyInterval , which is multiplied by 1000 since the setTimeout function expects milliseconds.
Inside
setTimeout , first we check whether isSubscribed is true. If it is, then we create a new Buffer with length of 3 bytes, we create a new Date, and then write the hours, minutes, and seconds to our Buffer. We then call the callback that was passed in to our function, and pass our data buffer through that call. Finally, we call our delayedNotification function again, and pass in the same callback. This will allow our notification to continually fire every 5 seconds until we unsubscribe and set isSubscribed to false .
Now, we’ll add the first of two handlers to be used for the notify process, starting with onSubscribe.
Add the following to
characteristic.js :
In our onSubscribe handler, we start with a log statement indicating the subscription has been made. We then set the
isSubscribed variable to true , and then call our delayedNotification function, passing in the updateValueCallback that we’ll call later to fire the notification.
One more small piece to go for our custom characteristic!
Now, we’ll add the unsubscribe handler by adding the following to
characteristic.js .
This will just set our
isSubscribed property to false when the onUnsubscribe handler fires. This will prevent our subscribe handler from calling the callback after the unsubscription has happened.
With that, we’ve finished adding read, write, and notify properties to our custom characteristic!
Adding the Characteristic to the Service
There is one more step before our characteristic can be tested. We’ll have to add our new custom characteristic to the service.
Add the following to
service.js :
The first line here makes our CustomCharacteristic module available for use in this file. Next, we tell bleno that when the advertising starts, assuming there are no errors, to set the services to an array that contains a BlenoPrimaryService with a UUID that matches the UUID that we are advertising after the
poweredOn state change. In the constructor of this service, we create an instance of our CustomCharacteristic .
With that, our coding is complete! We have a BLE service running our custom characteristic with read, write, and notify properties. And we did it with less than 100 lines of code!
This is a simple example, where we’re just sending through some basic number values. You could add all sorts of other logic or expand on the data buffer to pass through more data than just a number, or parse additional data that is written to the characteristic.
If you’re interested in seeing some more complex examples of services you can write with bleno, check out the examples directory on the bleno github page.
Testing the Simulated Peripheral Service with LightBlue Explorer
This step is optional. But if you would like a quick way to test that your new service is available, you can verify it by using LightBlue (available on Android and iOS).
While your node service is running and your BLE service is advertising, run LightBlue from your mobile device. Once the app opens, it’ll load a list of any nearby peripherals it can find. The name of our simulated device will likely match the name of the computer you are running bleno from. In my case, it’s “Julian’s MacBook Pro.”
Locate your device in the peripherals list, and tap on it.
Once you have connected to the peripheral, you’ll see a new page with some details. Verify at the top that the UUID matches the one we defined for our service as the BlenoPrimaryService in
service.js . In my example code, I used 27cf08c1-076a-41af-becd-02ed6f6109b9 .
Next, scroll to the bottom of this page. There will be a list of some available services offered by this peripheral. At the bottom, you should see the UUID of our service, along with the UUID of the characteristic we defined in
characteristic.js . In my example, we used`fd758b93-0bfa-4c52-8af0-85845a74a606 . You should also see the available properties listed here- in my example, we defined read , write , and notify properties. What is the mac app for graphs.
Now, tap on that characteristic cell.
It will load a characteristic detail view. On this view, you will see the characteristic UUID across the top, and below that is a “READ/NOTIFIED VALUES” section. At the bottom of that section is a cell that reads
0x2A . This is the hex value for the number 42- the value we specified in our read handler of characteristic.js .
When this view loads, it automatically performs an initial read. To perform additional reads, you can tap the blue text that says “Read again.” You’ll see additional value cells appear with
0x2A along with time stamps of when the read was performed. If you watch the terminal where you are running the bleno service, you’ll see some logging output indicating a read was performed.
Below the “READ/NOTIFIED VALUES” section is another section with the title “WRITTEN VALUES”. If you tap on the “Write new value” text, it will load a new view with a hex keyboard. From here, you can enter a value to write to our characteristic.
After entering a value, tap “Done”.
Now you will see the value that was entered in a new cell below “Write new value” along with a timestamp of when the write occurred. Checking back to the terminal where bleno is running, you’ll see a log output along with the value that was written. In my example here, it was
18F6 .
The last item to test is the “notify” property. Tap on the “Listen for notifications” button. After every 5 seconds (or whatever amount you specified for
notifyInterval ), you’ll see a new cell appear. The value will be 3 bytes, representing the hours, minutes, and seconds of the time at which the notification was sent. Tap “Stop listening” to unsubscribe from notifications. You can also see some logging in the terminal window running bleno indicating the subscribe / unsubscribe handlers have fired.
How To Run Node Js App Mac Pro
With that, we have successfully verified our custom BLE peripheral!
Final Thoughts
After finishing this guide, you’ll have successfully set up a custom BLE peripheral that supports the read, write, and notify properties using Node.js and bleno. This can be a handy tool for a mobile developer working on a BLE device implementation — whether you need to work on integrating support for a new device that hasn’t been manufactured yet, or you’re assisting with the process of defining what a service or characteristic should look like, getting a usable implementation up and running in minutes can help you move quickly through the mobile software development process.
Check out this GitHub gist to see all the code used in this example together in one spot.
Working together is the foundation of developing a connected product that is well-architected and a joy to support. Our team helps build products while making you look good throughout the entire process.
In order to use almost any development tools based in JavaScript, you'll need to know how to use npm and Node.js. Gulp, Grunt, and Webpack are a few examples of popular technologies you may have heard of that require a knowledge of the Node ecosystem.
I find myself writing about this over and over again in the prerequisites of an article I've begun to write. I'd prefer to write one definitive guide to refer to in the future, so here it is.
Prerequisites
Goals
What is Node.js?
JavaScript is a client-side programming language, which means it’s processed in the browser. With the advent of Node.js, JavaScript can also be used as a server-side language.
What is npm?
npm doesn't stand for Node Package Manager*, which means it’s the tool to connect to the repository containing all the Node.js programs, plugins, modules and so on.
*npm actually does not stand for 'Node Package Manager' but essentially that's what it is and does, so most people refer to it that way.
Local vs. Global
This is the most confusing concept to understand at first, so it's important to let this settle in. Traditionally, you're used to globally installing any sort of program or software on your computer. If you want Spotify, you'll download Spotify, and then it will be available to you.
With npm, you will have some global installs, but mostly everything will be done on a local project basis, meaning you'll have to install everything you need for each project in its own directory. If you want to have a project running Gulp and Sass, you'll create a directory, with a new npm install. Why won't my facetime app open on my mac os.
For future reference, any global installations will have the
-g flag.
Installation on Windows
Installing everything on Windows is a breeze.
Install Node.js and npm
Node.js and npm can be installed from a download link. Go to the Node installation page, and download the Node installer. I have a 64-bit Windows 10 OS, so I chose that one.
Once it's done, you can test to see both node and npm functioning by opening PowerShell (or any shell) and typing
node -v and npm -v , which will check the version number.
All set.
Installation on a Mac or Linux
In order to install everything on a Mac, we'll be running commands in Terminal.app, and Linux distributions vary.
Install Node.js and npmUpdate Node Js Mac
We’re going to use Node Version Manager (nvm) to install Node.js and npm.
Open the
~/.bash_profile file, and make sure source ~/.bashrc is written in there somewhere. Restart the terminal.
Run the install command.
Run the use command.
Now that Node.js and npm are installed, test them by typing
node -v and npm -v .
All set.
Create a ProjectVisual Studio Code
At this point, you're set to start setting up Gulp, Webpack, Browserify, or whatever your aim is. We can also create a simple project to test that everything is working properly.
Initialize ProjectHow To Run Node Js App Mac Free
Navigate to the directory in which you want your project to exist - in my case, sites/node-test.
Now initalize a new project with npm.
The following will pop up in the terminal, and prompt you for a few
First, it will ask for a package name.
Version number.
Description.
The rest you can just press enter and skip. Now you'll notice we have a package.json file that contains all the information we entered.
A package.json is a file that contains metadata about the project, and handles the dependencies (additional software and modules) of the project.
Now, we're going to install our first dependency - a very important and useful package called left-pad, which will add white space to the left side of a string, adding up to a number.
For example, writing this:
Will output this:
left-pad is a package on npm, which as we stated previously contains the registry for all publicly available packages.
Install dependencies
To install a dependency with npm, we use the command
npm install dependency-name-here . Now, simply running npm install will download the dependency, but it won't save it to the project. Since we've already created our package.json, we'll use the flag --save to install the dependency and add it to package.json.
As long as you ran this command inside the project directory, it will successfully install the dependency by creating a node_modules directory. It will also create a package-lock.json file, which we can ignore. Finally, it updated our package.json file with a new line.
Now the project recognizes the left-pad dependency as existing
You can also run
npm install --save-dev to specify that the dependency will only be used for development (not production) purposes.
Run Node in the terminal
Let's create index.js in the root of our directory. This is everything you should have now:
For future reference, don't bother looking in the node_modules rabbit hole. It will get really overwhelming with bigger projects.
In order to use a dependency, we use
require() and put it in a variable, like so:
This will be the entirety of our index.js file, in which we require left-pad, run a
leftPad() function, and send it to the console.
Since Node.js is not recognized by the browser, we'll be testing this in the console. In your shell, run the
node command followed by the filename in the root of your project.
If everything went well, you should have printed
Hello, World! to the console, with two spaces on the left.
Conclusion
In this tutorial, we learned the following:
If you got lost at any point, view the source on GitHub.
With this knowledge, you're ready to start using Gulp, Grunt, Webpack, Browserify, or anything else that depends on Node.js or npm.
Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |