-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathraspPi.js
261 lines (227 loc) · 10.4 KB
/
raspPi.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
var async = require("async");
var Firebase = require("firebase");
var SerialPort = require("serialport");
var colors = require("colors/safe");
var Queue = require("firebase-queue");
var exec = require('child_process').exec;
// Configuration variables
var verbose = true;
var serialBaud = 9600;
var timeoutAfterLedOff = 750;
var ledArduinoSerialNum = "75437303830351917221";
var pumpArduinoSerialNum = "754373038303515150C1";
var queueRef = new Firebase('https://boozebot.firebaseio.com/drinkQueue');
// Serial ports
var serialPortLed;
var serialPortPump;
// Keep track of previous bottle lighting color
var colorNum = 1;
// Rasp Pi -> Arduino message structure {
// "msgType": <0: drink on queue, 1: set individual LED color, 2: dispense liquor, 3: done making drink>
// --> if 0:
// --> "drinkName": <name of drink on queue>
// --> "userName" : <name of user who ordered drink>
// --> if 1:
// --> "led": {
// "r": <value between 0 and 4095>,
// "g": <value between 0 and 4095>,
// "b": <value between 0 and 4095>
// }
// --> if 2:
// --> "liquor": {
// "amt": <amount to pump in fl oz>,
// "bot": <bottle number to pump amt from>
// }
// --> if 3: <no further info needed>
// }
// Arduino -> Rasp Pi response message structure {
// "response": <0: data error, 1: drink cancelled, 2: start making drink, 3: done pumping ingredient>
// }
// Chooses color to light bottle for when next liquor pours
var pickLightingColor = function(bottleNum) {
var colorRGB;
switch(colorNum) {
case 0:
colorRGB = {"r": 4095, "g": 0, "b": 0};
break;
case 1:
colorRGB = {"r": 0, "g": 4095, "b": 0};
break;
case 2:
colorRGB = {"r": 0, "g": 0, "b": 4095};
break;
case 3:
colorRGB = {"r": 4095, "g": 4095, "b": 0};
break;
case 4:
colorRGB = {"r": 0, "g": 4095, "b": 4095};
break;
case 5:
colorRGB = {"r": 4095, "g": 0, "b": 4095};
break;
case 6:
colorRGB = {"r": 4095, "g": 4095, "b": 4095};
break;
}
// Increment state
if (colorNum == 6) {
colorNum = 0;
} else {
colorNum++;
}
colorRGB["num"] = parseInt(bottleNum);
return colorRGB;
}
// Dispense ingredient
var dispenseIngredient = function(callback, ingredient) {
console.log(colors.green(" Dispensing ") + colors.green.underline(ingredient["amountUsed"]) + colors.green(" fl oz of bottle ") + colors.green.underline(ingredient["liquorBottleNum"]));
// Condense ingredient data for Arduino
var condensedIngredientPacket = {
"msgType": 2,
"liquor": {
"amt": ingredient["amountUsed"],
"bot": ingredient["liquorBottleNum"]
}
};
var ingredientString = JSON.stringify(condensedIngredientPacket);
// Write to Pump Arduino
if (verbose) { console.log(colors.white(" Ingredient string: " + ingredientString)); }
serialPortPump.write(ingredientString, function(ingredientWriteErr, ingredientWriteResults) {
if (ingredientWriteErr != null) { console.log(colors.red(" Write errors: " + ingredientWriteErr)); }
// Wait for response from Pump Arduino
if (verbose) { console.log(colors.magenta(" Waiting for response...")); }
serialPortPump.on('data', function(ingredientResponseData) {
if (verbose) { console.log(colors.white(" Response packet string: " + ingredientResponseData)); }
// Close and reopen serial port around parsing
serialPortPump.close(function(ingredientCloseErr) {
if (ingredientCloseErr != null) { console.log(colors.red(" Port close error: " + ingredientCloseErr)); }
var ingredientResponseObj = JSON.parse(ingredientResponseData);
serialPortPump.open(function(ingredientOpenErr) {
if (ingredientOpenErr != null) { console.log(colors.red(" Port reopen error: " + ingredientOpenErr)); }
if (ingredientResponseObj["response"] == 3) {
if (verbose) { console.log(colors.green(" Done pumping ingredient")); }
callback(ingredientWriteErr, "two");
}
});
});
});
});
}
// Listens to Firebase queue for new data
var firebaseListener = function(data, progress, resolve, reject) {
// New drink on queue, send to LCD attached to LED Arduino
console.log(colors.white("New drink on queue: ") + colors.white.underline(data["recipeUsed"]));
var drinkPacket = {
"msgType": 0,
"drinkName": data["recipeUsed"]
};
var drinkPacketString = JSON.stringify(drinkPacket);
console.log(colors.yellow("Sending drink on queue to LED Arduino..."));
if (verbose) { console.log(colors.white(" Drink packet string: " + drinkPacketString)); }
serialPortLed.write(drinkPacketString, function(err, results) {
if (err != null) { console.log(colors.red(" Write errors: " + err)); }
// Wait for response from LED Arduino
if (verbose) { console.log(colors.magenta(" Waiting for response...")); }
serialPortLed.on('data', function(drinkResponse) {
if (verbose) { console.log(colors.white(" Response packet string: " + drinkResponse)); }
// Close and reopen serial port around parsing
serialPortLed.close(function(closeErr) {
if (closeErr != null) { console.log(colors.red(" Port close error: " + closeErr)); }
var responseObj = JSON.parse(drinkResponse);
serialPortLed.open(function(openErr) {
if (openErr != null) { console.log(colors.red(" Port reopen error: " + openErr)); }
if (responseObj["response"] == 0) { // Data error
console.log(colors.red("LED Arduino says there was an error with its received data"));
reject("Data error");
} else if (responseObj["response"] == 1) { // Drink cancelled
console.log(colors.blue("Drink cancelled by user"));
reject("Drink cancelled by user");
} else if (responseObj["response"] == 2) { // Continue making drink on queue
console.log(colors.green("BoozeBot making drink: ") + colors.green.underline(data["recipeUsed"]));
// Compress/reformat ingredient list
var ingredientList = {};
for (var i = 1; i <= parseInt(data["ingredientCount"], 10); i++) {
ingredientList[i] = data["ingredient" + i];
}
async.eachSeries(ingredientList, function(ingredient, loopCallback) {
dispenseIngredient(loopCallback, ingredient);
}, function(err) {
console.log(colors.green("BoozeBot finished making drink: ") + colors.green.underline(data["recipeUsed"]));
// Create completion data packet to send to LED Arduino
var completionPacket = {
"msgType": 3
};
var completionString = JSON.stringify(completionPacket);
// Write to LED Arduino
if (verbose) { console.log(colors.white(" Completion string: " + completionString)); }
serialPortLed.write(completionString, function(completionErr, completionResult) {
if (completionErr != null) { console.log(colors.red(" Write errors: " + completionErr)); }
resolve();
});
});
}
});
});
});
});
}
// Opens serial port to LED Arduino
var ledPortOpen = function() {
return new Promise(function(resolve, reject) {
serialPortLed.on("open", function() {
console.log(colors.blue.bgWhite("Serial port to LED Arduino open"));
resolve();
});
});
}
// Opens serial port to Pump Arduino
var pumpPortOpen = function() {
return new Promise(function(resolve, reject) {
serialPortPump.on("open", function() {
console.log(colors.blue.bgWhite("Serial port to Pump Arduino open"));
resolve();
});
});
}
// Find and open serial ports to Arduinos
var promises = [];
SerialPort.list(function(err, ports) {
for (var i = 0; i < ports.length; ++i) {
var port = ports[i];
if (port.serialNumber != undefined) {
serialNum = port.serialNumber;
serialNum = serialNum.replace("Arduino__www.arduino.cc__0043_", "");
if (serialNum == ledArduinoSerialNum) {
var comName = port.comName;
comName = comName.replace("cu", "tty");
// Open serial port to LED Arduino
serialPortLed = new SerialPort.SerialPort(comName, {
baudrate: serialBaud,
parser: SerialPort.parsers.readline("\n")
});
promises.push(ledPortOpen());
} else if (serialNum == pumpArduinoSerialNum) {
var comName = port.comName;
comName = comName.replace("cu", "tty");
// Open serial port to LED Arduino
serialPortPump = new SerialPort.SerialPort(comName, {
baudrate: serialBaud,
parser: SerialPort.parsers.readline("\n")
});
promises.push(pumpPortOpen());
}
}
}
// Requires that both Arduinos be connected, exits otherwise
if (serialPortLed == null) {
console.log(colors.red("LED Arduino not connected"));
process.exit(1);
} else if (serialPortPump == null) {
console.log(colors.red("Pump Arduino not connected"));
process.exit(1);
}
});
// Waits for both serial ports to open, then starts up the Firebase queue listener
Promise.all(promises).then(function() {
var queue = new Queue(queueRef, firebaseListener);
});