Skip to content

Instantly share code, notes, and snippets.

@siyo
Last active November 3, 2016 05:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save siyo/a9e45d892f17edf5c9bf1447e868b315 to your computer and use it in GitHub Desktop.
Save siyo/a9e45d892f17edf5c9bf1447e868b315 to your computer and use it in GitHub Desktop.
部屋の環境を監視しインターネットに公開するIoTソリューション (Runtime: Node.js v.4.4.x)
'use strict';
// node deps
const path = require('path');
const os = require ('os');
const fs = require('fs');
// npm deps
const noble = require('noble');
const Netatmo = require('netatmo');
const Twitter = require('twitter');
const RaspiCam = require('raspicam');
const _ = require('lodash');
const log = require('npmlog');
// config
// e.g. config.json
// {
// "twitter":{
// "consumer_key": "xxxxxxxxxxxxxxx",
// "consumer_secret": "xxxxxxxxxxxxxxx",
// "access_token_key": "xxxxxxxxxxxxxxx",
// "access_token_secret": "xxxxxxxxxxxxxxx"
// },
// "netatmo": {
// "client_id": "xxxxxxxxxxxxxxx",
// "client_secret": "xxxxxxxxxxxxxxx",
// "username": "xxxxxxxxxxxxxxx",
// "password": "xxxxxxxxxxxxxxx"
// }
// }
//
const config = require('./config.json');
const TAG = path.basename(__filename);
const INTERVAL_TWEET = 15 * 60 * 1000; // msec
const IMG_DIR = '/tmp';
const IMG_FILENAME = 'raspicam.jpg';
const IMG_PATH = IMG_DIR + '/' + IMG_FILENAME;
//log.level = 'verbose';
var luxes = [];
const tw = new Twitter(config.twitter);
const netatmo = new Netatmo(config.netatmo);
const cam = new RaspiCam({
mode: 'photo',
output: IMG_PATH,
w: 1280,
h: 720,
q: 70,
e: 'jpg'
});
function calcLux() {
var total = _.reduce(luxes, (memo, lux) => {
return memo += lux;
}, 0);
var val = Math.round(total / luxes.length);
var emoji = val > 2750 ? '☀️' :
val > 2000 ? '🌤' :
val > 1000 ? '⛅️' :
val > 500 ? '☁️' :
val > 100 ? '💡':
val > 10 ? '🕯':
'👻';
luxes = [];
return emoji + ' ' + val + ' ';
}
function parseNetatmoDevice(device) {
var status = '';
var data = device.dashboard_data;
if (!data) {
log.warn(TAG, 'data: %j', data);
return status;
}
_.each([
['Temperature', '🌡', '℃'],
['Humidity','💧', '%'],
['Pressure', '🎈', 'hPa'],
['CO2','🌳', 'ppm' ],
['Noise', '🔊','dB ']
], (ary) => {
var key = ary[0],
emoji = ary[1],
unit = ary[2];
var val = data[key];
if (_.isNumber(val))
status += emoji + ' ' + val + unit + ' ';
});
return status;
}
function twpost(status, media_ids) {
var st = {
status: status,
media_ids: media_ids
};
tw.post('statuses/update', st, (error) => {
if(error)
log.error(TAG, 'Error: %j', error);
else
log.info(TAG, 'POST: %j', st);
});
}
const throttledCamStill = _.throttle(() => {
cam.start();
}, INTERVAL_TWEET);
cam.on('start', () => {
log.info(TAG, 'cam start');
});
cam.on('read', (err, timestamp, filename) => {
if (err)
log.error(TAG, 'cam saved Error: %j', err);
else
log.info(TAG, 'cam saved: %s (%d)', filename, timestamp );
if (filename !== IMG_FILENAME) {
return;
}
netatmo.getDevicelist((err, devices) => {
var data = fs.readFileSync(IMG_PATH);
tw.post('media/upload', {media: data}, function(error, media) {
var media_ids = null;
var status = '';
if (!error) {
media_ids = media.media_id_string;
}
status += calcLux();
if (!err)
status += parseNetatmoDevice(devices[0]);
else
log.error(TAG, '%j', err);
status += '⏰ ' + _.now() + 'UTC';
twpost(status, media_ids);
});
});
});
cam.on('stop', () => {
log.info(TAG, 'cam stop');
});
cam.on('exit', () => {
console.log('cam exit');
});
noble.on('stateChange', (state) => {
if (state === 'poweredOn') {
noble.startScanning([], true);
} else {
noble.stopScanning();
}
});
noble.on('discover', (peripheral) => {
var name = peripheral.advertisement.localName,
data = peripheral.advertisement.manufacturerData;
var val;
log.verbose(TAG, 'peripheral.advertisement:%j', peripheral.advertisement);
log.verbose(TAG, 'endian:%s', os.endianness());
if (!_.isString(name) || !name.match(/^BLECAST_BL/) || !data)
return;
val = data.readUInt8(5) * 256 + data.readUInt8(4);
luxes.push(val);
log.verbose(TAG, 'MEASURE: %s %d', name, val);
throttledCamStill();
});
{
"name": "kitazawagosho",
"version": "1.1.0",
"description": "Environment of Kitazawa-gosho",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"ble",
"bluetooth",
"illuminance",
"sensor",
"IoT",
"netatmo"
],
"author": "siyo",
"license": "MIT",
"dependencies": {
"async": "^2.0.0-rc.5",
"lodash": "^4.13.1",
"netatmo": "^1.5.0",
"noble": "1.5.0",
"npmlog": "^2.0.4",
"raspicam": "^0.2.13",
"twitter": "^1.3.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment