Skip to content

Commit fe1605b

Browse files
author
Chris
committed
- added blink() and reset() methods to device
- added fix for empty addresses on discovery - changed noble links to abandonware
1 parent c318604 commit fe1605b

File tree

4 files changed

+80
-27
lines changed

4 files changed

+80
-27
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# miflora
22

3-
Node.js package for the Xiaomi Mi Flora Plant Sensor built on top of [noble](https://github.com/noble/noble).
3+
Node.js package for the Xiaomi Mi Flora Plant Sensor built on top of [noble](https://github.com/abandonware/noble) (maintained by [abandonware](https://abandonware.github.io/)).
44

55
[![npm](https://img.shields.io/npm/v/miflora.svg)](https://www.npmjs.com/package/miflora)
66
![language](https://img.shields.io/github/languages/top/ChrisScheffler/miflora.svg)
77
[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo)
88
![commit](https://img.shields.io/github/last-commit/ChrisScheffler/miflora.svg)
9-
![firmware](https://img.shields.io/badge/firmware-3.1.9-brightgreen.svg)
9+
![firmware](https://img.shields.io/badge/firmware-3.2.1-brightgreen.svg)
1010
[![licence](https://img.shields.io/npm/l/miflora.svg)](LICENSE)
1111

1212
Have a look in the [Wiki](https://github.com/ChrisScheffler/miflora/wiki) for more information on the sensor.
@@ -15,7 +15,7 @@ Have a look in the [Wiki](https://github.com/ChrisScheffler/miflora/wiki) for mo
1515

1616
## Prerequisites
1717

18-
Please see [the Prerequisites section for noble](https://github.com/noble/noble#prerequisites).
18+
Please see [the Prerequisites section for noble](https://github.com/abandonware/noble#prerequisites).
1919

2020
## Install
2121

lib/miflora-device.js

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,6 @@
22

33
const debug = require('debug');
44

5-
const UUID_SERVICE_XIAOMI = 'fe95';
6-
const UUID_SERVICE_DATA = '0000120400001000800000805f9b34fb';
7-
const UUID_CHARACTERISTIC_MODE = '00001a0000001000800000805f9b34fb';
8-
const UUID_CHARACTERISTIC_DATA = '00001a0100001000800000805f9b34fb';
9-
const UUID_CHARACTERISTIC_FIRMWARE = '00001a0200001000800000805f9b34fb';
10-
11-
const MODE_BUFFER_SERIAL = Buffer.from('b0ff', 'hex');
12-
const MODE_BUFFER_REALTIME = {
13-
Enable: Buffer.from('a01f', 'hex'),
14-
Disable: Buffer.from('c01f', 'hex')
15-
};
16-
175
const timeout = (timeout, promiseFuncs) => {
186
const promises = [new Promise(promiseFuncs)];
197
if (timeout > 0) {
@@ -29,6 +17,20 @@ const timeout = (timeout, promiseFuncs) => {
2917
return Promise.race(promises);
3018
};
3119

20+
const UUID_SERVICE_XIAOMI = 'fe95';
21+
const UUID_SERVICE_DATA = '0000120400001000800000805f9b34fb';
22+
const UUID_CHARACTERISTIC_MODE = '00001a0000001000800000805f9b34fb';
23+
const UUID_CHARACTERISTIC_DATA = '00001a0100001000800000805f9b34fb';
24+
const UUID_CHARACTERISTIC_FIRMWARE = '00001a0200001000800000805f9b34fb';
25+
26+
const MODE_BUFFER_SERIAL = Buffer.from('b0ff', 'hex');
27+
const MODE_BUFFER_BLINK = Buffer.from('fdff', 'hex');
28+
const MODE_BUFFER_RESET = Buffer.from('d0aa', 'hex');
29+
const MODE_BUFFER_REALTIME = {
30+
Enable: Buffer.from('a01f', 'hex'),
31+
Disable: Buffer.from('c01f', 'hex')
32+
};
33+
3234
/**
3335
* Represents a Mi Flora device
3436
* @public
@@ -80,11 +82,13 @@ class MiFloraDevice {
8082
connect() {
8183
return timeout(10000, (resolve, reject) => {
8284
if (this._peripheral.state === 'connected') {
85+
this.logDebug('already connected');
8386
return resolve();
8487
}
8588

8689
this._peripheral.once('connect', async () => {
8790
try {
91+
this.logDebug('connected, resolving chars');
8892
await this._resolveCharacteristics();
8993
return resolve();
9094
} catch (error) {
@@ -192,6 +196,32 @@ class MiFloraDevice {
192196
});
193197
}
194198

199+
blink() {
200+
return timeout(10000, async (resolve, reject) => {
201+
this.logDebug('requesting device to blink');
202+
try {
203+
await this.connect();
204+
this._setDeviceMode(MODE_BUFFER_BLINK);
205+
return resolve();
206+
} catch (error) {
207+
return reject();
208+
}
209+
});
210+
}
211+
212+
reset() {
213+
return timeout(10000, async (resolve, reject) => {
214+
this.logDebug('requesting device to forget setting');
215+
try {
216+
await this.connect();
217+
this._setDeviceMode(MODE_BUFFER_RESET);
218+
return resolve();
219+
} catch (error) {
220+
return reject();
221+
}
222+
});
223+
}
224+
195225
/**
196226
* @private
197227
* @param {ByteBuffer} buffer Bytes to write
@@ -230,7 +260,7 @@ class MiFloraDevice {
230260
}
231261

232262
_resolveCharacteristics() {
233-
return timeout(10004, async (resolve, reject) => {
263+
return timeout(10000, async (resolve, reject) => {
234264
try {
235265
this.logDebug('resolving characteristic');
236266
this._peripheral.discoverAllServicesAndCharacteristics((error, services, characteristics) => {
@@ -303,9 +333,9 @@ class MiFloraDevice {
303333
if (dataItem) {
304334
const productId = dataItem.data.readUInt16LE(2);
305335
switch (productId) {
306-
case 152:
336+
case 0x98:
307337
return new MiFloraDevice(peripheral, 'MiFloraMonitor');
308-
case 349:
338+
case 0x015D:
309339
return new MiFloraDevice(peripheral, 'MiFloraPot');
310340
default:
311341
}

lib/miflora.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22

33
const noble = require('@abandonware/noble');
44
const logDebug = require('debug')('miflora');
5-
const MiFloraDevice = require('./miflora-device.js');
6-
7-
const UUID_SERVICE_XIAOMI = 'fe95';
5+
const MiFloraDevice = require('./miflora-device');
86

97
const getOpt = (options, value, def) => {
108
return (options && typeof options[value] !== 'undefined') ? options[value] : def;
119
};
1210

11+
const intToHex = num => {
12+
const res = num.toString(16);
13+
return (res.length % 2 === 1) ? '0' + res : res;
14+
};
15+
16+
const UUID_SERVICE_XIAOMI = 'fe95';
17+
1318
class MiFlora {
1419
constructor() {
1520
this._devices = {};
@@ -68,7 +73,7 @@ class MiFlora {
6873
* @private
6974
*/
7075
_ensurePowerOnState() {
71-
return new Promise(async resolve => {
76+
return new Promise(resolve => {
7277
if (noble.state === 'poweredOn') {
7378
return resolve();
7479
}
@@ -113,10 +118,28 @@ class MiFlora {
113118
return resolve();
114119
}, duration);
115120
noble.on('discover', peripheral => {
116-
const deviceAddress = MiFloraDevice.normaliseAddress(peripheral.address);
121+
let deviceAddress = peripheral.address;
122+
if (deviceAddress === '') {
123+
const serviceData = peripheral.advertisement.serviceData.find(item => item.uuid === UUID_SERVICE_XIAOMI);
124+
if (serviceData && serviceData.data && serviceData.data.length > 10) {
125+
for (let i = 10; i > 4; i--) {
126+
deviceAddress += intToHex(serviceData.data.readUInt8(i));
127+
if (i > 5) {
128+
deviceAddress += ':';
129+
}
130+
}
131+
132+
logDebug('fixing peripheral with address %s', deviceAddress);
133+
peripheral.address = deviceAddress;
134+
} else {
135+
logDebug('skipping unknown advertisment %o', peripheral.advertisement);
136+
return;
137+
}
138+
}
139+
140+
deviceAddress = MiFloraDevice.normaliseAddress(peripheral.address);
117141
if (ignoreUnknown && !addresses.find(addr => addr === deviceAddress)) {
118142
logDebug('ignoring device with address %s', deviceAddress);
119-
120143
return;
121144
}
122145

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "miflora",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"description": "Node.js package for the Xiaomi Plant Sensor Flower Care (Mi Flora)",
55
"main": "./lib/miflora.js",
66
"scripts": {
@@ -28,10 +28,10 @@
2828
},
2929
"homepage": "https://github.com/ChrisScheffler/miflora#readme",
3030
"dependencies": {
31-
"@abandonware/noble": "^1.9.2-5",
31+
"@abandonware/noble": "^1.9.2-8",
3232
"debug": "^4.1.1"
3333
},
3434
"devDependencies": {
35-
"xo": "^0.26.1"
35+
"xo": "^0.29.0"
3636
}
3737
}

0 commit comments

Comments
 (0)