Skip to content

Instantly share code, notes, and snippets.

@manzke
Last active August 29, 2015 14:24
Show Gist options
  • Select an option

  • Save manzke/95cd656bda2ee1f7a87d to your computer and use it in GitHub Desktop.

Select an option

Save manzke/95cd656bda2ee1f7a87d to your computer and use it in GitHub Desktop.
Lock My Mac - node-red, noble, scan ble and my Nike+ FuelBand SE

This is my first flow for an interesting tool called node-red. It will help me to learn node.js, BLE with noble and hosting it on my brand new Intel Edison.

You can model your node-red flows without knowing a programming language. (theoretically ;))

A flow consists of an input, output and if necessary a lot of other stuff like functions, switches and so on. They have a pretty good and up-to-date documentation.

All these tools and skills should later help me to extend the capabilities of an awesome wireless controller for my connected home.

Therefore I'm working with a Berlin-based hardware startup called senic. They are the inventors the awesome input devices called nuimo.
You can control any integrated product with the help of click, touch, gestures and turn of a high precision ring. That's your unique wireless controller for connected devices!

Nuimo is using Bluetooth Low Energy (Developing for nuimo with BLE) to connect to your laptop, mobile phone/tablet or bluetooth hub. BLE ensures that the power consumption is pretty low, so you can work without recharging for more than a month.

I did a lot of research how to get started with node-red and found an interesting article about scanning for BLE devices. It has been pretty interesting because the author used it to lock his Mac. :)

The flow used in this example was to simple. For example if no BLE device is around the "Scan BLE" node won't trigger anything. So how do you lock something if the process is not triggered? You also have to allow duplicates otherwise your device will only be detected ones and never again. BLE doesn't establish a connection. It advertise it (what is like a ping). It can be that noble scans when your BLE device doesn't advertise, so I wanted to have a threshold before my Mac will be locked.

The biggest finding what I had was the amount of advertise packages which are floating around. There are so many devices using BLE already that it nearly crashed my chrome, because too many packages had been logged in the debug window. I strongly recommend that you specify a Service UUID, so noble can skip unnecessary services by default.

The last missing piece is the calculation of the distance. It seems that BLE has a pretty good range. I had to put my FuelBand into pot and placed it in another room to test what happens if the device is not there anymore. I want to detect if my FuelBand is next to my Mac or far far away even if it can ping it.

The complete flow can be found in this gist. Just copy & paste it into your running node-red instance and you are all set. All you have to do is to configure the id of your peripheral (Nike+ FuelBand SE) or any other BLE enabled device. Last but not least you need to configure the Service UUID of your device in the "Scan BLE" node.

[
{
"id":"243f9c28.dbc064",
"type":"scan ble",
"uuids":"83cdc41031dd11e281c10800200c9a66",
"duplicates":true,
"name":"Scan for BLEs",
"x":82,
"y":442,
"z":"dc9ec147.23614",
"wires":[
[
"d431169d.2bcee8"
]
]
},
{
"id":"9c4f96f.f63b068",
"type":"exec",
"command":"pmset displaysleepnow",
"addpay":false,
"append":"",
"useSpawn":"",
"name":"Lock()",
"x":968,
"y":95,
"z":"dc9ec147.23614",
"wires":[
[
],
[
],
[
]
]
},
{
"id":"d431169d.2bcee8",
"type":"function",
"name":"detect",
"func":"msg.context = context;\nif(context.global.found === undefined || context.global.found === false) {\n if(msg.payload !== undefined && msg.payload.peripheralUuid !== undefined) {\n var peripheralUuid = msg.payload.peripheralUuid;\n context.global.found = (peripheralUuid == '4587223b7a6645d88b0f3c5fefddeb62');\n msg.found = context.global.found;\n }\n}\n\nreturn msg;",
"outputs":1,
"noerr":0,
"x":230,
"y":442,
"z":"dc9ec147.23614",
"wires":[
[
"35967d43.ca6982"
]
]
},
{
"id":"95bd231a.6a42e",
"type":"function",
"name":"check++",
"func":"var threshold = context.global.threshold || 0;\nthreshold++;\ncontext.global.threshold = threshold;\nmsg.threshold = context.global.threshold;\nmsg.found = context.global.found || false;\nmsg.context = context;\n\nreturn msg;",
"outputs":1,
"noerr":0,
"x":485,
"y":501,
"z":"dc9ec147.23614",
"wires":[
[
"eb2fdfe0.14d02"
]
]
},
{
"id":"3f96126c.c069ee",
"type":"function",
"name":"reset",
"func":"context.global.found = false\ncontext.global.threshold = 0\n\nreturn msg;",
"outputs":1,
"noerr":0,
"x":973,
"y":507,
"z":"dc9ec147.23614",
"wires":[
[
]
]
},
{
"id":"4ed256a5.b12da8",
"type":"switch",
"name":"wait",
"property":"locking",
"rules":[
{
"t":"true"
}
],
"checkall":"true",
"outputs":1,
"x":355,
"y":501,
"z":"dc9ec147.23614",
"wires":[
[
"95bd231a.6a42e"
]
]
},
{
"id":"6d5a9103.92a57",
"type":"switch",
"name":"threshold",
"property":"threshold",
"rules":[
{
"t":"eq",
"v":"3"
}
],
"checkall":"true",
"outputs":1,
"x":791,
"y":443,
"z":"dc9ec147.23614",
"wires":[
[
"3f96126c.c069ee",
"9c4f96f.f63b068"
]
]
},
{
"id":"ae5b5b1b.51a4a8",
"type":"http in",
"name":"",
"url":"/lock/mac/now",
"method":"get",
"swaggerDoc":"",
"x":112,
"y":82,
"z":"dc9ec147.23614",
"wires":[
[
"715f68c.f8ea098",
"15ecb884.ea1347",
"f3342eb1.0ccbd"
]
]
},
{
"id":"eb2fdfe0.14d02",
"type":"switch",
"name":"found?",
"property":"found",
"rules":[
{
"t":"false"
},
{
"t":"true"
}
],
"checkall":"true",
"outputs":2,
"x":621,
"y":501,
"z":"dc9ec147.23614",
"wires":[
[
"6d5a9103.92a57"
],
[
"3f96126c.c069ee"
]
]
},
{
"id":"65e1c667.9a1e38",
"type":"catch",
"name":"",
"x":479,
"y":32,
"z":"dc9ec147.23614",
"wires":[
[
"715f68c.f8ea098"
]
]
},
{
"id":"715f68c.f8ea098",
"type":"debug",
"name":"",
"active":false,
"console":"false",
"complete":"true",
"x":625,
"y":177,
"z":"dc9ec147.23614",
"wires":[
]
},
{
"id":"f016e5ff.0fe918",
"type":"inject",
"name":"idle",
"topic":"",
"payload":"",
"payloadType":"date",
"repeat":"10",
"crontab":"",
"once":false,
"x":102,
"y":501,
"z":"dc9ec147.23614",
"wires":[
[
"d2d2c1e5.2d2d4"
]
]
},
{
"id":"fe64d076.019b3",
"type":"http in",
"name":"",
"url":"/lock/mac/off",
"method":"get",
"swaggerDoc":"",
"x":117,
"y":181,
"z":"dc9ec147.23614",
"wires":[
[
"65d61a3a.9a29e4",
"15ecb884.ea1347"
]
]
},
{
"id":"bffbeb2b.400418",
"type":"http in",
"name":"",
"url":"/lock/mac/on",
"method":"get",
"swaggerDoc":"",
"x":114,
"y":286,
"z":"dc9ec147.23614",
"wires":[
[
"7ac5e673.853a18",
"15ecb884.ea1347"
]
]
},
{
"id":"65d61a3a.9a29e4",
"type":"function",
"name":"deactivate",
"func":"context.global.locking = false;\nreturn msg;",
"outputs":1,
"noerr":0,
"x":342,
"y":203,
"z":"dc9ec147.23614",
"wires":[
[
"715f68c.f8ea098"
]
]
},
{
"id":"7ac5e673.853a18",
"type":"function",
"name":"activate",
"func":"context.global.locking = true;\nreturn msg;",
"outputs":1,
"noerr":0,
"x":337,
"y":309,
"z":"dc9ec147.23614",
"wires":[
[
"715f68c.f8ea098"
]
]
},
{
"id":"d2d2c1e5.2d2d4",
"type":"function",
"name":"active?",
"func":"msg.locking = context.global.locking;\nreturn msg;",
"outputs":1,
"noerr":0,
"x":229,
"y":501,
"z":"dc9ec147.23614",
"wires":[
[
"4ed256a5.b12da8"
]
]
},
{
"id":"35967d43.ca6982",
"type":"function",
"name":"reset",
"func":"if(msg.found === true) {\n msg.threshold = 0;\n msg.found = false;\n context.global.threshold = msg.threshold;\n context.global.found = msg.found;\n} else {\n msg.found = false;\n context.global.found = msg.found;\n}\n\nreturn msg;",
"outputs":1,
"noerr":0,
"x":358,
"y":442,
"z":"dc9ec147.23614",
"wires":[
[
"715f68c.f8ea098"
]
]
},
{
"id":"15ecb884.ea1347",
"type":"http response",
"name":"",
"x":330,
"y":32,
"z":"dc9ec147.23614",
"wires":[
]
},
{
"id":"fe1a1523.01e5e8",
"type":"inject",
"name":"lock on",
"topic":"",
"payload":"",
"payloadType":"none",
"repeat":"",
"crontab":"",
"once":false,
"x":142,
"y":332,
"z":"dc9ec147.23614",
"wires":[
[
"7ac5e673.853a18"
]
]
},
{
"id":"7d8ab3fd.82754c",
"type":"inject",
"name":"lock now",
"topic":"",
"payload":"",
"payloadType":"none",
"repeat":"",
"crontab":"",
"once":false,
"x":145,
"y":120,
"z":"dc9ec147.23614",
"wires":[
[
"f3342eb1.0ccbd"
]
]
},
{
"id":"f3342eb1.0ccbd",
"type":"function",
"name":"",
"func":"\nreturn msg;",
"outputs":1,
"noerr":0,
"x":329,
"y":95,
"z":"dc9ec147.23614",
"wires":[
[
"9c4f96f.f63b068"
]
]
},
{
"id":"dae11c21.251ee",
"type":"inject",
"name":"lock off",
"topic":"",
"payload":"",
"payloadType":"none",
"repeat":"",
"crontab":"",
"once":false,
"x":145,
"y":224,
"z":"dc9ec147.23614",
"wires":[
[
"65d61a3a.9a29e4"
]
]
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment