Last active
November 29, 2019 00:33
-
-
Save diginfo/b95f809bb308a5d350e1c1b13cd28385 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const cl = console.log; | |
const noble = require('@abandonware/noble'); | |
function buf2arr(bufdata){ | |
var buffer = Buffer.from(bufdata) | |
return Array.prototype.slice.call(buffer, 0) | |
} | |
// use manufacturer data, no connect. | |
function readMfgData(peripheral) { | |
/* | |
tempdata: [0,26,6,0,71,3] | |
mfgdata: [ | |
{0,26,6,0,71,3}, | |
{23}, | |
{205,215,81,21,15,126} | |
] | |
*/ | |
const result = { | |
counter : new Date().getTime(), | |
id : peripheral.id, | |
mac : peripheral.address, | |
raw : peripheral.advertisement.manufacturerData, | |
mfgdata : buf2arr(peripheral.advertisement.manufacturerData), | |
}; | |
result.tmphum = result.mfgdata.slice(0,6); | |
result.event = { | |
data: { | |
batt : result.mfgdata[6], | |
rssi : peripheral.rssi, | |
tmp : result.tmphum[1]+result.tmphum[2]/10, | |
hum : result.tmphum[4]+result.tmphum[5]/10, | |
stamp : new Date().getTime() | |
} | |
} | |
return result; | |
} | |
//var gwmod = ''; // change later for running as a script. | |
var gwmod = '/home/pi/mozilla-iot/gateway/node_modules/'; | |
const { | |
Adapter, | |
Device, | |
Property | |
} = require(`${gwmod}gateway-addon`); | |
class TemperatureHumiditySensor extends Device { | |
constructor(adapter, manifest, id) { | |
//super(adapter, `${manifest.display_name}-${id}`); | |
super(adapter,id); | |
this['@context'] = 'https://iot.mozilla.org/schemas/'; | |
this['@type'] = ['TemperatureSensor']; | |
this.name = manifest.display_name; | |
//this.name = id; | |
//this.description = manifest.description; | |
this.description = 'room1'; | |
this.addProperty({ | |
type: 'number', | |
'@type': 'TemperatureProperty', | |
minimum: -127.99, | |
maximum: 127.99, | |
multipleOf: 0.1, | |
unit: 'degree celsius', | |
title: 'temperature', | |
description: 'The ambient temperature', | |
readOnly: true | |
}); | |
this.addProperty({ | |
type: 'number', | |
minimum: 0, | |
maximum: 100, | |
multipleOf: 0.1, | |
unit: '%', | |
title: 'humidity', | |
description: 'The relative humidity', | |
readOnly: true | |
}); | |
this.addProperty({ | |
type: 'number', | |
minimum: -100, | |
maximum: 0, | |
multipleOf: 0.1, | |
unit: 'dbi', | |
title: 'rssi', | |
description: 'Signal Strength', | |
readOnly: true | |
}); | |
this.addProperty({ | |
type: 'number', | |
minimum: 0, | |
maximum: 100, | |
multipleOf: 0.1, | |
unit: '%', | |
title: 'batt', | |
description: 'Battery Level', | |
readOnly: true | |
}); | |
} | |
// function. | |
addProperty(description) { | |
const property = new Property(this, description.title, description); | |
this.properties.set(description.title, property); | |
} | |
// this function should get & set data ??? | |
setData(data) { | |
cl(`${data.id}.setData(${JSON.stringify(data.event.data,null,2)})`); | |
if(isdev) this.adapter.manager.sendPropertyChangedNotification = function (property){}; | |
/* | |
{ | |
mac: '', | |
capability: '', | |
raw: [ 0, 28, 4, 0, 66, 0 ], | |
event: { | |
raw: [ 0, 28, 4, 0, 66, 0 ], | |
data: { | |
batt: 41, | |
rssi: -67, | |
tmp: 28.4, | |
hum: 66, | |
stamp: 1574738827049 | |
} | |
} | |
} | |
*/ | |
const result = data; | |
//const result = readServiceData(serviceData.data); | |
if (result.event && result.event.data) { | |
const data = result.event.data; | |
if (data.batt) { | |
const batt = result.event.data.batt; | |
const property = this.properties.get('batt'); | |
property.setCachedValue(batt); | |
this.notifyPropertyChanged(property); | |
} | |
if (data.rssi) { | |
const rssi = result.event.data.rssi; | |
const property = this.properties.get('rssi'); | |
property.setCachedValue(rssi); | |
this.notifyPropertyChanged(property); | |
} | |
if (data.tmp) { | |
const temperature = result.event.data.tmp; | |
const property = this.properties.get('temperature'); | |
property.setCachedValue(temperature); | |
this.notifyPropertyChanged(property); | |
} | |
if (data.hum) { | |
const humidity = result.event.data.hum; | |
const property = this.properties.get('humidity'); | |
property.setCachedValue(humidity); | |
this.notifyPropertyChanged(property); | |
} | |
} | |
} | |
} | |
class TemperatureHumiditySensorAdapter extends Adapter { | |
/** | |
* Example process ro remove a device from the adapter. | |
* The important part is to call: `this.handleDeviceRemoved(device)` | |
* @param {String} deviceId ID of the device to remove. | |
* @return {Promise} which resolves to the device removed. | |
*/ | |
removeDevice(deviceId) { | |
cl('@@ removeDevice():',deviceId); | |
return new Promise((resolve, reject) => { | |
const device = this.devices[deviceId]; | |
if (device) { | |
this.handleDeviceRemoved(device); | |
resolve(device); | |
} else { | |
reject(`Device: ${deviceId} not found.`); | |
} | |
}); | |
} | |
/** | |
* Unpaira the provided the device from the adapter. | |
* @param {Object} device Device to unpair with | |
*/ | |
removeThing(device) { | |
cl('remove Device:', this.name, 'id', this.id,'removeThing(', device.id, ') started'); | |
this.removeDevice(device.id).then(() => { | |
cl('ExampleAdapter: device:', device.id, 'was unpaired.'); | |
}).catch((err) => { | |
cl('ExampleAdapter: unpairing', device.id, 'failed'); | |
cl(err); | |
}); | |
} | |
constructor(addonManager, manifest) { | |
super(addonManager, TemperatureHumiditySensorAdapter.name, manifest.name); | |
addonManager.addAdapter(this); | |
// manifest.moziot.config.pollInterval is null ! | |
//this.pollInterval = manifest.moziot.config.pollInterval; | |
this.pollInterval = 15; // seconds | |
this.knownDevices = {}; | |
const me = this; | |
// initialise | |
noble.on('stateChange', (state) => { | |
const duplicates = true; | |
console.log('Noble adapter is %s', state); | |
if (state === 'poweredOn') noble.startScanning(['aa20'],duplicates); | |
}); | |
// discovered | |
noble.on('discover', (peripheral) => { | |
const id = peripheral.id; | |
let knownDevice = this.knownDevices[id]; | |
// if unknown then add it. | |
if (!knownDevice) { | |
//cl(`Detected new Sensor ${id}`); | |
knownDevice = new TemperatureHumiditySensor(this, manifest, id); | |
this.handleDeviceAdded(knownDevice); | |
this.knownDevices[id] = knownDevice; | |
} | |
// NO-CONNECT use manufacturer's data (no connect) | |
var data = readMfgData(peripheral); | |
var now = new Date().getTime(); | |
// limit update frequency | |
if(! knownDevice._last || now - knownDevice._last > (this.pollInterval * 1000)){ | |
knownDevice.setData(data); | |
this.knownDevices[id]._last = now; | |
} | |
}); | |
} | |
} | |
// Run this as a stand-alone script for development | |
// node /home/pi/.mozilla-iot/addons/xiaomi-temperature-humidity-sensor-adapter/xiaomi-temperature-humidity-sensor-adapter.js | |
// sudo systemctl restart bluetooth; sudo systemctl restart mozilla-iot-gateway.service; journalctl -f | grep xiaomi | |
var isdev = false; | |
const debug = 1; | |
if(require.main === module){ | |
isdev = true; | |
gwmod = '/home/pi/mozilla-iot/gateway/node_modules/'; | |
const manifest = require('/home/pi/.mozilla-iot/addons/xiaomi-temperature-humidity-sensor-adapter/manifest.json'); | |
//if(!manifest.moziot) manifest.moziot = {config:{pollInterval:15}}; | |
process.on('SIGINT', function() { | |
cl("Quitting Noble."); | |
noble.stopScanning(); | |
process.exit(); | |
}); | |
const addonManager = { | |
handleDeviceAdded: function(knownDevice){ | |
cl('handleDeviceAdded()') | |
}, | |
addAdapter: function(){ | |
cl('addAdapter()') | |
} | |
}; | |
// | |
jinou = new TemperatureHumiditySensorAdapter(addonManager,manifest); | |
} | |
module.exports = TemperatureHumiditySensorAdapter; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment