Skip to content

Commit

Permalink
Merge pull request #14 from mKeRix/dev
Browse files Browse the repository at this point in the history
v0.3.0
  • Loading branch information
mKeRix authored Mar 6, 2017
2 parents 71da9fe + 0ecf51d commit d7f3f85
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 9 deletions.
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,40 @@ On Linux this component will have to run as root [unless you set the correct per
```json
{
"ble": {
"enabled": true,
"channel": "room_presence",
"max_distance": 0,
"whitelist": ["id1", "id2"],
"use_mac": false,
"system_noise": 0.01,
"measurement_noise": 3,
"update_frequency": 0
}
}
```

Options:

- **enabled** - enable or disable component
- **channel** - channel for the announcements about found beacons
- **max_distance** - maximum distance where the scanner will still send the data to a publisher, 0 means unlimited
- **whitelist** - array of Bluetooth IDs as whitelist for updates that should be sent to the publisher, an empty list disables the whitelist
- **use_mac** - publish the Bluetooth MAC address instead of the UUID (for devices without a consistent UUID)
- **system_noise** - describes how noisy the system is and should be kept relatively low (used for the Kalman filter)
- **measurement_noise** - describes how noisy the measurements are (used for the Kalman filter)
- **update_frequency** - in milliseconds, limits how often the component sends updates to not "spam" the publisher, 0 disables the check and is the default

#### iBeacons ####

This component tracks only the iBeacons it finds and posts updates about them including a calculated their id, name, signal strength and a calculated distance.
To avoid faulty data through noise the distance values are smoothed using the [Kalman filter](https://en.wikipedia.org/wiki/Kalman_filter).
The iBeacon component is mostly useful if you want to address your beacons via the major minor system or if the BLE component did not work correctly with your hardware.

On Linux this component will have to run as root [unless you set the correct permissions](https://github.com/sandeepmistry/noble#running-on-linux).

```json
{
"ibeacon": {
"enabled": true,
"channel": "room_presence",
"max_distance": 0,
Expand Down Expand Up @@ -184,7 +218,9 @@ Please note that we are using a fork of the actual tool. Unfortunately the offic
"interval": 1000,
"channel": "motion_sensor"
}
]
],
"qos": 1,
"retain": true
}
}
```
Expand All @@ -197,6 +233,43 @@ Options:
- **port** - the actual physical port number to be tracked ([reference](https://github.com/rakeshpai/pi-gpio#about-the-pin-configuration))
- **interval** - the interval in which the port should be checked in milliseconds
- **channel** - channel for value updates
- **qos** - quality of service level for the message (for MQTT)
- **retain** - whether the message should be retained or not (for MQTT)

#### Shell Commands ####

This component executes any given shell command regularly and reports the stdout output to your publisher.

```json
{
"shell": {
"enabled": true,
"commands": [
{
"command": "/home/pi/airsensor/airsensor -o",
"regexp": "(.*)",
"float": false,
"interval": 60000,
"channel": "air_quality"
}
],
"qos": 0,
"retain": false
}
}
```

Options:

- **enabled** - enable or disable component
- **commands** - an array of commands to be executed
- **command** - any bash command, make sure the user executing room-assistant has the needed permissions
- **regexp** - regular expression string to tune your output, the first matched group will be used
- **float** - whether to convert to the output to a float or not
- **interval** - the interval in which the command should be executed in milliseconds
- **channel** - channel for value updates
- **qos** - quality of service level for the message (for MQTT)
- **retain** - whether the message should be retained or not (for MQTT)

## Running as a service ##

Expand Down
13 changes: 12 additions & 1 deletion components/ble.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ var console = process.console;
var KalmanFilter = require('kalmanjs').default;

var channel = config.get('ble.channel');
var updateFreq = parseInt(config.get('ble.update_frequency'), 0);

var lastUpdateTime = new Date();

function BLEScanner(callback) {
// constructor
Expand All @@ -30,6 +33,14 @@ BLEScanner.prototype._startScanning = function (state) {
};

BLEScanner.prototype._handlePacket = function (peripheral) {
if (updateFreq > 0) {
var currTime = new Date();
if ((currTime - lastUpdateTime) < updateFreq) {
return;
}
lastUpdateTime = currTime;
}

var advertisement = peripheral.advertisement;

// check if we have a whitelist
Expand Down Expand Up @@ -89,4 +100,4 @@ BLEScanner.prototype._filter = function (id, distance) {
return this.kalmanManager[id].filter(distance);
};

module.exports = BLEScanner;
module.exports = BLEScanner;
7 changes: 6 additions & 1 deletion components/gpio.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ function GPIO(callback) {
// constructor
this.callback = callback;

this.options = {
qos: config.get('gpio.qos'),
retain: config.get('gpio.retain')
};

this._init();
}

Expand Down Expand Up @@ -53,7 +58,7 @@ GPIO.prototype.read = function (port, channel) {
var payload = {
value: val
};
that.callback(channel, payload);
that.callback(channel, payload, that.options);
}
}
});
Expand Down
84 changes: 84 additions & 0 deletions components/ibeacon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
var config = require('config');
var bleacon = require('bleacon');
var console = process.console;

var KalmanFilter = require('kalmanjs').default;

var channel = config.get('ibeacon.channel');

function iBeaconScanner(callback) {
// constructor
this.callback = callback;
this.kalmanManager = {};

this._init();
console.info('iBeacon scanner was initialized');
}

iBeaconScanner.prototype._init = function () {
bleacon.startScanning();
bleacon.on('discover', this._handlePacket.bind(this));
};

iBeaconScanner.prototype._handlePacket = function (ibeacon) {
// check if we have a whitelist
// and if we do, if this id is listed there
var whitelist = config.get('ibeacon.whitelist') || [];

var id = ibeacon.uuid + '-' + ibeacon.major + '-' + ibeacon.minor;

if (whitelist.length == 0 || whitelist.indexOf(id) > -1) {

// default hardcoded value for beacon tx power
var txPower = ibeacon.measuredPower || -59;
var distance = this._calculateDistance(ibeacon.rssi, txPower);

// max distance parameter checking
var maxDistance = config.get('ibeacon.max_distance') || 0;
if (maxDistance == 0 || ibeacon.accuracy <= maxDistance) {
var filteredDistance = this._filter(id, distance);

var payload = {
id: id,
uuid: ibeacon.uuid,
major: ibeacon.major,
minor: ibeacon.minor,
rssi: ibeacon.rssi,
distance: filteredDistance,
accuracy: ibeacon.accuracy,
measuredpower: ibeacon.measuredPower,
proximity: ibeacon.proximity
};

this.callback(channel, payload);
}
}
};

iBeaconScanner.prototype._calculateDistance = function (rssi, txPower) {
if (rssi == 0) {
return -1.0;
}

var ratio = rssi * 1.0 / txPower;
if (ratio < 1.0) {
return Math.pow(ratio, 10);
}
else {
return (0.89976) * Math.pow(ratio, 7.7095) + 0.111;
}
};

iBeaconScanner.prototype._filter = function (id, distance) {
if (!this.kalmanManager.hasOwnProperty(id)) {
this.kalmanManager[id] = new KalmanFilter({
R: config.get('ibeacon.system_noise') || 0.01,
Q: config.get('ibeacon.measurement_noise') || 3
});
}

return this.kalmanManager[id].filter(distance);
};


module.exports = iBeaconScanner;
5 changes: 3 additions & 2 deletions components/mqtt.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ function MQTTPublisher() {
console.info('Connected to MQTT server');
}

MQTTPublisher.prototype.publish = function (channel, payload) {
MQTTPublisher.prototype.publish = function (channel, payload, options) {
var topic = channel + '/' + config.get('mqtt.topic');
this.client.publish(topic, JSON.stringify(payload));

this.client.publish(topic, JSON.stringify(payload), options);
};

module.exports = MQTTPublisher;
4 changes: 2 additions & 2 deletions components/publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ function Publisher() {
this._init();
}

Publisher.prototype.publish = function (channel, payload) {
Publisher.prototype.publish = function (channel, payload, options) {
if (this.mqttPublish) {
this.mqttPublish(channel, payload);
this.mqttPublish(channel, payload, options);
}
if (this.consolePublish) {
this.consolePublish(channel, payload);
Expand Down
62 changes: 62 additions & 0 deletions components/shell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
var config = require('config');
var exec = require('child_process').exec;
var console = process.console;

function Shell(callback) {
// constructor
this.callback = callback;

this.options = {
qos: config.get('shell.qos'),
retain: config.get('shell.retain')
};

this._init();
}

Shell.prototype._init = function () {
var that = this;
var commands = config.get('shell.commands');

commands.forEach(function (command) {
var regex = new RegExp(command.regexp);

setInterval(function() {
that.executeCommand(command.command, regex, command.channel, command.float)
}, command.interval);

console.info('Shell command \"' + command.command + '\" initialized')
});
};

Shell.prototype.executeCommand = function (command, regex, channel, convertToFloat) {
var that = this;

exec(command, function(err, stdout, stderr) {
if (err) {
console.error(err);
}
if (stderr) {
console.warning(stderr);
}

if (stdout) {
var matches = stdout.match(regex);

if (matches) {
var match = matches[1];
if (convertToFloat) {
match = parseFloat(match);
}

var payload = {
value: match
};

that.callback(channel, payload, that.options);
}
}
})
};

module.exports = Shell;
24 changes: 22 additions & 2 deletions config/default.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"app": {
"unsafe": false
},
"mqtt": {
"enabled": false,
"url": "mqtt://localhost",
Expand All @@ -17,6 +20,15 @@
"whitelist": [],
"use_mac": false,
"system_noise": 0.01,
"measurement_noise": 3,
"update_frequency": 0
},
"ibeacon": {
"enabled": false,
"channel": "room_presence",
"max_distance": 0,
"whitelist": [],
"system_noise": 0.01,
"measurement_noise": 3
},
"temper": {
Expand All @@ -29,6 +41,14 @@
"gpio": {
"enabled": false,
"only_send_updates": true,
"ports": []
"ports": [],
"qos": 0,
"retain": false
},
"shell": {
"enabled": false,
"commands": [],
"qos": 0,
"retain": false
}
}
}
Loading

0 comments on commit d7f3f85

Please sign in to comment.