-
Notifications
You must be signed in to change notification settings - Fork 55
/
kittyCam.js
156 lines (122 loc) · 3.79 KB
/
kittyCam.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* KittyCam
* A Raspberry Pi app using a camera PIR motion sensor, with cat facial detection
*
* Tomomi Imura (@girlie_mac)
*/
'use strict'
const config = require('./config');
const fs = require('fs');
const child_process = require('child_process');
require('events').EventEmitter.prototype._maxListeners = 20;
// Johnny-Five for RPi
const raspi = require('raspi-io');
const five = require('johnny-five');
const board = new five.Board({io: new raspi()});
let i = 0;
board.on('ready', () => {
console.log('board is ready');
// Create a new `motion` hardware instance.
const motion = new five.Motion('P1-7'); //a PIR is wired on pin 7 (GPIO 4)
// 'calibrated' occurs once at the beginning of a session
motion.on('calibrated', () => {
console.log('calibrated');
});
// Motion detected
motion.on('motionstart', () => {
console.log('motionstart');
// Run raspistill command to take a photo with the camera module
let filename = 'photo/image_'+i+'.jpg';
let args = ['-w', '320', '-h', '240', '-o', filename, '-t', '1'];
let spawn = child_process.spawn('raspistill', args);
spawn.on('exit', (code) => {
console.log('A photo is saved as '+filename+ ' with exit code, ' + code);
let timestamp = Date.now();
i++;
// Detect cats from photos
if((/jpg$/).test(filename)) { // Ignore the temp filenames like image_001.jpg~
let imgPath = __dirname + '/' + filename;
// Child process: read the file and detect cats with KittyDar
let args = [imgPath];
let fork = child_process.fork(__dirname + '/detectCatsFromPhoto.js');
fork.send(args);
// the child process is completed
fork.on('message', (base64) => {
if(base64) {
uploadToCloudinary(base64, timestamp);
}
// Once done, delete the photo to clear up the space
deletePhoto(imgPath);
});
}
})
});
// 'motionend' events
motion.on('motionend', () => {
console.log('motionend');
});
});
function deletePhoto(imgPath) {
fs.unlink(imgPath, (err) => {
if (err) {
return console.error(err);
}
console.log(imgPath + ' is deleted.');
});
}
// PubNub to publish the data
// to make a separated web/mobile interface can subscribe the data to stream the photos in realtime.
const channel = 'kittyCam';
const pubnub = require('pubnub').init({
subscribe_key: config.pubnub.subscribe_key,
publish_key: config.pubnub.publish_key
});
function publish(url, timestamp) {
pubnub.publish({
channel: channel,
message: {image: url, timestamp: timestamp},
callback: (m) => {console.log(m);},
error: (err) => {console.log(err);}
});
}
// Nexmo to send SMS
const Nexmo = require('nexmo');
const nexmo = new Nexmo({
apiKey: config.nexmo.api_key,
apiSecret: config.nexmo.api_secret
});
function sendSMS(url, timestamp) {
var t = new Date(timestamp).toLocaleString();
let msg = '🐈 detected on '+ t + '! See the photo at: ' + url;
nexmo.message.sendSms(
config.nexmo.fromNumber,
config.nexmo.toNumber,
msg,
{type: 'unicode'},
(err, responseData) => {
if (err) {
console.log(err);
} else {
console.dir(responseData);
}
}
);
}
// Cloudinary to store the photos
const cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: config.cloudinary.cloud_name,
api_key: config.cloudinary.api_key,
api_secret: config.cloudinary.api_secret
});
function uploadToCloudinary(base64Img, timestamp) {
cloudinary.uploader.upload(base64Img, (result) => {
console.log(result);
publish(result.url, timestamp); // Comment this out if you don't use PubNub
sendSMS(result.url, timestamp); // Comment this out if you don't use Nexmo
});
}
// Ctrl-C
process.on('SIGINT', () => {
process.exit();
});