Commit 17f914dd authored by Mikhail Vataleu's avatar Mikhail Vataleu
Browse files

Add ESLint support; Define codestyle rules; Refactoring;

parent 7f72b4f9
{
"extends": "airbnb-base",
"env": {
"es6": true,
"node": true
},
"rules": {
"brace-style": [
"error",
"stroustrup"
],
"comma-dangle": [
"error",
"never"
],
"no-unused-vars": [
"warn"
],
"no-console": [
"off"
],
"global-require":[
"off"
]
}
}
\ No newline at end of file
......@@ -102,8 +102,8 @@ This application is using [Nordic-Thingy52-Nodejs](https://github.com/NordicPlay
* Switch to `classic` mode.
* Execute following commands:
```
sudo update-ca-certificates
sudo service ntp stop
sudo ntpdate -s time.nist.gov
sudo service ntp start
sudo update-ca-certificates
```
\ No newline at end of file
#!/usr/bin/env node
'use strict';
const os = require('os');
const MQTT = require('mqtt');
let Thingy = null;
......@@ -15,242 +13,245 @@ let cleanup = false;
let mqttClient = null;
let connectedThingy = null;
const thingyState = {
accel: {
x: 0,
y: 0,
z: 0
},
button: false,
timestamp: 0
accel: {
x: 0,
y: 0,
z: 0
},
button: false,
timestamp: 0
};
// Main
// Commons
// ==========
const config = init();
start(config);
const loadConfig = () => {
const config = require('./config');
let { topic } = config.mqtt;
topic = topic.replace('{hostname}', os.hostname());
config.mqtt.topic = topic;
return config;
};
// App Utils
// Broker Utils
// ==========
function loadConfig() {
const config = require('./config');
let topic = config.mqtt.topic;
topic = topic.replace('{hostname}', os.hostname());
config.mqtt.topic = topic;
return config;
}
function init() {
const config = loadConfig();
// Setup noble lib
process.env['NOBLE_HCI_DEVICE_ID'] = config.ble.hciDeviceNum;
Thingy = require('thingy52');
// Set exit handlers
process.on('exit', function () {
stop();
});
process.on('uncaughtException', function (err) {
console.error('uncaughtException:', err);
stop();
process.exit(-1);
});
return config;
}
function start(config) {
console.log('=== Thingy:52 to MQTT ===');
console.log('Configuration:', config);
console.log('=========================');
brokerConnectTaskId = startBrokerConnectTask(config);
startDiscoverThingyTask(config);
dataTransmissionTaskId = startDataTransmissionTask(config);
}
function stop() {
if (cleanup) return;
cleanup = true;
console.log('=========================');
stopDataTransmissionTask();
stopBrokerConnectTask();
stopDiscoverThingyTask();
}
const brokerDisconnect = () => {
if (mqttClient) {
mqttClient.end(true);
mqttClient = null;
}
};
// Broker Utils
// ==========
const brokerConnect = (mqttConfig) => {
connectingToBroker = true;
const mqttAddr = `${mqttConfig.host}:${mqttConfig.port}`;
console.log(`[MQTT] Connecting to: ${mqttAddr}`);
function startBrokerConnectTask(config) {
console.log('[MQTT] Start Broker Connect Task ...');
const connectionInterval = 3 * 1000;
return setInterval(function () {
if (connectingToBroker || !mqttClient) {
brokerConnect(config.mqtt);
}
}, connectionInterval);
}
function stopBrokerConnectTask() {
console.log('[MQTT] Stop Broker Connect Task ...');
clearInterval(brokerConnectTaskId);
brokerDisconnect();
}
function brokerConnect(mqttConfig) {
connectingToBroker = true;
const mqttAddr = mqttConfig.host + ':' + mqttConfig.port;
console.log('[MQTT] Connecting to: ' + mqttAddr);
const client = MQTT.connect({
protocol: 'mqtt',
host: mqttConfig.host,
port: mqttConfig.port,
});
client.on('connect', connectionSuccessHandler);
client.on('close', connectionProblemsHandler);
client.on('error', connectionProblemsHandler);
client.on('end', connectionProblemsHandler);
client.on('offline', connectionProblemsHandler);
function connectionSuccessHandler() {
mqttClient = client;
console.log('[MQTT] Successfully connected to: ' + mqttAddr);
connectingToBroker = false;
const connectionProblemsHandler = (err) => {
if (err) {
console.log('[MQTT] Connection problem, disconnecting ... ', err);
brokerDisconnect();
connectingToBroker = false;
}
};
const client = MQTT.connect({
protocol: 'mqtt',
host: mqttConfig.host,
port: mqttConfig.port
});
client.on('connect', () => {
mqttClient = client;
console.log(`[MQTT] Successfully connected to: ${mqttAddr}`);
connectingToBroker = false;
});
client.on('close', connectionProblemsHandler);
client.on('error', connectionProblemsHandler);
client.on('end', connectionProblemsHandler);
client.on('offline', connectionProblemsHandler);
};
function connectionProblemsHandler(err) {
if (err) {
console.log('[MQTT] Connection problem, disconnecting ... ', err);
brokerDisconnect();
connectingToBroker = false;
}
const startBrokerConnectTask = (config) => {
console.log('[MQTT] Start Broker Connect Task ...');
const connectionInterval = 3 * 1000;
return setInterval(() => {
if (connectingToBroker || !mqttClient) {
brokerConnect(config.mqtt);
}
}
}, connectionInterval);
};
function brokerDisconnect() {
if (mqttClient) {
mqttClient.end(true);
mqttClient = null;
}
}
const stopBrokerConnectTask = () => {
console.log('[MQTT] Stop Broker Connect Task ...');
clearInterval(brokerConnectTaskId);
brokerDisconnect();
};
// Thingy Utils
// ==========
function startDiscoverThingyTask(config) {
console.log('[BLE] Start Discovery Task ...');
const id = macToId(config.ble.deviceMAC);
Thingy.discoverWithFilter(function(device) {
console.log('[BLE] Discover:', device.id, 'target:', id);
if (id === '*') return true;
return id === device.id;
}, handleDiscover);
function handleDiscover(thingy) {
if (!connectedThingy) {
connectAndSetupThingy(thingy);
}
const disconnectThingy = (disconnected) => {
if (!disconnected && connectedThingy) {
connectedThingy.disconnect();
}
connectedThingy = null;
};
const macToId = mac => (mac.toLowerCase().replace(new RegExp(':', 'g'), ''));
const startDiscoverThingyTask = (config) => {
const handleDiscover = (thingy) => {
if (!connectedThingy) {
connectAndSetupThingy(thingy); // eslint-disable-line no-use-before-define
}
}
};
console.log('[BLE] Start Discovery Task ...');
const id = macToId(config.ble.deviceMAC);
Thingy.discoverWithFilter((device) => {
console.log('[BLE] Discover:', device.id, 'target:', id);
if (id === '*') return true;
return id === device.id;
}, handleDiscover);
};
function stopDiscoverThingyTask(disconnected) {
console.log('[BLE] Stop Discovery Task ...');
Thingy.stopDiscover(function(err) {
if (err) {
console.log(err);
}
});
disconnectThingy(disconnected);
}
/**
* Restart discovery task as workaround for noble-device issue.
* */
function restartDiscoverThingyTask(disconnected) {
const config = loadConfig();
stopDiscoverThingyTask(disconnected);
setTimeout(function () {
startDiscoverThingyTask(config);
}, 5 * 1000);
}
function connectAndSetupThingy(thingy) {
console.log('[BLE] Connecting to the Thingy:52', thingy.id);
thingy.connectAndSetUp(function(error) {
if (error) handleError(error);
else {
// User Interface
thingy.led_breathe({
color: 2,
intensity: 100,
delay: 1000,
});
thingy.button_enable(handleError);
thingy.on('buttonNotif', function(state) {
if (state === 'Pressed') {
thingyState.button = true;
}
});
// Sensors
thingy.raw_enable(handleError);
thingy.on('rawNotif', function(rawData) {
thingyState.accel.x = rawData.accelerometer.x;
thingyState.accel.y = rawData.accelerometer.y;
thingyState.accel.z = rawData.accelerometer.z;
});
// Service
thingy.on('disconnect', function() {
console.log('[BLE] Thingy:52 disconnected');
restartDiscoverThingyTask(true)
});
connectedThingy = thingy;
console.log('[BLE] Successfully connected to ', thingy.id);
}
});
function handleError(error) {
if (error) {
console.log('[BLE] Connection/Setup problem, disconnecting ...', error);
restartDiscoverThingyTask();
const stopDiscoverThingyTask = (disconnected) => {
console.log('[BLE] Stop Discovery Task ...');
Thingy.stopDiscover((err) => {
if (err) {
console.log(err);
}
});
disconnectThingy(disconnected);
};
const restartDiscoverThingyTask = (disconnected) => { // XXX: workaround for noble-device issue
const config = loadConfig();
stopDiscoverThingyTask(disconnected);
setTimeout(() => {
startDiscoverThingyTask(config);
}, 5 * 1000);
};
const connectAndSetupThingy = (thingy) => {
const handleError = (error) => {
if (error) {
console.log('[BLE] Connection/Setup problem, disconnecting ...', error);
restartDiscoverThingyTask();
}
};
console.log('[BLE] Connecting to the Thingy:52', thingy.id);
thingy.connectAndSetUp((error) => {
if (error) handleError(error);
else {
// User Interface
thingy.led_breathe({
color: 2,
intensity: 100,
delay: 1000
});
thingy.button_enable(handleError);
thingy.on('buttonNotif', (state) => {
if (state === 'Pressed') {
thingyState.button = true;
}
});
// Sensors
thingy.raw_enable(handleError);
thingy.on('rawNotif', (rawData) => {
thingyState.accel.x = rawData.accelerometer.x;
thingyState.accel.y = rawData.accelerometer.y;
thingyState.accel.z = rawData.accelerometer.z;
});
// Service
thingy.on('disconnect', () => {
console.log('[BLE] Thingy:52 disconnected');
restartDiscoverThingyTask(true);
});
connectedThingy = thingy;
console.log('[BLE] Successfully connected to ', thingy.id);
}
}
});
};
function disconnectThingy(disconnected) {
if (!disconnected && connectedThingy) {
connectedThingy.disconnect();
// Transmission Utils
// ==========
const transmission = (config) => {
thingyState.timestamp = Math.round((new Date()).getTime() / 1000);
const msg = JSON.stringify(thingyState);
mqttClient.publish(config.topic, msg);
console.log(`[TRS] Publish to ${config.topic} ${msg}`);
thingyState.button = false;
};
const startDataTransmissionTask = (config) => {
console.log('[TRS] Start Transmission Task ...');
const transmissionInterval = 3 * 1000;
return setInterval(() => {
if (mqttClient && connectedThingy) {
transmission(config.mqtt);
}
connectedThingy = null;
}
}, transmissionInterval);
};
function macToId(mac) {
return mac.toLowerCase().replace(new RegExp(':', 'g'), '');
}
const stopDataTransmissionTask = () => {
console.log('[TRS] Stop Transmission Task ...');
clearInterval(dataTransmissionTaskId);
};
// Transmission Utils
// App Utils
// ==========
function startDataTransmissionTask(config) {
console.log('[TRS] Start Transmission Task ...');
const transmissionInterval = 3 * 1000;
return setInterval(function () {
if (mqttClient && connectedThingy) {
transmission(config.mqtt);
}
}, transmissionInterval);
}
function stopDataTransmissionTask() {
console.log('[TRS] Stop Transmission Task ...');
clearInterval(dataTransmissionTaskId);
}
function transmission(config) {
thingyState.timestamp = Math.round((new Date()).getTime() / 1000);
const msg = JSON.stringify(thingyState);
mqttClient.publish(config.topic, msg);
console.log('[TRS] Publish to ' + config.topic + ' ' + msg);
thingyState.button = false;
}
const start = (config) => {
console.log('=== Thingy:52 to MQTT ===');
console.log('Configuration:', config);
console.log('=========================');
brokerConnectTaskId = startBrokerConnectTask(config);
startDiscoverThingyTask(config);
dataTransmissionTaskId = startDataTransmissionTask(config);
};
const stop = () => {
if (cleanup) return;
cleanup = true;
console.log('=========================');
stopDataTransmissionTask();
stopBrokerConnectTask();
stopDiscoverThingyTask();
};
const init = () => {
const config = loadConfig();
// Setup noble lib
process.env.NOBLE_HCI_DEVICE_ID = config.ble.hciDeviceNum;
Thingy = require('thingy52');
// Set exit handlers
process.on('exit', () => {
stop();
});
process.on('uncaughtException', (err) => {
console.error('uncaughtException:', err);
try {
stop();
}
catch (stopErr) {
console.error('Error while stop:', stopErr);
}
finally {
process.exit(-1);
}
});
return config;
};
// Application
// ==========
const config = init();
setTimeout(() => { // XXX: Wait HCI devices on system startup
start(config);
}, 5 * 1000);
......@@ -5,6 +5,8 @@
"main": "index.js",
"scripts": {
"start": "node ./index.js",
"lint": "./node_modules/.bin/eslint .",
"lint:fix": "npm run lint -- --fix",
"test": "echo \"Error: no test specified\" && exit 1"
},
"engines": {
......@@ -30,5 +32,10 @@
"dependencies": {
"mqtt": "^2.17.0",
"thingy52": "^1.0.4"
},
"devDependencies": {
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.10.0"
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment