UNPKG

27.4 kBJavaScriptView Raw
1var Emitter = require("events").EventEmitter;
2var util = require("util");
3
4var Board = require("./board");
5var Fn = require("./fn");
6
7var toFixed = Fn.toFixed;
8
9var CELSIUS_TO_KELVIN = 273.15;
10
11function analogHandler(opts, dataHandler) {
12 var pin = opts.pin;
13
14 this.io.pinMode(pin, this.io.MODES.ANALOG);
15 this.io.analogRead(pin, function(data) {
16 dataHandler.call(this, data);
17 }.bind(this));
18}
19
20var activeDrivers = new Map();
21
22var Drivers = {
23 MAX31850K: {
24 initialize: {
25 value: function(board, opts) {
26 var CONSTANTS = {
27 TEMPERATURE_FAMILY: 0x3B,
28 CONVERT_TEMPERATURE_COMMAND: 0x44,
29 READ_SCRATCHPAD_COMMAND: 0xBE,
30 READ_COUNT: 9
31 },
32 pin = opts.pin,
33 freq = opts.freq || 100,
34 getAddress, readTemperature, isConversionAvailable, getAddresses, readOne;
35
36 getAddress = function(device) {
37 // 64-bit device code
38 // device[0] => Family Code
39 // device[1..6] => Serial Number (device[1] is LSB)
40 // device[7] => CRC
41 var i, result = 0;
42 for (i = 6; i > 0; i--) {
43 result = result * 256 + device[i];
44 }
45 return result;
46 };
47
48 board.io.sendOneWireConfig(pin, true);
49 board.io.sendOneWireSearch(pin, function(err, devices) {
50 if (err) {
51 this.emit("error", err);
52 return;
53 }
54
55 this.devices = devices.filter(function(device) {
56 return device[0] === CONSTANTS.TEMPERATURE_FAMILY;
57 }, this);
58
59 if (devices.length === 0) {
60 this.emit("error", new Error("FAILED TO FIND TEMPERATURE DEVICE"));
61 return;
62 }
63
64 this.devices.forEach(function(device) {
65 this.emit("initialized", getAddress(device));
66 }.bind(this));
67
68 getAddresses = function() {
69 if (this.addresses) {
70 return this.devices.filter(function(device) {
71 var address = getAddress(device);
72 return this.addresses.includes(address);
73 }, this);
74 } else {
75 return [this.devices[0]];
76 }
77 }.bind(this);
78
79 readTemperature = function() {
80 var devicesToWait, devicesToRead, result;
81
82 // request tempeature conversion
83 devicesToWait = getAddresses();
84 devicesToRead = getAddresses();
85
86 devicesToRead.forEach(function(device) {
87 board.io.sendOneWireReset(pin);
88 board.io.sendOneWireWrite(pin, device, CONSTANTS.CONVERT_TEMPERATURE_COMMAND);
89 });
90
91 isConversionAvailable = function(done) {
92 var nextDevice;
93
94 if (devicesToWait.length === 0) {
95 return done();
96 }
97
98 nextDevice = devicesToWait.pop();
99
100 board.io.sendOneWireReset(pin);
101
102 board.io.sendOneWireWriteAndRead(pin, nextDevice, CONSTANTS.READ_SCRATCHPAD_COMMAND, CONSTANTS.READ_COUNT, function(err, data) {
103 if (!data[0]) {
104 devicesToWait.push(nextDevice);
105
106 if (data[1] !== 0) { //*****checks if second data bit is 0, if not its an error and gets thrown out
107 return done();
108 }
109 }
110
111 isConversionAvailable(done);
112 });
113 }.bind(this);
114
115 readOne = function() {
116 var device;
117
118 if (devicesToRead.length === 0) {
119 setTimeout(readTemperature, freq);
120 return;
121 }
122
123 device = devicesToRead.pop();
124 // read from the scratchpad
125 board.io.sendOneWireReset(pin);
126
127 board.io.sendOneWireWriteAndRead(pin, device, CONSTANTS.READ_SCRATCHPAD_COMMAND, CONSTANTS.READ_COUNT, function(err, data) {
128 if (err) {
129 this.emit("error", err);
130 return;
131 }
132
133 result = (data[1] << 8) | data[0];
134 this.emit("data", getAddress(device), result);
135
136 readOne();
137 }.bind(this));
138 }.bind(this);
139
140 isConversionAvailable(readOne);
141 }.bind(this);
142
143 readTemperature();
144 }.bind(this));
145 }
146 },
147 register: {
148 value: function(address) {
149 if (!this.addresses) {
150 this.addresses = [];
151 }
152
153 this.addresses.push(address);
154 }
155 }
156 },
157 DS18B20: {
158 initialize: {
159 value: function(board, opts) {
160 var CONSTANTS = {
161 TEMPERATURE_FAMILY: 0x28,
162 CONVERT_TEMPERATURE_COMMAND: 0x44,
163 READ_SCRATCHPAD_COMMAND: 0xBE,
164 READ_COUNT: 2
165 },
166 pin = opts.pin,
167 freq = opts.freq || 100,
168 getAddress, readThermometer, readOne;
169
170 getAddress = function(device) {
171 // 64-bit device code
172 // device[0] => Family Code
173 // device[1..6] => Serial Number (device[1] is LSB)
174 // device[7] => CRC
175 var i, result = 0;
176 for (i = 6; i > 0; i--) {
177 result = result * 256 + device[i];
178 }
179 return result;
180 };
181
182 board.io.sendOneWireConfig(pin, true);
183 board.io.sendOneWireSearch(pin, function(err, devices) {
184 if (err) {
185 this.emit("error", err);
186 return;
187 }
188
189 this.devices = devices.filter(function(device) {
190 return device[0] === CONSTANTS.TEMPERATURE_FAMILY;
191 }, this);
192
193 if (devices.length === 0) {
194 this.emit("error", new Error("FAILED TO FIND TEMPERATURE DEVICE"));
195 return;
196 }
197
198 this.devices.forEach(function(device) {
199 this.emit("initialized", getAddress(device));
200 }.bind(this));
201
202 readThermometer = function() {
203 var devicesToRead, result;
204
205 // request tempeature conversion
206 if (this.addresses) {
207 devicesToRead = this.devices.filter(function(device) {
208 var address = getAddress(device);
209 return this.addresses.includes(address);
210 }, this);
211 } else {
212 devicesToRead = [this.devices[0]];
213 }
214
215 devicesToRead.forEach(function(device) {
216 board.io.sendOneWireReset(pin);
217 board.io.sendOneWireWrite(pin, device, CONSTANTS.CONVERT_TEMPERATURE_COMMAND);
218 });
219
220 // the delay gives the sensor time to do the calculation
221 board.io.sendOneWireDelay(pin, 1);
222
223 readOne = function() {
224 var device;
225
226 if (devicesToRead.length === 0) {
227 setTimeout(readThermometer, freq);
228 return;
229 }
230
231 device = devicesToRead.pop();
232 // read from the scratchpad
233 board.io.sendOneWireReset(pin);
234
235 board.io.sendOneWireWriteAndRead(pin, device, CONSTANTS.READ_SCRATCHPAD_COMMAND, CONSTANTS.READ_COUNT, function(err, data) {
236 if (err) {
237 this.emit("error", err);
238 return;
239 }
240
241 result = (data[1] << 8) | data[0];
242 this.emit("data", getAddress(device), result);
243
244 readOne();
245 }.bind(this));
246 }.bind(this);
247
248 readOne();
249 }.bind(this);
250
251 readThermometer();
252 }.bind(this));
253 }
254 },
255 register: {
256 value: function(address) {
257 if (!this.addresses) {
258 this.addresses = [];
259 }
260
261 this.addresses.push(address);
262 }
263 }
264 }
265};
266
267Drivers.get = function(board, driverName, opts) {
268 var drivers, driver;
269
270 if (!activeDrivers.has(board)) {
271 activeDrivers.set(board, {});
272 }
273
274 drivers = activeDrivers.get(board);
275
276 var key = driverName + "_" + opts.pin;
277
278 if (!drivers[key]) {
279 driver = new Emitter();
280 Object.defineProperties(driver, Drivers[driverName]);
281 driver.initialize(board, opts);
282 drivers[key] = driver;
283 }
284
285 return drivers[key];
286};
287
288Drivers.clear = function() {
289 activeDrivers.clear();
290};
291
292// References
293//
294var Controllers = {
295 // Generic thermistors. See datasheet for each device.
296 ANALOG: {
297 initialize: {
298 value: analogHandler
299 }
300 },
301
302 LM35: {
303 initialize: {
304 value: analogHandler
305 },
306 toCelsius: {
307 value: function(raw) {
308 // VOUT = 1500 mV at 150°C
309 // VOUT = 250 mV at 25°C
310 // VOUT = –550 mV at –55°C
311
312 var mV = this.aref * 1000 * raw / 1023;
313
314 // 10mV = 1°C
315 //
316 // Page 1
317 return Math.round(mV / 10);
318 }
319 }
320 },
321
322 LM335: {
323 initialize: {
324 value: analogHandler
325 },
326 toCelsius: {
327 value: function(raw) {
328 // OUTPUT 10mV/°K
329
330 var mV = this.aref * 1000 * raw / 1023;
331
332 // Page 1
333 return Math.round((mV / 10) - CELSIUS_TO_KELVIN);
334 }
335 }
336 },
337
338 TMP36: {
339 initialize: {
340 value: analogHandler
341 },
342 toCelsius: {
343 value: function(raw) {
344 // Analog Reference Voltage
345 var mV = this.aref * 1000 * raw / 1023;
346
347 // tempC = (mV / 10) - 50
348 //
349 // Page 3
350 // Table 1
351 // Accuracy 1°C
352 return Math.round((mV / 10) - 50);
353 }
354 }
355 },
356
357 TMP102: {
358 ADDRESSES: {
359 value: [0x48]
360 },
361 initialize: {
362 value: function(opts, dataHandler) {
363 var address = opts.address || this.ADDRESSES[0];
364
365 opts.address = address;
366
367 this.io.i2cConfig(opts);
368
369 // Addressing is unclear.
370
371 this.io.i2cRead(address, 0x00, 2, function(data) {
372 // Based on the example code from https://www.sparkfun.com/products/11931
373 var raw = ((data[0] << 8) | data[1]) >> 4;
374
375 // The tmp102 does twos compliment but has the negative bit in the wrong spot, so test for it and correct if needed
376 if (raw & (1 << 11)) {
377 raw |= 0xF800; // Set bits 11 to 15 to 1s to get this reading into real twos compliment
378 }
379
380 // twos compliment
381 raw = raw >> 15 ? ((raw ^ 0xFFFF) + 1) * -1 : raw;
382
383 dataHandler(raw);
384 });
385 }
386 },
387 toCelsius: {
388 value: function(raw) {
389 // 6.5 Electrical Characteristics
390 // –25°C to 85°C ±0.5
391 return toFixed(raw / 16, 1);
392 }
393 },
394 },
395
396 MAX31850K: {
397 initialize: {
398 value: function(opts, dataHandler) {
399 var state = priv.get(this),
400 address = opts.address,
401 driver = Drivers.get(this.board, "MAX31850K", opts);
402
403 if (address) {
404 state.address = address;
405 driver.register(address);
406 } else {
407 if (driver.addressless) {
408 this.emit("error", "You cannot have more than one MAX31850K without an address");
409 }
410 driver.addressless = true;
411 }
412
413 driver.once("initialized", function(dataAddress) {
414 if (!state.address) {
415 state.address = dataAddress;
416 }
417 });
418
419 driver.on("data", function(dataAddress, data) {
420 if (!address || dataAddress === address) {
421 dataHandler(data);
422 }
423 }.bind(this));
424 }
425 },
426 toCelsius: {
427 // Page 4
428 // Thermocouple Temperature Data Resolution
429 value: function(raw) {
430 return toFixed(raw / 16, 2);
431 }
432 },
433 address: {
434 get: function() {
435 return priv.get(this).address || 0x00;
436 }
437 }
438 },
439
440 // Based on code from Westin Pigott:
441 // https://github.com/westinpigott/one-wire-temps
442 // And the datasheet:
443 // OneWire protocol. The device needs to be issued a "Convert Temperature"
444 // command which can take up to 10 microseconds to compute, so we need
445 // tell the board to delay 1 millisecond before issuing the "Read Scratchpad" command
446 //
447 // This device requires the OneWire support enabled via ConfigurableFirmata
448 DS18B20: {
449 initialize: {
450 value: function(opts, dataHandler) {
451 var state = priv.get(this),
452 address = opts.address,
453 driver = Drivers.get(this.board, "DS18B20", opts);
454
455 if (address) {
456 state.address = address;
457 driver.register(address);
458 } else {
459 if (driver.addressless) {
460 this.emit("error", "You cannot have more than one DS18B20 without an address");
461 }
462 driver.addressless = true;
463 }
464
465 driver.once("initialized", function(dataAddress) {
466 if (!state.address) {
467 state.address = dataAddress;
468 }
469 });
470
471 driver.on("data", function(dataAddress, data) {
472 if (!address || dataAddress === address) {
473 dataHandler(data);
474 }
475 });
476 }
477 },
478 toCelsius: {
479 value: function(raw) {
480 // ±0.5°C accuracy from -10°C to +85°C
481 //
482 // Temp resolution is as follows:
483 // 9b, 10b 11b, 12b
484 // 0.5°C, 0.25°C, 0.125°C, 0.0625°C
485 //
486 // I'm not sure which we're reading, so default to 4
487 // fractional digits until we can verify
488 return toFixed(raw / 16, 4);
489 }
490 },
491 address: {
492 get: function() {
493 return priv.get(this).address || 0x00;
494 }
495 }
496 },
497
498
499 SHT31D: {
500 initialize: {
501 value: function(opts, dataHandler) {
502 var Multi = require("./imu");
503 var driver = Multi.Drivers.get(this.board, "SHT31D", opts);
504 driver.on("data", function(data) {
505 dataHandler(data.temperature);
506 });
507 }
508 },
509 toCelsius: {
510 value: function(raw) {
511 // Page 4, Table 1.2 Temperature Sensor Performance
512 // Resolution: 0.015
513 //
514 // Page 14
515 // 4.13 Conversion of Signal Output
516 // T[C] = -45 + 175 * (St / ((2 ** 26) - 1))
517 // St = Sensor raw temperature
518 return toFixed((175 * raw / 65535) - 45, 3);
519 }
520 }
521 },
522
523 HTU21D: {
524 initialize: {
525 value: function(opts, dataHandler) {
526 var Multi = require("./imu");
527 var driver = Multi.Drivers.get(this.board, "HTU21D", opts);
528 driver.on("data", function(data) {
529 dataHandler(data.temperature);
530 });
531 }
532 },
533 toCelsius: {
534 value: function(raw) {
535 // Page 5
536 // Digital Relative Humidity sensor with Temperature output
537 // Resolution shows 0.01-0.04
538 //
539 // Page 15
540 // CONVERSION OF SIGNAL OUTPUTS
541 // T = -46.85 + 175.72 * (Stemp / (2 ** 16))
542 // Stemp = Sensor raw temperature
543 return toFixed((175.72 * raw / 65536) - 46.85, 2);
544 }
545 }
546 },
547 HIH6130: {
548 initialize: {
549 value: function(opts, dataHandler) {
550 var Multi = require("./imu");
551 var driver = Multi.Drivers.get(this.board, "HIH6130", opts);
552 driver.on("data", function(data) {
553 dataHandler(data.temperature);
554 });
555 }
556 },
557 toCelsius: {
558 value: function(raw) {
559 // Page 3
560 // 5.0 Calculation of Optional Temperature
561 // from the Digital Output
562 //
563 // -40 C = 0
564 // 125 C = 2 ** 14 - 1
565 return Math.round(raw / 1000);
566 }
567 }
568 },
569
570 DHT_I2C_NANO_BACKPACK: {
571 initialize: {
572 value: function(opts, dataHandler) {
573 var Multi = require("./imu");
574 var driver = Multi.Drivers.get(this.board, "DHT_I2C_NANO_BACKPACK", opts);
575 driver.on("data", function(data) {
576 dataHandler(data.temperature);
577 });
578 }
579 },
580 toCelsius: {
581 value: function(raw) {
582 // Page 2
583 // 5. Product parameters
584 // Range: ... ±2°C
585 return Math.round(raw / 100);
586 }
587 }
588 },
589
590 TH02: {
591 initialize: {
592 value: function(opts, dataHandler) {
593 var Multi = require("./imu");
594 var driver = Multi.Drivers.get(this.board, "TH02", opts);
595 driver.on("data", function(data) {
596 dataHandler(data.temperature);
597 });
598 }
599 },
600 toCelsius: {
601 value: function(raw) {
602 // Page 8, Table 5
603 // Temperature Sensor
604 // Accuracy Typical at 25 °C — ±0.5 ±1.0 °C
605 return toFixed(raw, 1);
606 }
607 }
608 },
609
610 MPU6050: {
611 initialize: {
612 value: function(opts, dataHandler) {
613 var IMU = require("./imu");
614 var driver = IMU.Drivers.get(this.board, "MPU6050", opts);
615 driver.on("data", function(data) {
616 dataHandler(data.temperature);
617 });
618 }
619 },
620 toCelsius: {
621 value: function(raw) {
622 // No sub-degree/fractional parts illustrated in datasheet
623 return Math.round((raw / 340.00) + 36.53);
624 }
625 }
626 },
627
628 BNO055: {
629 initialize: {
630 value: function(opts, dataHandler) {
631 var IMU = require("./imu");
632 var driver = IMU.Drivers.get(this.board, "BNO055", opts);
633 driver.on("data", function(data) {
634 dataHandler(data.temperature);
635 });
636 }
637 },
638 toCelsius: {
639 value: function(raw) {
640 // Page 37, Table 3-37
641 // Temperature data representation
642 // 1°C = 1 LSB
643 // raw is already C
644 return Math.trunc(raw);
645 }
646 }
647 },
648
649 MPL115A2: {
650 initialize: {
651 value: function(opts, dataHandler) {
652 var Multi = require("./imu");
653 var driver = Multi.Drivers.get(this.board, "MPL115A2", opts);
654 driver.on("data", function(data) {
655 dataHandler(data.temperature);
656 });
657 }
658 },
659 toCelsius: {
660 value: function(raw) {
661 // No description, so removing fractional parts
662 return Math.trunc((raw - 498) / -5.35 + 25);
663 }
664 }
665 },
666
667 MPL3115A2: {
668 initialize: {
669 value: function(opts, dataHandler) {
670 var Multi = require("./imu");
671 var driver = Multi.Drivers.get(this.board, "MPL3115A2", opts);
672 driver.on("data", function(data) {
673 dataHandler(data.temperature);
674 });
675 }
676 },
677 toCelsius: {
678 value: function(raw) {
679 // Page 5
680 // Table 2 Mechanical Characteristics
681 // Accuracy @ 25 °C ±1°C
682 return Math.round(raw / 16);
683 }
684 }
685 },
686
687 MS5611: {
688 initialize: {
689 value: function(opts, dataHandler) {
690 var Multi = require("./imu");
691 var driver = Multi.Drivers.get(this.board, "MS5611", opts);
692 driver.on("data", function(data) {
693 dataHandler(data.temperature);
694 });
695 }
696 },
697 toCelsius: {
698 value: function(raw) {
699 // Page 1
700 // TECHNICAL DATA
701 // Resolution <0.01 °C
702 return toFixed(raw, 2);
703 }
704 }
705 },
706
707 GROVE: {
708 initialize: {
709 value: analogHandler
710 },
711 toCelsius: {
712 value: function(raw) {
713 // http://www.seeedstudio.com/wiki/Grove_-_Temperature_Sensor
714 var adcres = 1023;
715 // Beta parameter
716 var beta = 3975;
717 // 10 kOhm (sensor resistance)
718 var rb = 10000;
719 // Ginf = 1/Rinf
720 // var ginf = 120.6685;
721 // Reference Temperature 25°C
722 var tempr = 298.15;
723
724 var rthermistor = (adcres - raw) * rb / raw;
725 var tempc = 1 / (Math.log(rthermistor / rb) / beta + 1 / tempr) - CELSIUS_TO_KELVIN;
726
727 return Math.round(tempc);
728 }
729 }
730 },
731
732 // MF52A103J3470
733 TINKERKIT: {
734 initialize: {
735 value: analogHandler
736 },
737 toCelsius: {
738 value: function(raw) {
739 var adcres = 1023;
740 var beta = 3950;
741 var rb = 10000; // 10 kOhm
742 var ginf = 120.6685; // Ginf = 1/Rinf
743
744 var rthermistor = rb * (adcres / raw - 1);
745 var tempc = beta / (Math.log(rthermistor * ginf));
746
747 return Math.round(tempc - CELSIUS_TO_KELVIN);
748 }
749 }
750 },
751
752 BMP180: {
753 initialize: {
754 value: function(opts, dataHandler) {
755 var Multi = require("./imu");
756 var driver = Multi.Drivers.get(this.board, "BMP180", opts);
757 driver.on("data", function(data) {
758 dataHandler(data.temperature);
759 });
760 }
761 },
762 toCelsius: {
763 value: function(raw) {
764 // Page 6, Table 1
765 // Operating conditions, output signal and mechanical characteristics
766 //
767 // Resolution of output data
768 // pressure 0.01 hPa
769 // temperature 0.1 °C
770 return toFixed(raw, 1);
771 }
772 }
773 },
774
775 BMP280: {
776 initialize: {
777 value: function(opts, dataHandler) {
778 var Multi = require("./imu");
779 var driver = Multi.Drivers.get(this.board, "BMP280", opts);
780 driver.on("data", function(data) {
781 dataHandler(data.temperature);
782 });
783 }
784 },
785 toCelsius: {
786 value: function(raw) {
787 // Page 8
788 //
789 // Resolution of output data in ultra high resolution mode*
790 // Pressure 0.0016 hPa
791 // Temperature 0.01 °C
792 //
793 // * resolution mode is currently not configurable.
794 //
795 return toFixed(raw, 2);
796 }
797 }
798 },
799
800 BME280: {
801 initialize: {
802 value: function(opts, dataHandler) {
803 var Multi = require("./imu");
804 var driver = Multi.Drivers.get(this.board, "BME280", opts);
805 driver.on("data", function(data) {
806 dataHandler(data.temperature);
807 });
808 }
809 },
810 toCelsius: {
811 value: function(raw) {
812 // Page 23
813 // Resolution is 0.01 DegC.
814 return toFixed(raw, 2);
815 }
816 }
817 },
818
819 SI7020: {
820 initialize: {
821 value: function(opts, dataHandler) {
822 var Multi = require("./imu");
823 var driver = Multi.Drivers.get(this.board, "SI7020", opts);
824 driver.on("data", function(data) {
825 dataHandler(data.temperature);
826 });
827 }
828 },
829 toCelsius: {
830 value: function(raw) {
831 // Page 9, Table 5. Temperature Sensor
832 // Accuracy1 –10 °C< tA < 85 °C — ±0.3 ±0.4 °C
833 //
834 // Page 23
835 // (See temperature conversion expression)
836 return toFixed((175.72 * raw / 65536) - 46.85, 1);
837 }
838 }
839 },
840
841 MCP9808: {
842 ADDRESSES: {
843 value: [0x18]
844 },
845 initialize: {
846 value: function(opts, dataHandler) {
847 var address = opts.address || this.ADDRESSES[0];
848
849 opts.address = address;
850
851 this.io.i2cConfig(opts);
852 // Page 17
853 // Register 0x05 = Ta (Temp, Ambient)
854 this.io.i2cRead(address, 0x05, 2, function(data) {
855 // Page 24
856 // 5.1.3 AMBIENT TEMPERATURE REGISTER (TA)
857 var raw = (data[0] << 8) | data[1];
858
859 // Page 25
860 raw = (raw & 0x0FFF) / 16;
861
862 if (raw & 0x1000) {
863 raw -= 256;
864 }
865 dataHandler(raw);
866 });
867 }
868 },
869 toCelsius: {
870 value: function(raw) {
871 // Page 1
872 // Microchip Technology Inc.s MCP9808 digital
873 // temperature sensor converts temperatures between
874 // -20°C and +100°C to a digital word with
875 // ±0.25°C/±0.5°C (typical/maximum) accuracy.
876 return toFixed(raw, 2);
877 }
878 },
879 },
880
881 LSM303C: {
882 initialize: {
883 value: function(opts, dataHandler) {
884 var Multi = require("./imu");
885 var driver = Multi.Drivers.get(this.board, "LSM303C", opts);
886 driver.on("data", function(data) {
887 dataHandler(data.temperature);
888 });
889 }
890 },
891 toCelsius: {
892 value: function(raw) {
893 // int16 resolution, 8 bits per C, 0 = 25 C
894 return toFixed((raw / 8) + 25, 1);
895 }
896 }
897 },
898};
899
900Controllers.BMP085 = Controllers.BMP180;
901Controllers.GY521 = Controllers.MPU6050;
902Controllers.SI7021 = Controllers.SI7020;
903Controllers.DHT11_I2C_NANO_BACKPACK = Controllers.DHT_I2C_NANO_BACKPACK;
904Controllers.DHT21_I2C_NANO_BACKPACK = Controllers.DHT_I2C_NANO_BACKPACK;
905Controllers.DHT22_I2C_NANO_BACKPACK = Controllers.DHT_I2C_NANO_BACKPACK;
906
907
908var priv = new Map();
909
910function Thermometer(opts) {
911
912 if (!(this instanceof Thermometer)) {
913 return new Thermometer(opts);
914 }
915
916 var controller = null;
917 var last = null;
918 var raw = null;
919
920 Board.Component.call(
921 this, opts = Board.Options(opts)
922 );
923
924 // Analog Reference Voltage (default to board.io.aref || 5)
925 this.aref = opts.aref || this.io.aref || 5;
926
927 if (opts.controller && typeof opts.controller === "string") {
928 controller = Controllers[opts.controller.toUpperCase()];
929 } else {
930 controller = opts.controller;
931 }
932
933 if (controller == null) {
934 controller = Controllers.ANALOG;
935 }
936
937 var state = {
938 enabled: typeof opts.enabled === "undefined" ? true : opts.enabled,
939 intervalId: null,
940 freq: opts.freq || 25,
941 previousFreq: opts.freq || 25,
942 };
943 priv.set(this, state);
944
945 Board.Controller.call(this, controller, opts);
946
947 if (!this.toCelsius) {
948 this.toCelsius = opts.toCelsius || function(x) {
949 return x;
950 };
951 }
952
953 // TODO: Move this out of the constructor
954 var eventProcessing = function() {
955 if (raw == null) {
956 return;
957 }
958
959 var data = {};
960 data.C = data.celsius = this.celsius;
961 data.F = data.fahrenheit = this.fahrenheit;
962 data.K = data.kelvin = this.kelvin;
963
964 this.emit("data", data);
965
966 if (this.celsius !== last) {
967 last = this.celsius;
968 this.emit("change", data);
969 }
970 }.bind(this);
971
972 var descriptors = {
973 celsius: {
974 get: function() {
975 return this.toCelsius(raw);
976 }
977 },
978 fahrenheit: {
979 get: function() {
980 return toFixed((this.celsius * 9 / 5) + 32, 2);
981 }
982 },
983 kelvin: {
984 get: function() {
985 return toFixed(this.celsius + CELSIUS_TO_KELVIN, 2);
986 }
987 },
988 freq: {
989 get: function() {
990 return state.freq;
991 },
992 set: function(newFreq) {
993 state.freq = newFreq;
994 if (state.intervalId) {
995 clearInterval(state.intervalId);
996 }
997
998 if (state.freq !== null) {
999 state.intervalId = setInterval(eventProcessing, newFreq);
1000 }
1001 }
1002 },
1003 };
1004 // Convenience aliases
1005 descriptors.C = descriptors.celsius;
1006 descriptors.F = descriptors.fahrenheit;
1007 descriptors.K = descriptors.kelvin;
1008
1009 Object.defineProperties(this, descriptors);
1010
1011 if (typeof this.initialize === "function") {
1012 this.initialize(opts, function(data) {
1013 raw = data;
1014 });
1015 }
1016
1017 // Set the freq property only after the get and set functions are defined
1018 // and only if the sensor is not `enabled: false`
1019 if (state.enabled) {
1020 this.freq = state.freq;
1021 }
1022}
1023
1024util.inherits(Thermometer, Emitter);
1025
1026/**
1027 * enable Enable a disabled thermometer.
1028 *
1029 * @return {Object} instance
1030 *
1031 */
1032Thermometer.prototype.enable = function() {
1033 var state = priv.get(this);
1034
1035 /* istanbul ignore else */
1036 if (!state.enabled) {
1037 this.freq = state.freq || state.previousFreq;
1038 }
1039
1040 return this;
1041};
1042
1043/**
1044 * disable Disable an enabled thermometer.
1045 *
1046 * @return {Object} instance
1047 *
1048 */
1049Thermometer.prototype.disable = function() {
1050 var state = priv.get(this);
1051
1052 /* istanbul ignore else */
1053 if (state.enabled) {
1054 state.enabled = false;
1055 state.previousFreq = state.freq;
1056 this.freq = null;
1057 }
1058
1059 return this;
1060};
1061
1062Thermometer.Drivers = Drivers;
1063
1064/* istanbul ignore else */
1065if (!!process.env.IS_TEST_MODE) {
1066 Thermometer.Controllers = Controllers;
1067 Thermometer.purge = function() {
1068 priv.clear();
1069 };
1070}
1071
1072module.exports = Thermometer;