forked from thobach/MMM-Gestures
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node_helper.js
165 lines (154 loc) · 5.95 KB
/
node_helper.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
157
158
159
160
161
162
163
164
165
"use strict";
/*
* Node.js application used to collect events from Arduino via serial USB port
* - gesture and presence events are forwarded to web view via websockets
* - power saving mode to turn off display if no gesture was received for 5 minutes
*
* By Thomas Bachmann (https://github.com/thobach)
*
* License: MIT
*
*/
// retrieving gesture and distance events from Arduino happens via serial port (USB)
var NodeHelper = require("node_helper");
const { ReadlineParser } = require('@serialport/parser-readline')
const { SerialPort } = require('serialport')
module.exports = NodeHelper.create({
start: function () {
// by default assuming monitor is on
this.hdmiOn = true;
// handler for timeout function, used to clear timer when display goes off
this.turnOffTimer = undefined;
// put monitor to sleep after 2 minute without gesture or distance events
this.WAIT_UNTIL_SLEEP = 2 * 60 * 1000;
this.reconnectionAttempts = 0;
this.init();
},
// broadcast text messages to all subscribers (open web views)
broadcast: function (str) {
this.sendSocketNotification("RETRIEVED_GESTURE", str);
console.log(new Date() + ': sendSocketNotification: RETRIEVED_GESTURE ' + str);
},
// turn display on or off
saveEnergy: function (person) {
var self = this;
console.log(new Date() + ': saveEnergy() called with person: ' + person + ', in state hdmiOn: ' + self.hdmiOn + ', turnOffTimer:' + self.turnOffTimer);
// deactivate timeout handler if present
if (self.turnOffTimer) {
console.log(new Date() + ': removing save energy timer');
clearTimeout(self.turnOffTimer);
}
// turn on display if off and person is present in front of mirror
if (person == "PRESENT" && !self.hdmiOn) {
console.log(new Date() + ': turn on display again');
// make system call to power on display
var exec = require('child_process').exec;
// alternatively could usee also "tvservice -p", but showed less compatability
exec('DISPLAY=:0 && xrandr --output HDMI-1 --mode \"1920x1080\" --rotate left', function (error, stdout, stderr) {
if (error !== null) {
console.log(new Date() + ': exec error: ' + error);
} else {
process.stdout.write(new Date() + ': Turned monitor on.\n');
self.hdmiOn = true;
}
});
}
// activate timer to turn off display if display is on and person is away for a while
else if (person == "AWAY" && self.hdmiOn) {
console.log(new Date() + ': set timer to turn off display in ' + self.WAIT_UNTIL_SLEEP + 's');
// activate time to turn off display
self.turnOffTimer = setTimeout(function () {
// make system call to turn off display
var exec = require('child_process').exec;
// alternatively could usee also "tvservice -o", but showed less compatability
exec('DISPLAY=:0 xrandr --output HDMI-1 --off', function (error, stdout, stderr) {
if (error !== null) {
console.log(new Date() + ': exec error: ' + error);
} else {
process.stdout.write(new Date() + ': Turned monitor off.\n');
self.hdmiOn = false;
}
});
}, self.WAIT_UNTIL_SLEEP);
}
},
createParser: function (self, serialPort) {
const parser = serialPort.pipe(new ReadlineParser({ delimiter: '\n' }));
// list to events from Arduino via serial USB port (e.g. from /dev/ttyACM0)
console.log('serial port opened');
// Listen for data event
parser.on('data', function (data) {
// parse Arduino distance events (distance sensor)
if (data.indexOf("Person: ") == 0) {
console.log(data);
var person = data.replace("Person: ", "");
// remove ending newline
person = person.replace(/(\r\n|\n|\r)/gm, "");
self.broadcast(person);
self.saveEnergy(person);
}
// parse Arduino gesture events (gesture sensor)
else if (data.indexOf("Gesture: ") == 0) {
console.log(data);
var gesture = data.replace("Gesture: ", "");
// remove ending newline
gesture = gesture.replace(/(\r\n|\n|\r)/gm, "");
self.broadcast(gesture);
}
// Parse error messages from Arduino and log to stderr
else if (data.indexOf("ERROR: ") == 0) {
console.error(data);
}
});
},
// init node.js app
init: function () {
// make system call to get device where Arduino is connected (e.g. /dev/ttyACM0 or /dev/ttyUSB0)
// can vary depending on which USB port the Arduino is connected
var exec = require('child_process').exec;
var self = this;
exec('ls /dev/ttyUSB*', function (error, stdout, stderr) {
if (error !== null) {
console.log(new Date() + ': exec error: ' + error);
} else {
// extract device information (which USB port)
var usbDev = stdout.replace("\n", "");
process.stdout.write(new Date() + ': Using USB: ' + usbDev + '.\n');
// open serial port to Arduino
const serialPort = new SerialPort({ path: usbDev, baudRate: 9600 });
// create parser to parse events from Arduino
self.createParser(self, serialPort);
// Listen for error event
serialPort.on('error', function (err) {
console.error('Error: ', err.message);
});
// Listen for close event and attempt to reopen serial port and
// parser. If after 5 attempts still not working, print error
// message to stderr, turn off the display (to prevent burn-in)
// and exit.
serialPort.on('close', function () {
console.log('serial port closed');
self.reconnectionAttempts++;
if (self.reconnectionAttempts < 5) {
console.log('attempting to reopen serial port');
self.init();
this.reconnectionAttempts = 0;
} else {
console.error('failed to reopen serial port after 5 attempts');
// make system call to turn off display
var exec = require('child_process').exec;
exec('DISPLAY=:0 xrandr --output HDMI-1 --off', function (error, stdout, stderr) {
if (error !== null) {
console.log(new Date() + ': exec error: ' + error);
} else {
process.stdout.write(new Date() + ': Turned monitor off.\n');
self.hdmiOn = false;
}
});
process.exit(1);
}
});
}
});
},
});