在iOS和iPadOS、Android以及Windows中开发基于Wi-Fi、BLE、MQTT等的物联网技术。
万物可以互联,万物也必须互联。
低功耗蓝牙 ( Bluetooth Low Energy )技术被广泛地使用在智能手表、运动手环、健康监测、共享单车、智能家电等设备的通讯中,使智能设备轻松地与手机、平板和电脑等交换数据信息。
公元 935-985 年间的丹麦和挪威的国王 Harald Blatand 非常爱吃蓝莓,因此牙齿被染成蓝色。 Harald Blatand 国王骁勇善战,统治丹麦期间,持续对外征战,统一了今天的挪威、瑞典和丹麦广大北欧地区。早年,他曾是北欧海盗精神的发扬者,而当时北欧地区的主要信仰是奥丁神( Odin ),即众神之王。
蓝牙技术联盟 SIG(Special Interest Group)行业协会,用这个似乎古怪的名字来体现和映衬 SIG 希望统一无线技术领域的雄心壮志。
蓝牙的图标取自 Harald Blatand 国王名字的两个首字母 H 和 B 的古北欧字母的结合。
与经典蓝牙相比较,低功耗蓝牙:
BluetoothManager mBluetoothManager = getSystemService( Context.BLUETOOTH_SERVICE );
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter( );
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback(){};
// 开始扫描
mBluetoothAdapter.startLeScan( mLeScanCallback );
// 发现设备后自动触发回调函数
mLeScanCallback. onLeScan ( BluetoothDevice device, int rssi , byte[] scanRecord ) {
// 存储设备名称、物理地址、信号强度等信息
mName[] = device.getName();
mAddress[] = device.getAddress();
mRSSI[] = rssi;
}
BluetoothLeService mBluetoothLeService;
ServiceConnection mServiceConnection =
new ServiceConnection() {};
Intent mGattServiceIntent =
new Intent( this, mBluetoothLeService.class );
bindService( mGattServiceIntent, mServiceConnection, BIN_AUTO_CREATE );
// 自动触发
mServiceConnection.onServiceConnected ( ComponentName componentName, IBinder service ) {
mBluetoothLeService = service.getService();
mBluetoothLeService.initialize();
}
initialize() {
BluetoothManager nBluetoothManager =
getSystemService
( Context.BLUETOOTH_SERVICE );
BluetoothAdapter nBluetoothAdapter =
nBluetoothManager.getAdapter();
}
// 自动触发
Ibinder nIBinder = new LocalBinder();
onBind( Intent intent ) {
return nIBinder;
}
LocalBinder( ) {
BluetoothLeService getService(){
return BluetoothLeServie.this
}
}
// 连接第1部设备
mBluetoothLeService.connect( mAddress[0], 1);
// 连接第2部设备
mBluetoothLeService.connect( mAddress[1], 2);
…
// 每部设备都有自己的 BLE GATT 和 BLE Service
BluetoothGatt[] nBluetoothGatt;
BluetoothGattCallback nBluetoothGattCallback = BluetoothGattCallback(){};
connect( String address, int n ) {
nAddress[n-1] = address;
BluetoothDevice device =
nBluetoothAdapter.getRemoteDevice( address );
nBluetoothGatt[n-1] =
device.connectGatt( Context this, Boolean
autoConnect false, BluetoothGattCallback
nBluetoothGattCallback);
}
// 自动触发
nBluetoothGattCallback() {
onConnectionStateChange( BluetoothGatt gatt, int status, int newState ) {
if( status == BluetoothGatt.GATT_SUCCESS ) {
if ( newState == STATE_CONNECTED ) {
if( gatt.getDevice().getAddress() == naddress[0] )
{ nBluetoothGatt[0]. discoverServices(); }
if( gatt.getDevice().getAddress() == naddress[1] )
{ nBluetoothGatt[1]. discoverServices(); }
…
}
}
}
}
// 自动搜索 BLE Service 和 BLE Characteristics
…
// 每个 BLE Service 都有自己的 BLE Characteristics
BluetoothGattCharacteristic[] nNotifyCharacteristic;
BluetoothGattCharacteristic[] nWriteCharacteristic;
BluetoothGattCharacteristic[] nReadCharacteristic;
// 自动触发
nBluetoothGattCallback() {
onServicesDiscovered( BluetoothGatt gatt, int status ) {
if ( status == BluetoothGatt.GATT_SUCCESS ) {
BluetoothGattService service =
BluetoothGatt.getService( UUID.fromString(XXXX) );
if ( service != null ) { // go on to get characteristic
if ( gatt.getDevice().getAddress() == nAddress[0] ) {
nNotifyCharacteristic[0] = service.getCharacteristic(UUID.fromString(XXXX));
nWriteCharacteristic[0] = service.getCharacteristic(UUID.fromString(XXXX));
nReadCharacteristic[0] = service.getCharacteristic(UUID.fromString(XXXX));
}
if ( gatt.getDevice().getAddress() == nAddress[1] ) {
nNotifyCharacteristic[1] = service.getCharacteristic(UUID.fromString(XXXX));
nWriteCharacteristic[1] = service.getCharacteristic(UUID.fromString(XXXX));
nReadCharacteristic[1] = service.getCharacteristic(UUID.fromString(XXXX));
}
}
}
}
}
// 向第1部设备发送数据
mBluetoothLeService.writeData( 1, data )
// 向第2部设备发送数据
mBluetoothLeService.writeData( 2, data )
…
writeData( int n, byte[] data ) {
nWriteCharacteristic[n].setValue( data );
nBluetoothGatt[n].writeCharacteristic
( nWriteCharacteristic[n] );
}
// 自动触发
nBluetoothGattCallback() {
onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS)
{ }
}
}
// 从第1部设备接收数据
mBluetoothLeService.readData ( 1, true );
// 从第2部设备接收数据
mBluetoothLeService.readData ( 2, true );
readData( int n, Boolean state) {
if(state) {
setCharacteristicNotification
( mNotifyCharacteristic[n-1],true );
nBluetoothGatt[n-1].readCharacteristic
( mNotifyCharacteristic[n-1] );
}
else {
nBluetoothGatt[n-1].
setCharacteristicNotification
( mNotifyCharacteristic[n-1],false );
}
}
// 通过 Broadcasting 把接收到的数据反馈给 Android Activity
// 自动触发
nBluetoothGattCallback() {
// 触发情况1
onCharacteristicRead (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if ( status == BluetoothGatt.GATT_SUCCESS ) {
if ( gatt.getDevice().getAddress() == nAddress[0] ) {
broadcastUpdate(ACTION_DATA_AVAILABLE_1,
characteristic);
}
if ( gatt.getDevice().getAddress() == nAddress[1] ) {
broadcastUpdate(ACTION_DATA_AVAILABLE_2,
characteristic);
}
}
}
// 触发情况2
onCharacteristicChanged (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if ( status == BluetoothGatt.GATT_SUCCESS ) {
if ( gatt.getDevice().getAddress() == nAddress[0] ) {
broadcastUpdate(ACTION_DATA_AVAILABLE_1,
characteristic);
}
if ( gatt.getDevice().getAddress() == nAddress[1] ) {
broadcastUpdate(ACTION_DATA_AVAILABLE_2,
characteristic);
}
}
}
}
// 把数据从 Android Service 传递到 Android Activity
broadcastUpdate (String action, BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
if ( UUID.fromString(XXXX).equals( characteristic.getUuid() ) ) {
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
intent.putExtra(EXTRA_DATA,data);
}
}
sendBroadcast(intent);
}
// 断开与第1部设备的连接
mBluetoothLEService. Disconnect(1);
// 断开与第2部设备的连接
mBluetoothLEService.disconnect(2);
…
// 取消 ANDROID SERVICE ( BLUETOOTHLEACTIVITY ) 和 ANDROID ACTIVITY ( BLUETOOTHLESERVICE ) 之间的绑定
unbindService( mServiceConnection );
mBluetoothLeService = null;
disconnect (int n) {
nBluetoothGatt[n-1].disconnect();
}
// 中心设备
var mCentralManager: CBCentralManager!
// 外围设备
Var mPeripheral_1: CBPeripheral!
Var mPeripheral_2: CBPeripheral!
…
// 外围设备标识
var mUUID_1: UUID
var mUUID_2: UUID
…
// Service
Var mService_1: CBService!
Var mService_2: CBService!
…
// Characteristic
Var mWriteCharacteristic_1: CBCharacteristic!
Var mReadCharacteristic_1: CBCharacteristic!
Var mNotifyCharacteristic_1: CBCharacteristic!
…
Var mWriteCharacteristic_2: CBCharacteristic!
Var mReadCharacteristic_2: CBCharacteristic!
Var mNotifyCharacteristic_2: CBCharacteristic!
…
// 初始化中心设备
self.mCentralManager = CBCentralManager(delegate: self, queue: nil)
…
// 检查中心设备的蓝牙硬件
// 自动触发
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch( central.state ){
case CBManagerState.poweredOn:
// 开始搜索外围 BLE 设备
self.mCentralManager.scanForPeripherals(withServices: nil, options: nil)
}
}
// 发现外围 BLE 设备时
// 自动触发
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
// 外围设备的 UUID、 名称和信号强度等
mPeripheral_1 = peripheral
mUUID_1 = mPeripheral_1.identifier
mPeripheral_2 = peripheral
mUUID_2 = mPeripheral_2.identifier
…
}
// 连接外围设备1
mCentralManager.connect(mperipheral_1, options: nil)
// 连接外围设备2
mCentralManager.connect(mperipheral_2, options: nil)
…
// 连接到外围设备时
// 自动触发
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if( peripheral.identifier == mUUID_1){
// 外围设备1已经连接
}
if( peripheral.identifier == mUUID_2){
// 外围设备2已经连接
}
…
}
// 检查外围设备状态
mPeripheral_1.discoverServices(nil)
mPeripheral_2.discoverServices(nil)
// 发现外围设备1的 Service 时
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if( peripheral == mPeripheral_1 ){
if( peripheral.services?.count != 0 )
for service in peripheral.services! {
if service.uuid.uuidString.contains(“XXXX"){
mService_1 = service as CBService
// 已经发现 Servie “XXXX"
// 继续发现 Characteristic
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
}
// 发现外围设备2的 Service 时
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if( peripheral == mPeripheral_2 ){
if( peripheral.services?.count != 0 )
for service in peripheral.services! {
if service.uuid.uuidString.contains(“XXXX"){
mService_2 = service as CBService
// 已经发现 Servie “XXXX"
// 继续发现 Characteristic
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
}
// 发现 Characteristic 时
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if( peripheral == mPeripheral_1 ){
if( service.characteristics!.count != 0 ){
for Characterisitc in service.characteristics!{
let mCharacteristic: CBCharacteristic = Characterisitc as CBCharacteristic
if( mService_1 != nil ){
if( mService_1 == service ){
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mNotifyCharacteristic_1 = mCharacteristic
}
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mWriteCharacteristic_1 = mCharacteristic
}
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mReadCharacteristic_1 = mCharacteristic
}
}
}
}
}
}
if( peripheral == mPeripheral_2 ){
if( service.characteristics!.count != 0 ){
for Characterisitc in service.characteristics!{
let mCharacteristic: CBCharacteristic = Characterisitc as CBCharacteristic
if( mService_2 != nil ){
if( mService_2 == service ){
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mNotifyCharacteristic_2 = mCharacteristic
}
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mWriteCharacteristic_2 = mCharacteristic
}
if( mCharacteristic.uuid.uuidString.contains(“xxxx") ){
mReadCharacteristic_2 = mCharacteristic
}
}
}
}
}
}
…
}
// 发送数据到外围设备1
DispatchAfter(after: 0.0) {
self.mPeripheral_1.setNotifyValue(false, for: self.mNotifyCharacteristic_1)
}
DispatchAfter(after: 0.2) {
self.mPeripheral_1.writeValue(writedata, for: self.mWriteCharacteristic_1, type: CBCharacteristicWriteType.withoutResponse)
}
// 发送数据到外围设备2
DispatchAfter(after: 0.0) {
self.mPeripheral_2.setNotifyValue(false, for: self.mNotifyCharacteristic_2)
}
DispatchAfter(after: 0.2) {
self.mPeripheral_2.writeValue(writedata, for: self.mWriteCharacteristic_2, type: CBCharacteristicWriteType.withoutResponse)
}
…
// 准备从外围设备1接收数据
mPeripheral_1?.readValue(for: mReadCharacteristic_1!)
// 准备从外围设备2接收数据
mPeripheral_2?.readValue(for: mReadCharacteristic_2!)
// 当接收到数据时
// 自动触发
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?){
if( peripheral.identifier == mUUID_1){
readdata1[0] = characteristic.value![0]
readdata1[1] = characteristic.value![1]
readdata1[2] = characteristic.value![2]
readdata1[3] = characteristic.value![3]
readdata1[4] = characteristic.value![4]
readdata1[5] = characteristic.value![5]
…
}
if( peripheral.identifier == mUUID_2){
readdata2[0] = characteristic.value![0]
readdata2[1] = characteristic.value![1]
readdata2[2] = characteristic.value![2]
readdata2[3] = characteristic.value![3]
readdata2[4] = characteristic.value![4]
readdata2[5] = characteristic.value![5]
…
}
…
}
self.mCentralManager.cancelPeripheralConnection(self.mPeripheral_1)
self.mCentralManager.cancelPeripheralConnection(self.mPeripheral_2)
…
-- | Android | Windows | iOS and iPadOS |
BLE | JAVA code using android.bluetooth | -------------------------------- | Swift code using CoreBluetooth |
Wi-Fi | JAVA code using socket | C# code using socket | Swift code using socket |
MQTT | JAVA code using Eclipse Paho | C# code using C# M2MQTT.NET | Swift code using CocoaMQTT |