0
# Event System
1
2
Real-time event monitoring for pin state changes, board connection status, and custom SysEx messages using EventEmitter2 for comprehensive Arduino communication.
3
4
## Capabilities
5
6
### Connection Events
7
8
Events fired during Arduino connection establishment and management.
9
10
```javascript { .api }
11
// Connection event types (no parameters)
12
// arduino.on('connect', callback)
13
// arduino.on('boardReady', callback)
14
// arduino.on('boardVersion', callback)
15
```
16
17
#### Connect Event
18
19
Fired when Arduino connection is fully established and ready for I/O operations.
20
21
```javascript
22
arduino.on('connect', function() {
23
console.log("Connected to: " + arduino.serialport_name);
24
console.log("Board version: " + arduino.boardVersion);
25
26
// Arduino is now ready for I/O operations
27
arduino.digitalWrite(13, true);
28
});
29
```
30
31
#### Board Ready Event
32
33
Fired when Arduino board is detected and initialization has begun (before full connection).
34
35
```javascript
36
arduino.on('boardReady', function() {
37
console.log('Arduino board detected and initializing...');
38
// Connection will be complete when 'connect' event fires
39
});
40
```
41
42
#### Board Version Event
43
44
Fired when Arduino board firmware version information is received.
45
46
```javascript { .api }
47
// arduino.on('boardVersion', function(version) { ... })
48
// Parameters:
49
// version (string) - Board firmware version (e.g., "2.3")
50
```
51
52
```javascript
53
arduino.on('boardVersion', function(version) {
54
console.log('Arduino firmware version:', version);
55
56
// Check for minimum required version
57
const [major, minor] = version.split('.').map(Number);
58
if (major < 2 || (major === 2 && minor < 2)) {
59
console.warn('Warning: Firmata 2.2+ recommended for full functionality');
60
}
61
});
62
```
63
64
### Digital I/O Events
65
66
Real-time monitoring of digital pin state changes.
67
68
```javascript { .api }
69
// Digital change event
70
// arduino.on('digitalChange', function(event) { ... })
71
// Event object properties:
72
interface DigitalChangeEvent {
73
pin: number; // Pin number that changed (0-13+)
74
value: boolean; // New pin state (true = HIGH, false = LOW)
75
old_value: boolean; // Previous pin state
76
}
77
```
78
79
#### Digital Change Monitoring
80
81
Monitor digital pin state changes for button presses, switch states, and sensor triggers.
82
83
```javascript
84
// Set up digital input monitoring
85
arduino.pinMode(7, ArduinoFirmata.INPUT);
86
arduino.pinMode(8, ArduinoFirmata.INPUT);
87
88
arduino.on('digitalChange', function(event) {
89
console.log(`Pin ${event.pin}: ${event.old_value ? 'HIGH' : 'LOW'} → ${event.value ? 'HIGH' : 'LOW'}`);
90
91
// Button press detection (LOW to HIGH transition)
92
if (event.pin === 7 && event.value === true && event.old_value === false) {
93
console.log('Button on pin 7 pressed!');
94
arduino.digitalWrite(13, true); // Turn on LED
95
}
96
97
// Button release detection (HIGH to LOW transition)
98
if (event.pin === 7 && event.value === false && event.old_value === true) {
99
console.log('Button on pin 7 released!');
100
arduino.digitalWrite(13, false); // Turn off LED
101
}
102
});
103
```
104
105
#### Multi-pin Digital Monitoring
106
107
```javascript
108
const inputPins = [2, 3, 4, 5, 6, 7, 8];
109
110
// Configure all pins as inputs
111
inputPins.forEach(pin => {
112
arduino.pinMode(pin, ArduinoFirmata.INPUT);
113
});
114
115
// Monitor all configured pins
116
arduino.on('digitalChange', function(event) {
117
if (inputPins.includes(event.pin)) {
118
console.log(`Input pin ${event.pin} changed to ${event.value ? 'HIGH' : 'LOW'}`);
119
120
// Update status LED based on any active input
121
const anyHigh = inputPins.some(pin => arduino.digitalRead(pin));
122
arduino.digitalWrite(13, anyHigh);
123
}
124
});
125
```
126
127
### Analog I/O Events
128
129
Real-time monitoring of analog pin value changes for sensor data and continuous monitoring.
130
131
```javascript { .api }
132
// Analog change event
133
// arduino.on('analogChange', function(event) { ... })
134
// Event object properties:
135
interface AnalogChangeEvent {
136
pin: number; // Analog pin number that changed (0-5)
137
value: number; // New analog reading (0-1023)
138
old_value: number; // Previous analog reading
139
}
140
```
141
142
#### Analog Change Monitoring
143
144
Monitor analog sensors for continuous data collection and threshold-based triggers.
145
146
```javascript
147
arduino.on('analogChange', function(event) {
148
const voltage = (event.value / 1023) * 5.0;
149
console.log(`Analog pin A${event.pin}: ${event.value} (${voltage.toFixed(2)}V)`);
150
151
// Temperature sensor monitoring (pin A0)
152
if (event.pin === 0) {
153
const temperature = voltage * 100; // LM35 temperature sensor
154
console.log(`Temperature: ${temperature.toFixed(1)}°C`);
155
156
// Temperature threshold alarm
157
if (temperature > 30 && event.old_value / 1023 * 5 * 100 <= 30) {
158
console.log('High temperature alert!');
159
arduino.digitalWrite(13, true);
160
}
161
}
162
163
// Light sensor controlling LED brightness (pin A1)
164
if (event.pin === 1) {
165
const brightness = Math.round((event.value / 1023) * 255);
166
arduino.analogWrite(9, brightness);
167
console.log(`Auto-brightness: ${brightness}/255`);
168
}
169
});
170
```
171
172
#### Sensor Data Logging
173
174
```javascript
175
const sensorData = {
176
temperature: [],
177
light: [],
178
potentiometer: []
179
};
180
181
arduino.on('analogChange', function(event) {
182
const timestamp = new Date().toISOString();
183
const value = event.value;
184
185
switch(event.pin) {
186
case 0: // Temperature sensor
187
const tempC = (value / 1023 * 5) * 100;
188
sensorData.temperature.push({ timestamp, value: tempC });
189
break;
190
case 1: // Light sensor
191
const lightLevel = Math.round((value / 1023) * 100);
192
sensorData.light.push({ timestamp, value: lightLevel });
193
break;
194
case 2: // Potentiometer
195
const potValue = Math.round((value / 1023) * 100);
196
sensorData.potentiometer.push({ timestamp, value: potValue });
197
break;
198
}
199
200
// Keep only last 100 readings per sensor
201
Object.keys(sensorData).forEach(sensor => {
202
if (sensorData[sensor].length > 100) {
203
sensorData[sensor].shift();
204
}
205
});
206
});
207
208
// Function to get recent sensor averages
209
function getSensorAverage(sensor, samples = 10) {
210
const data = sensorData[sensor];
211
if (data.length === 0) return null;
212
213
const recent = data.slice(-samples);
214
const sum = recent.reduce((total, reading) => total + reading.value, 0);
215
return sum / recent.length;
216
}
217
```
218
219
### SysEx Events
220
221
Handle custom SysEx messages for extended Arduino functionality and bidirectional communication.
222
223
```javascript { .api }
224
// SysEx message event
225
// arduino.on('sysex', function(event) { ... })
226
// Event object properties:
227
interface SysexEvent {
228
command: number; // SysEx command byte (0-127)
229
data: number[]; // Array of data bytes received
230
}
231
```
232
233
#### SysEx Message Handling
234
235
Process custom SysEx messages from Arduino firmware.
236
237
```javascript
238
arduino.on('sysex', function(event) {
239
console.log(`SysEx command: 0x${event.command.toString(16)}`);
240
console.log('Data bytes:', event.data);
241
242
switch(event.command) {
243
case 0x01: // LED blink completion
244
console.log('LED blink sequence completed');
245
break;
246
247
case 0x10: // Custom sensor data
248
if (event.data.length >= 2) {
249
const sensorId = event.data[0];
250
const rawValue = event.data[1];
251
console.log(`Custom sensor ${sensorId}: ${rawValue}`);
252
}
253
break;
254
255
case 0x20: // Multi-byte data example
256
if (event.data.length >= 3) {
257
const id = event.data[0];
258
const highByte = event.data[1];
259
const lowByte = event.data[2];
260
const value = (highByte << 7) | lowByte; // Reconstruct 14-bit value
261
console.log(`14-bit value for ID ${id}: ${value}`);
262
}
263
break;
264
265
default:
266
console.log('Unknown SysEx command:', event.command);
267
}
268
});
269
```
270
271
### Event-Driven Application Example
272
273
Complete example showing event-driven Arduino control application.
274
275
```javascript
276
const ArduinoFirmata = require('arduino-firmata');
277
const arduino = new ArduinoFirmata();
278
279
// Application state
280
const appState = {
281
connected: false,
282
buttons: {},
283
sensors: {},
284
ledState: false
285
};
286
287
arduino.connect();
288
289
// Connection management
290
arduino.on('connect', function() {
291
console.log('Arduino application connected');
292
appState.connected = true;
293
294
// Setup pins
295
arduino.pinMode(7, ArduinoFirmata.INPUT); // Button
296
arduino.pinMode(13, ArduinoFirmata.OUTPUT); // Status LED
297
298
// Initial status blink
299
blinkStatusLED(3);
300
});
301
302
arduino.on('boardVersion', function(version) {
303
console.log(`Running on Arduino firmware ${version}`);
304
});
305
306
// Digital input handling
307
arduino.on('digitalChange', function(event) {
308
appState.buttons[event.pin] = {
309
state: event.value,
310
changed: Date.now()
311
};
312
313
// Button press actions
314
if (event.pin === 7 && event.value === true) {
315
console.log('Button pressed - toggling LED');
316
appState.ledState = !appState.ledState;
317
arduino.digitalWrite(13, appState.ledState);
318
}
319
});
320
321
// Analog sensor monitoring
322
arduino.on('analogChange', function(event) {
323
appState.sensors[event.pin] = {
324
value: event.value,
325
voltage: (event.value / 1023) * 5,
326
updated: Date.now()
327
};
328
329
// Auto-brightness based on light sensor
330
if (event.pin === 1) {
331
const brightness = Math.round((event.value / 1023) * 255);
332
arduino.analogWrite(9, brightness);
333
}
334
});
335
336
// Custom protocol handling
337
arduino.on('sysex', function(event) {
338
if (event.command === 0x50) { // Status request
339
// Send status response
340
const statusData = [
341
appState.ledState ? 1 : 0,
342
Object.keys(appState.buttons).length,
343
Object.keys(appState.sensors).length
344
];
345
arduino.sysex(0x51, statusData);
346
}
347
});
348
349
// Utility functions
350
function blinkStatusLED(times, interval = 200) {
351
let count = 0;
352
const blinkInterval = setInterval(function() {
353
arduino.digitalWrite(13, count % 2 === 0);
354
count++;
355
356
if (count >= times * 2) {
357
clearInterval(blinkInterval);
358
arduino.digitalWrite(13, appState.ledState);
359
}
360
}, interval);
361
}
362
363
// Periodic status reporting
364
setInterval(function() {
365
if (appState.connected) {
366
console.log('Application Status:');
367
console.log(' LED State:', appState.ledState);
368
console.log(' Active Buttons:', Object.keys(appState.buttons).length);
369
console.log(' Active Sensors:', Object.keys(appState.sensors).length);
370
}
371
}, 10000);
372
```
373
374
### Event Listener Management
375
376
Best practices for managing event listeners in long-running applications.
377
378
```javascript
379
class ArduinoController {
380
constructor() {
381
this.arduino = new ArduinoFirmata();
382
this.eventHandlers = {};
383
this.setupEventHandlers();
384
}
385
386
setupEventHandlers() {
387
// Store handlers for later cleanup
388
this.eventHandlers.connect = () => {
389
console.log('Arduino connected');
390
this.onConnect();
391
};
392
393
this.eventHandlers.digitalChange = (event) => {
394
this.handleDigitalChange(event);
395
};
396
397
this.eventHandlers.analogChange = (event) => {
398
this.handleAnalogChange(event);
399
};
400
401
this.eventHandlers.sysex = (event) => {
402
this.handleSysexMessage(event);
403
};
404
405
// Register handlers
406
this.arduino.on('connect', this.eventHandlers.connect);
407
this.arduino.on('digitalChange', this.eventHandlers.digitalChange);
408
this.arduino.on('analogChange', this.eventHandlers.analogChange);
409
this.arduino.on('sysex', this.eventHandlers.sysex);
410
}
411
412
connect() {
413
this.arduino.connect();
414
}
415
416
disconnect() {
417
// Remove event listeners before disconnecting
418
Object.keys(this.eventHandlers).forEach(event => {
419
this.arduino.removeListener(event, this.eventHandlers[event]);
420
});
421
422
this.arduino.close();
423
}
424
425
onConnect() {
426
// Override in subclass
427
}
428
429
handleDigitalChange(event) {
430
// Override in subclass
431
}
432
433
handleAnalogChange(event) {
434
// Override in subclass
435
}
436
437
handleSysexMessage(event) {
438
// Override in subclass
439
}
440
}
441
442
// Usage
443
const controller = new ArduinoController();
444
controller.connect();
445
446
// Clean shutdown
447
process.on('SIGINT', () => {
448
console.log('Shutting down...');
449
controller.disconnect();
450
process.exit(0);
451
});
452
```
453
454
## Event System Architecture
455
456
### EventEmitter2 Integration
457
458
Arduino Firmata extends EventEmitter2, providing enhanced event capabilities:
459
460
- **Wildcard events**: Listen to multiple event types with patterns
461
- **Namespaced events**: Organize events with dot notation
462
- **Event priority**: Control event handler execution order
463
- **Maximum listeners**: Configure listener limits per event
464
465
### Event Loop Considerations
466
467
Arduino events are processed in the Node.js event loop:
468
469
- Events are fired asynchronously when data arrives from Arduino
470
- Event handlers should be non-blocking for optimal performance
471
- Heavy processing should be delegated to worker threads or queued
472
473
### Performance Guidelines
474
475
1. **Keep handlers fast**: Avoid blocking operations in event handlers
476
2. **Debounce noisy signals**: Use timers for switch debouncing
477
3. **Batch operations**: Group related I/O operations together
478
4. **Remove unused listeners**: Clean up event handlers when not needed
479
5. **Monitor memory**: Check for event listener memory leaks in long-running apps
480
481
```javascript
482
// Example: Debounced button handling
483
let buttonTimeout = null;
484
485
arduino.on('digitalChange', function(event) {
486
if (event.pin === 7) { // Button pin
487
// Clear existing timeout
488
if (buttonTimeout) {
489
clearTimeout(buttonTimeout);
490
}
491
492
// Set new timeout for debouncing
493
buttonTimeout = setTimeout(() => {
494
if (arduino.digitalRead(7) === true) {
495
console.log('Debounced button press confirmed');
496
// Handle button press
497
}
498
buttonTimeout = null;
499
}, 50); // 50ms debounce
500
}
501
});
502
```