forked from noble/noble
-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inject GATT descriptors #29
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/** discover a device (here, the first one where the name was resolved), | ||
* for the first device discover all services and characteristics, | ||
* store the collected GATT information into a meta-data object and write to disk. | ||
* Finds a temperature characteristic and registers for data. | ||
* Prints timing information from discovered to connected to reading states. | ||
*/ | ||
|
||
var noble = require('../index'); | ||
const fs = require('fs'); | ||
|
||
// the sensor value to scan for, number of bits and factor for displaying it | ||
const CHANNEL = process.env['CHANNEL'] ? process.env['CHANNEL'] : 'Temperature' | ||
const BITS = process.env['BITS'] ? 1 * process.env['BITS'] : 16 | ||
const FACTOR = process.env['FACTOR'] ? 1. * process.env['FACTOR'] : .1 | ||
|
||
const EXT='.dump' | ||
|
||
noble.on('stateChange', function(state) { | ||
if (state === 'poweredOn') { | ||
noble.startScanning(); | ||
} else { | ||
noble.stopScanning(); | ||
} | ||
}); | ||
|
||
let tDisco=0; // time when device was discovered | ||
let tConn =0; // time when connection to device was established | ||
let tRead =0; // time when reading data starts. | ||
|
||
// collect device meta-data into this object: | ||
let meta = { | ||
services: [], // stores an array of GATT service data objects | ||
characteristics: {} // a map with key service-UUID, stores the array of characteristics | ||
} | ||
|
||
noble.on('discover', function(peripheral) { | ||
console.log('peripheral discovered (' + peripheral.id + | ||
' with address <' + peripheral.address + ', ' + peripheral.addressType + '>,' + | ||
' connectable ' + peripheral.connectable + ',' + | ||
' RSSI ' + peripheral.rssi + ':'); | ||
console.log('\thello my local name is:'); | ||
console.log('\t\t' + peripheral.advertisement.localName); | ||
console.log(); | ||
|
||
// connect to the first device with a valid name | ||
if (peripheral.advertisement.localName) { | ||
console.log('Connecting to ' + peripheral.address + ' ' + peripheral.advertisement.localName) | ||
|
||
tDisco = Date.now() | ||
|
||
connectToDevice(peripheral) | ||
} | ||
}); | ||
|
||
let connectToDevice = function (peripheral) { | ||
// BLE cannot scan and connect in parallel, so we stop scanning here: | ||
noble.stopScanning() | ||
|
||
peripheral.connect((error) => { | ||
// noble.startScanning([], true) | ||
if (error) { | ||
console.log('Connect error: ' + error) | ||
noble.startScanning([], true) | ||
return | ||
} | ||
tConn = Date.now() | ||
console.log('Connected!') | ||
|
||
findServices(noble, peripheral) | ||
}) | ||
} | ||
|
||
|
||
let servicesToRead = 0; | ||
|
||
let findServices = function (noble, peripheral) { | ||
meta.uuid = peripheral.uuid | ||
meta.address = peripheral.address | ||
meta.name = peripheral.advertisement.localName // not needed but nice to have | ||
|
||
meta.characteristics = {} | ||
|
||
// callback triggers with GATT-relevant data | ||
peripheral.on('servicesDiscovered', (peripheral, services) => { | ||
|
||
console.log('servicesDiscovered: Found '+ services.length + ' services! ') | ||
meta.services = services | ||
for (let i in services) { | ||
const service = services[i] | ||
console.log('\tservice ' + i + ' : ' + JSON.stringify(service)) | ||
//meta.services[ service.uuid ] = service | ||
} | ||
}) | ||
|
||
peripheral.discoverServices([], (error, services) => { | ||
|
||
let sensorCharacteristic | ||
|
||
servicesToRead = services.length | ||
// we found the list of services, now trigger characteristics lookup for each of them: | ||
|
||
for (let i = 0; i < services.length; i++) { | ||
let service = services[i] | ||
|
||
service.on('characteristicsDiscovered', (characteristics) => { | ||
// store the list of characteristics per service | ||
meta.characteristics[service.uuid] = characteristics | ||
|
||
console.log('SRV\t' + service.uuid + ' characteristic GATT data: ') | ||
for (let i = 0; i < characteristics.length; i++) { | ||
console.log('\t' + service.uuid + ' chara.\t ' + ' ' + i + ' ' + JSON.stringify(characteristics[i])) | ||
} | ||
}) | ||
|
||
service.discoverCharacteristics([], function (error, characteristics) { | ||
console.log('SRV\t' + service.uuid + ' characteristic decoded data: ' ) | ||
for (let j = 0; j< characteristics.length; j++) { | ||
let ch = characteristics[j] | ||
console.log('\t' + service.uuid + ' chara.\t ' + ' ' + j + ' ' + ch) | ||
|
||
if ( ch.name === CHANNEL) { | ||
console.log('found ' + CHANNEL + ' characteristic!') | ||
sensorCharacteristic = ch | ||
} | ||
} | ||
|
||
servicesToRead-- | ||
if (!servicesToRead) { | ||
console.log('----------------- FINISHED') | ||
console.log(JSON.stringify(meta, null, 4)) | ||
// write to file | ||
fs.writeFile(meta.uuid + EXT, JSON.stringify(meta,null,2), function(err) { | ||
if(err) { | ||
return console.log(err); | ||
} | ||
console.log("The data was saved to " , meta.uuid + EXT); | ||
}); | ||
|
||
if (sensorCharacteristic) { | ||
console.log('Listening for temperature data...') | ||
|
||
tRead = Date.now() | ||
|
||
sensorCharacteristic.on('data', (data) => { | ||
if (BITS === 16 ) { | ||
console.log(' new ' + CHANNEL + ' ' + (data.readUInt16LE() * FACTOR) ) | ||
} else if (BITS === 32) { | ||
console.log(' new ' + CHANNEL + ' ' + (data.readUInt32LE() * FACTOR) ) | ||
} else { | ||
console.log(' Cannot cope with BITS value '+ BITS) | ||
} | ||
}) | ||
sensorCharacteristic.read() | ||
} | ||
|
||
console.log('Timespan from discovery to connected: ' + (tConn -tDisco) + ' ms') | ||
console.log('Timespan from connected to reading : ' + (tRead -tConn) + ' ms') | ||
} | ||
}) | ||
} | ||
}) | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** reconnect to a device that has been discovered earlier on using cache-gatt-discovery: | ||
* If a device is discovered and a dump file exists, load it and connect to it, re-initializing service | ||
* and characteristic objects in the noble stack. | ||
* Finds a temperature characteristic and registers for data. | ||
* Prints timing information from discovered to connected to reading states. | ||
*/ | ||
|
||
var noble = require('../index'); | ||
const fs = require('fs'); | ||
|
||
// the sensor value to scan for, number of bits and factor for displaying it | ||
const CHANNEL = process.env['CHANNEL'] ? process.env['CHANNEL'] : 'Temperature' | ||
const BITS = process.env['BITS'] ? 1 * process.env['BITS'] : 16 | ||
const FACTOR = process.env['FACTOR'] ? 1. * process.env['FACTOR'] : .1 | ||
|
||
const EXT='.dump' | ||
|
||
noble.on('stateChange', function(state) { | ||
if (state === 'poweredOn') { | ||
noble.startScanning(); | ||
} else { | ||
noble.stopScanning(); | ||
} | ||
}); | ||
|
||
let tDisco=0; // time when device was discovered | ||
let tConn =0; // time when connection to device was established | ||
let tRead =0; // time when reading data starts. | ||
|
||
// collect device meta-data into this object: | ||
let meta = { | ||
services: {}, // a map indexted by service-UUID -> contains service data | ||
characteristics: {} // an map with key service-UUID, stores the array of characteristics | ||
} | ||
|
||
noble.on('discover', function(peripheral) { | ||
console.log('peripheral discovered (' + peripheral.id + | ||
' with address <' + peripheral.address + ', ' + peripheral.addressType + '>,' + | ||
' connectable ' + peripheral.connectable + ',' + | ||
' RSSI ' + peripheral.rssi + ':'); | ||
console.log('\thello my local name is:'); | ||
console.log('\t\t' + peripheral.advertisement.localName); | ||
console.log(); | ||
|
||
|
||
// Check if a dump exists in the current directory. | ||
fs.access(peripheral.uuid + EXT, fs.constants.F_OK, (err) => { | ||
if (!err) { | ||
console.log('found dump file for ' + peripheral.uuid ) | ||
|
||
tDisco=Date.now() | ||
|
||
quickConnect(peripheral) | ||
} | ||
}); | ||
}); | ||
|
||
|
||
let quickConnect = function (peripheral) { | ||
// BLE cannot scan and connect in parallel, so we stop scanning here: | ||
noble.stopScanning() | ||
|
||
|
||
peripheral.connect((error) => { | ||
if (error) { | ||
console.log('Connect error: ' + error) | ||
noble.startScanning([], true) | ||
return | ||
} | ||
tConn = Date.now() | ||
console.log('Connected!') | ||
|
||
// load stored data. This needs to be done when connected, as we need a handle at GATT level | ||
meta = loadData(peripheral) | ||
|
||
// initialize the service and charateristics objects in Noble; return a temperature characteristic, if found | ||
let sensorCharacteristic = setData(peripheral, meta) | ||
|
||
if (!sensorCharacteristic) { | ||
console.log('Warning - no temperature characteristic found.') | ||
} else { | ||
console.log('Listening for temperature data...') | ||
|
||
tRead = Date.now() | ||
|
||
sensorCharacteristic.on('data', (data) => { | ||
if (BITS === 16 ) { | ||
console.log(' new ' + CHANNEL + ' ' + (data.readUInt16LE() * FACTOR) ) | ||
} else if (BITS === 32) { | ||
console.log(' new ' + CHANNEL + ' ' + (data.readUInt32LE() * FACTOR) ) | ||
} else { | ||
console.log(' Cannot cope with BITS value '+ BITS) | ||
} | ||
}) | ||
sensorCharacteristic.read() | ||
|
||
console.log('Timespan from discovery to connected: ' + (tConn -tDisco) + ' ms') | ||
console.log('Timespan from connected to reading : ' + (tRead -tConn) + ' ms') | ||
} | ||
}) | ||
} | ||
|
||
let loadData = function(peripheral) { | ||
const dump = fs.readFileSync(peripheral.uuid + EXT) | ||
const data = JSON.parse(dump) | ||
|
||
// verify data: console.log(JSON.stringify(data,null,2)) | ||
return data | ||
} | ||
|
||
let setData = function(peripheral, meta) { | ||
// first, create the service objects: | ||
console.log('initializing services... ') | ||
|
||
// addServices returns an array of initialized service objects | ||
let services = noble.addServices(peripheral.uuid, meta.services) | ||
|
||
console.log('initialized services: ') | ||
for (let i in services) { | ||
const service = services[i] | ||
console.log('\tservice ' + i + ' ' + service) | ||
} | ||
console.log() | ||
|
||
let sensorCharacteristic | ||
|
||
console.log('initializing characteristics... ') | ||
// now, for each service, set the characteristics: | ||
for (let i in services) { | ||
const service = services[i] | ||
const charas = meta.characteristics[service.uuid] | ||
console.log('\tservice ' + i + ' ' + service + ' ' + JSON.stringify(charas)) | ||
|
||
let characteristics = noble.addCharacteristics(peripheral.uuid, service.uuid, charas) | ||
|
||
for (let j in characteristics) { | ||
let characteristic = characteristics[j] | ||
console.log('\t\tcharac ' + service.uuid + ' ' + j + ' ' + characteristic + ' ' + characteristic.rawProps) | ||
if (characteristic.name === CHANNEL) { | ||
console.log('\t\t\t-->found ' + CHANNEL + ' characteristic!') | ||
sensorCharacteristic = characteristic | ||
} | ||
} | ||
} | ||
return sensorCharacteristic | ||
} |
This file contains 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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or just "Unknown"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer a working example... at least for parts of the universe ;)