forked from demirhanaydin/node-mi-flora
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
122 lines (109 loc) · 4.04 KB
/
index.js
File metadata and controls
122 lines (109 loc) · 4.04 KB
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
const EventEmitter = require('events');
const noble = require('noble');
const debug = require('debug')('miflora');
const DeviceData = require('./lib/device-data');
const DEFAULT_DEVICE_NAME = 'Flower mate';
const DATA_SERVICE_UUID = '0000120400001000800000805f9b34fb';
const DATA_CHARACTERISTIC_UUID = '00001a0100001000800000805f9b34fb';
const FIRMWARE_CHARACTERISTIC_UUID = '00001a0200001000800000805f9b34fb';
const REALTIME_CHARACTERISTIC_UUID = '00001a0000001000800000805f9b34fb';
const REALTIME_META_VALUE = Buffer.from([0xA0, 0x1F]);
const SERVICE_UUIDS = [DATA_SERVICE_UUID];
const CHARACTERISTIC_UUIDS = [DATA_CHARACTERISTIC_UUID, FIRMWARE_CHARACTERISTIC_UUID, REALTIME_CHARACTERISTIC_UUID];
class MiFlora extends EventEmitter {
constructor(macAddress) {
super();
this.noble = noble;
this._macAddress = macAddress;
noble.on('discover', this.discover.bind(this));
}
discover(peripheral) {
debug('device discovered: ', peripheral.advertisement.localName);
if (this._macAddress !== undefined) {
if (this._macAddress.toLowerCase() === peripheral.address.toLowerCase()) {
debug('trying to connect mi flora, living at %s', this._macAddress);
// start listening the specific device
this.connectDevice(peripheral);
}
} else if (peripheral.advertisement.localName === DEFAULT_DEVICE_NAME) {
debug('no mac address specified, trying to connect available mi flora...');
// start listening found device
this.connectDevice(peripheral);
}
}
connectDevice(peripheral) {
// prevent simultanious connection to the same device
if (peripheral.state === 'disconnected') {
peripheral.connect();
peripheral.once('connect', function () {
this.listenDevice(peripheral, this);
}.bind(this));
}
}
listenDevice(peripheral, context) {
peripheral.discoverSomeServicesAndCharacteristics(SERVICE_UUIDS, CHARACTERISTIC_UUIDS, function (error, services, characteristics) {
characteristics.forEach(function (characteristic) {
switch (characteristic.uuid) {
case DATA_CHARACTERISTIC_UUID:
characteristic.read(function (error, data) {
context.parseData(peripheral, data);
});
break;
case FIRMWARE_CHARACTERISTIC_UUID:
characteristic.read(function (error, data) {
context.parseFirmwareData(peripheral, data);
});
break;
case REALTIME_CHARACTERISTIC_UUID:
debug('enabling realtime');
characteristic.write(REALTIME_META_VALUE, true);
break;
default:
debug('found characteristic uuid %s but not matched the criteria', characteristic.uuid);
}
});
});
}
parseData(peripheral, data) {
debug('data:', data);
let temperature = data.readUInt16LE(0) / 10;
let lux = data.readUInt32LE(3);
let moisture = data.readUInt16BE(6);
let fertility = data.readUInt16LE(8);
let deviceData = new DeviceData(peripheral.id,
temperature,
lux,
moisture,
fertility);
debug('temperature: %s °C', temperature);
debug('Light: %s lux', lux);
debug('moisture: %s %', moisture);
debug('fertility: %s µS/cm', fertility);
this.emit('data', deviceData);
}
parseFirmwareData(peripheral, data) {
debug('firmware data:', data);
let firmware = {
deviceId: peripheral.id,
batteryLevel: parseInt(data.toString('hex', 0, 1), 16),
firmwareVersion: data.toString('ascii', 2, data.length)
};
this.emit('firmware', firmware);
}
startScanning() {
if (noble.state === 'poweredOn') {
noble.startScanning([], true);
} else {
// bind event to start scanning
noble.on('stateChange', function (state) {
if (state === 'poweredOn') {
noble.startScanning([], true);
}
});
}
}
stopScanning() {
noble.stopScanning();
}
}
module.exports = MiFlora;