I already had a look to the API provided by OralB. It’s quite disappointing.
They will provide you with classes to develop tools for android or ios apps. Not what we are looking for right now. :wink:
But maybe the documentation could be usefull.
I tried to find the forum page you mentioned. Found nothing usefull yet. Maybe you can have a look and help me out here.
I made a first attempt with noble and got some pretty nice results by reading out the braodcasted information from my brush.
I you wanna try on your own, do the following:
- Install noble in a directory of your choice, by following the instructions on the noble page:
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
sudo ln -s /usr/bin/nodejs /usr/bin/node
npm install noble
- Move into the new node_modules/noble/ - folder and create a new file ‘toothbrush.js’ with the following content
var async = require('async');
var noble = require('./index');
var OralB_manufacturerData = 'dc00010205030000000101';
console.log('Lookinhg for OralB Toothbrushes with manufacturerData: "' + OralB_manufacturerData +'"');
noble.on('stateChange', function(state) {
if (state === 'poweredOn') {
noble.startScanning();
} else {
noble.stopScanning();
}
});
noble.on('discover', function(peripheral) {
var advertisement = peripheral.advertisement;
console.log('Found device with manufacturerData: "' + advertisement.manufacturerData.toString('hex') +'" localName: ' + advertisement.localName);
if (advertisement.manufacturerData.toString('hex') === OralB_manufacturerData) {
noble.stopScanning();
console.log('peripheral with ID ' + peripheral.id + ' found');
var localName = advertisement.localName;
var txPowerLevel = advertisement.txPowerLevel;
var manufacturerData = advertisement.manufacturerData;
var serviceData = advertisement.serviceData;
var serviceUuids = advertisement.serviceUuids;
if (localName) {
console.log(' Local Name = ' + localName);
}
if (txPowerLevel) {
console.log(' TX Power Level = ' + txPowerLevel);
}
if (manufacturerData) {
console.log(' Manufacturer Data = ' + manufacturerData.toString('hex'));
}
if (serviceData) {
console.log(' Service Data = ' + serviceData);
}
if (serviceUuids) {
console.log(' Service UUIDs = ' + serviceUuids);
}
console.log();
explore(peripheral);
}
});
function explore(peripheral) {
console.log('services and characteristics:');
peripheral.on('disconnect', function() {
process.exit(0);
});
peripheral.connect(function(error) {
peripheral.discoverServices([], function(error, services) {
var serviceIndex = 0;
async.whilst(
function () {
return (serviceIndex < services.length);
},
function(callback) {
var service = services[serviceIndex];
var serviceInfo = service.uuid;
if (service.name) {
serviceInfo += ' (' + service.name + ')';
}
console.log(serviceInfo);
service.discoverCharacteristics([], function(error, characteristics) {
var characteristicIndex = 0;
async.whilst(
function () {
return (characteristicIndex < characteristics.length);
},
function(callback) {
var characteristic = characteristics[characteristicIndex];
var characteristicInfo = ' ' + characteristic.uuid;
if (characteristic.name) {
characteristicInfo += ' (' + characteristic.name + ')';
}
async.series([
function(callback) {
characteristic.discoverDescriptors(function(error, descriptors) {
async.detect(
descriptors,
function(descriptor, callback) {
return callback(descriptor.uuid === '2901');
},
function(userDescriptionDescriptor){
if (userDescriptionDescriptor) {
userDescriptionDescriptor.readValue(function(error, data) {
if (data) {
characteristicInfo += ' (' + data.toString() + ')';
}
callback();
});
} else {
callback();
}
}
);
});
},
function(callback) {
characteristicInfo += '\n properties ' + characteristic.properties.join(', ');
if (characteristic.properties.indexOf('read') !== -1) {
characteristic.read(function(error, data) {
if (data) {
var string = data.toString('ascii');
characteristicInfo += '\n value ' + data.toString('hex') + ' | \'' + string + '\'';
}
callback();
});
} else {
callback();
}
},
function() {
console.log(characteristicInfo);
characteristicIndex++;
callback();
}
]);
},
function(error) {
serviceIndex++;
callback();
}
);
});
},
function (err) {
peripheral.disconnect();
}
);
});
});
}
- Start the script by with
sudo node toothbrush.js
Here is what I got:
Lookinhg for OralB Toothbrushes with mac address:54:4a:16:21:20:9f
peripheral with ID 544a1621209f found
Manufacturer Data = dc00010205020000000101
Service Data =
Service UUIDs =
services and characteristics:
1800 (Generic Access)
2a00 (Device Name)
properties read
value 4f72616c2d4220546f6f74686272757368 | 'Oral-B Toothbrush'
2a01 (Appearance)
properties read
value 0000 | ''
2a02 (Peripheral Privacy Flag)
properties read, write
value 00 | ''
2a03 (Reconnection Address)
properties read, write
value 000000000000 | ''
2a04 (Peripheral Preferred Connection Parameters)
properties read
value 5000a0000000e803 | 'P h'
1801 (Generic Attribute)
2a05 (Service Changed)
properties indicate
a0f0fff050474d5382084f72616c2d42
a0f0fff150474d5382084f72616c2d42 (Command)
properties read, write, notify
value 00 | ''
a0f0fff250474d5382084f72616c2d42 (Data)
properties read, write
value 00000000 | ''
a0f0fff350474d5382084f72616c2d42 (Auth)
properties read, write
value 00 | ''
a0f0fff450474d5382084f72616c2d42 (Secret)
properties read, write
value 00000000 | ''
a0f0ff0050474d5382084f72616c2d42
a0f0ff0150474d5382084f72616c2d42 (Handle ID)
properties read
value 00000000 | ''
a0f0ff0250474d5382084f72616c2d42 (Handle Type)
properties read
value 02 | ''
a0f0ff0350474d5382084f72616c2d42 (User Account)
properties read
value 01 | ''
a0f0ff0450474d5382084f72616c2d42 (Device State)
properties read, notify
value 0200 | ''
a0f0ff0550474d5382084f72616c2d42 (Battery Level)
properties read, notify
value 63 | 'c'
a0f0ff0650474d5382084f72616c2d42 (Button State)
properties read, notify
value 00000000 | ''
a0f0ff0750474d5382084f72616c2d42 (Brushing Mode)
properties read, notify
value 01 | ''
a0f0ff0850474d5382084f72616c2d42 (Brushing Time)
properties read, notify
value 0000 | ''
a0f0ff0950474d5382084f72616c2d42 (Quadrant)
properties read, notify
value 00 | ''
a0f0ff0a50474d5382084f72616c2d42 (Smiley)
properties read, notify
value 00 | ''
a0f0ff0b50474d5382084f72616c2d42 (Pressure Sensor)
properties read, notify
value 00 | ''
a0f0ff0c50474d5382084f72616c2d42 (Cache)
properties read, write, notify
value | ''
a0f0ff2050474d5382084f72616c2d42
a0f0ff2150474d5382084f72616c2d42 (Status)
properties read, write, notify
value 8100 | ''
a0f0ff2250474d5382084f72616c2d42 (RTC)
properties read, write
value 97d81120 | 'X '
a0f0ff2350474d5382084f72616c2d42 (Timezone)
properties read, write
' value 0d | '
a0f0ff2450474d5382084f72616c2d42 (Brushing Timer)
properties read, write
value 0f | ''
a0f0ff2550474d5382084f72616c2d42 (Brushing Modes)
properties read, write
value 0105020403000000 | ''
PuTTY a0f0ff2650474d5382084f72616c2d42 (Quadrant Times)
properties read, write
value 1e001e001e001e000000000000000000 | ''
a0f0ff2750474d5382084f72616c2d42 (Tongue Time)
properties read, write
value 00 | ''
a0f0ff2850474d5382084f72616c2d42 (Pressure)
properties read, write
value 03 | ''
a0f0ff2950474d5382084f72616c2d42 (Data)
properties read
value 68d6fd1f7700010100000063d1e7fd1f | 'hV}wcQg}'
a0f0ff2a50474d5382084f72616c2d42 (Flight Mode)
properties read, write
value 00 | ''