or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analog-io.mdconnection.mddigital-io.mdevents.mdindex.mdservo.mdsysex.md

events.mddocs/

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

```