-
-
Save gwaldvogel/ddfffcc264f42900ab347b3e9f536416 to your computer and use it in GitHub Desktop.
This gist shows an example implementation of how to access the testo 300 Bluetooth API.
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
package de.testo.demo.t300interface.ble; | |
import android.bluetooth.BluetoothAdapter; | |
import android.bluetooth.BluetoothDevice; | |
import android.bluetooth.BluetoothManager; | |
import android.bluetooth.le.BluetoothLeScanner; | |
import android.bluetooth.le.ScanCallback; | |
import android.bluetooth.le.ScanFilter; | |
import android.bluetooth.le.ScanResult; | |
import android.bluetooth.le.ScanSettings; | |
import android.content.Context; | |
import android.os.Handler; | |
import android.os.ParcelUuid; | |
import android.util.Log; | |
import java.util.ArrayList; | |
import java.util.List; | |
public abstract class BluetoothScanHelper { | |
private static final String TAG = "BluetoothScanHelper"; | |
protected BluetoothAdapter m_bluetoothAdapter = null; | |
protected BluetoothLeScanner m_bluetoothScanner = null; | |
protected String m_nameFilter = null; | |
private boolean scanRunning = false; | |
private Handler handler = new Handler(); | |
ScanCallback m_scanCallback = new ScanCallback() { | |
@Override | |
public void onScanResult(int callbackType, ScanResult result) { | |
super.onScanResult(callbackType, result); | |
Log.d(TAG, "onScanResult: " + callbackType + " result: " + result.toString()); | |
if(callbackType != ScanSettings.CALLBACK_TYPE_MATCH_LOST) { | |
handleScanResult(result); | |
} | |
} | |
@Override | |
public void onBatchScanResults(List<ScanResult> results) { | |
super.onBatchScanResults(results); | |
Log.d(TAG, "onBatchScanResults: " + results.size()); | |
for (ScanResult result : results) { | |
handleScanResult(result); | |
} | |
} | |
@Override | |
public void onScanFailed(int errorCode) { | |
super.onScanFailed(errorCode); | |
Log.e(TAG, "Scan failed:" + errorCode); | |
} | |
}; | |
public BluetoothScanHelper(Context context) { | |
this("testo 300", context); | |
} | |
public BluetoothScanHelper(String nameFilter, Context context) { | |
Log.d(TAG, "Initializing BluetoothScanHelper"); | |
m_nameFilter = nameFilter; | |
BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); | |
if(manager != null) { | |
m_bluetoothAdapter = manager.getAdapter(); | |
m_bluetoothScanner = m_bluetoothAdapter.getBluetoothLeScanner(); | |
} | |
} | |
public void startScan() { | |
if(m_bluetoothScanner != null) { | |
this.scanRunning = true; | |
Log.d(TAG, "Starting Bluetooth scan"); | |
ArrayList<ScanFilter> filters = new ArrayList<>(); | |
filters.add(new ScanFilter.Builder().setServiceUuid(new ParcelUuid(TestoGattDefinitions.UUID_MEASDATA_SERVICE)).build()); | |
filters.add(new ScanFilter.Builder().setServiceUuid(new ParcelUuid(TestoGattDefinitions.UUID_CONTROL_SERVICE)).build()); | |
ScanSettings settings = new ScanSettings.Builder() | |
.setScanMode(ScanSettings.SCAN_MODE_BALANCED) | |
.setReportDelay(0) | |
.build(); | |
m_bluetoothScanner.startScan(filters, settings, m_scanCallback); | |
handler.postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
stopScan(); | |
} | |
}, 10000); | |
} | |
} | |
public void stopScan() { | |
if(scanRunning) { | |
Log.d(TAG, "Stopping Bluetooth scan"); | |
m_bluetoothScanner.stopScan(m_scanCallback); | |
scanRunning = false; | |
} | |
} | |
protected void handleScanResult(ScanResult scanResult) { | |
Log.d(TAG, "handleScanResult: " + scanResult.toString()); | |
if(scanResult.isConnectable()) { | |
Log.d(TAG, "handleScanResult: isConnectable() true"); | |
BluetoothDevice device = scanResult.getDevice(); | |
Log.d(TAG, "+--------------------------------------------------"); | |
Log.d(TAG, "| Device name: " + device.getName()); | |
Log.d(TAG, "| Device address: " + device.getAddress()); | |
Log.d(TAG, "| Device type: " + device.getType()); | |
Log.d(TAG, "| Bond state: " + device.getBondState()); | |
Log.d(TAG, "+--------------------------------------------------"); | |
if(device.getName().startsWith(m_nameFilter)) { | |
Log.d(TAG, "Found device with name: " + device.getName()); | |
bleDeviceFound(device); | |
} | |
} | |
} | |
abstract public void bleDeviceFound(BluetoothDevice device); | |
} |
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
package de.testo.demo.t300interface.ble; | |
import android.bluetooth.BluetoothDevice; | |
import android.bluetooth.BluetoothGatt; | |
import android.bluetooth.BluetoothGattCallback; | |
import android.bluetooth.BluetoothGattCharacteristic; | |
import android.bluetooth.BluetoothGattService; | |
import android.content.Context; | |
import android.util.Log; | |
import android.util.SparseArray; | |
import java.nio.charset.StandardCharsets; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.UUID; | |
import de.testo.demo.t300interface.json.JsonProcessor; | |
import de.testo.demo.t300interface.device.TestoDevice; | |
public class TestoBluetoothDevice extends TestoDevice { | |
private static final String TAG = TestoBluetoothDevice.class.getSimpleName(); | |
private BluetoothGatt bluetoothGatt = null; | |
private BluetoothGattService measdataService = null; | |
private List<UUID> jsonDataCharacteristics = new ArrayList<>( | |
Arrays.asList( | |
TestoGattDefinitions.UUID_JSON_MEASDATA01_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA02_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA03_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA04_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA05_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA06_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA07_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA08_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA09_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA10_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA11_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA12_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA13_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA14_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA15_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA16_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA17_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA18_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA19_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA20_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA21_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA22_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA23_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA24_CHARACTERISTIC, | |
TestoGattDefinitions.UUID_JSON_MEASDATA25_CHARACTERISTIC | |
) | |
); | |
private SparseArray<String> jsonResponseArray = new SparseArray<>(); | |
private int activeJsonCharacteristics = 0; | |
private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { | |
@Override | |
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { | |
if(newState == BluetoothGatt.STATE_CONNECTED) { | |
gatt.requestMtu(512); | |
} | |
} | |
@Override | |
public void onServicesDiscovered(BluetoothGatt gatt, int status) { | |
measdataService = gatt.getService(TestoGattDefinitions.UUID_MEASDATA_SERVICE); | |
gatt.readCharacteristic(measdataService.getCharacteristic(TestoGattDefinitions.UUID_JSON_MEASDATA_META_CHARACTERISTIC)); | |
} | |
@Override | |
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { | |
if(characteristic.getUuid().equals(TestoGattDefinitions.UUID_JSON_MEASDATA_META_CHARACTERISTIC)) { | |
activeJsonCharacteristics = Integer.parseInt(characteristic.getStringValue(0)); | |
Log.d(TAG, "activeJsonCharacteristics: " + activeJsonCharacteristics); | |
Log.d(TAG, "Reading characteristic: " + jsonDataCharacteristics.get(0).toString()); | |
gatt.readCharacteristic(measdataService.getCharacteristic(jsonDataCharacteristics.get(0))); | |
} | |
else if(jsonDataCharacteristics.contains(characteristic.getUuid())) { | |
jsonResponseArray.put(jsonDataCharacteristics.indexOf(characteristic.getUuid()), new String(characteristic.getValue(), StandardCharsets.UTF_8)); | |
Log.d(TAG, "Successful Read for characteristic " + characteristic.getUuid().toString()); | |
int nextIndex = jsonDataCharacteristics.indexOf(characteristic.getUuid()) + 1; | |
if(nextIndex < activeJsonCharacteristics) { | |
gatt.readCharacteristic(measdataService.getCharacteristic(jsonDataCharacteristics.get(nextIndex))); | |
Log.d(TAG, "Reading characteristic: " + jsonDataCharacteristics.get(nextIndex).toString()); | |
} | |
} | |
if(jsonResponseArray.size() != 0 | |
&& activeJsonCharacteristics != 0 | |
&& jsonResponseArray.size() == activeJsonCharacteristics | |
&& deviceCallback != null) { | |
String jsonInput; | |
StringBuilder jsonInputBuilder = new StringBuilder(); | |
for(int i = 0; i < jsonResponseArray.size(); i++) { | |
jsonInputBuilder.append(jsonResponseArray.get(i)); | |
} | |
jsonInput = jsonInputBuilder.toString(); | |
JsonProcessor jsonProcessor = new JsonProcessor(); | |
jsonProcessor.setJsonInput(jsonInput.toString()); | |
jsonProcessor.parseJson(); | |
measurementList = jsonProcessor.getMeasurementList(); | |
title = jsonProcessor.getTitle(); | |
if(deviceCallback != null) { | |
deviceCallback.onDataFetchedFromDevice(TestoBluetoothDevice.this); | |
} | |
} | |
} | |
@Override | |
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { | |
Log.d(TAG, "MTU changed: " + mtu + " (Status: " + status + ")"); | |
gatt.discoverServices(); | |
} | |
}; | |
/** | |
* Creates a new instance from a given BluetoothDevice | |
* | |
* @param bluetoothDevice | |
* @return | |
*/ | |
public static TestoDevice fromBluetoothDevice(BluetoothDevice bluetoothDevice) { | |
String serial = bluetoothDevice.getName().replace("testo 300 ", ""); | |
return new TestoBluetoothDevice("testo 300", serial, bluetoothDevice); | |
} | |
private TestoBluetoothDevice(String deviceName, String serialNumber, BluetoothDevice device) { | |
this.deviceName = deviceName; | |
this.serialNumber = serialNumber; | |
this.bleDevice = device; | |
this.type = TYPE_BLE; | |
} | |
@Override | |
public void connect(Context context) { | |
this.bluetoothGatt = this.bleDevice.connectGatt(context, false, bluetoothGattCallback); | |
} | |
@Override | |
public void fetchData() { | |
if(measdataService != null) { | |
jsonResponseArray.clear(); | |
activeJsonCharacteristics = 0; | |
bluetoothGatt.readCharacteristic(measdataService.getCharacteristic(TestoGattDefinitions.UUID_JSON_MEASDATA_META_CHARACTERISTIC)); | |
} | |
} | |
@Override | |
public void toggleMeasurement() { | |
if(bluetoothGatt != null) { | |
BluetoothGattCharacteristic characteristic = bluetoothGatt.getService(TestoGattDefinitions.UUID_CONTROL_SERVICE) | |
.getCharacteristic(TestoGattDefinitions.UUID_CONTROL_COMMAND_CHARACTERISTIC); | |
characteristic.setValue("TOGGLE_MEASUREMENT"); | |
bluetoothGatt.writeCharacteristic(characteristic); | |
Log.d(TAG, "Write value \"TOGGLE_MEASUREMENT\" to " + TestoGattDefinitions.UUID_CONTROL_STATUS_CHARACTERISTIC.toString()); | |
} | |
} | |
} |
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
package de.testo.demo.t300interface.ble; | |
import java.util.UUID; | |
public abstract class TestoGattDefinitions { | |
public static final UUID UUID_MEASDATA_SERVICE = UUID.fromString("00002000-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA_META_CHARACTERISTIC = UUID.fromString("00003000-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA01_CHARACTERISTIC = UUID.fromString("00003001-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA02_CHARACTERISTIC = UUID.fromString("00003002-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA03_CHARACTERISTIC = UUID.fromString("00003003-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA04_CHARACTERISTIC = UUID.fromString("00003004-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA05_CHARACTERISTIC = UUID.fromString("00003005-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA06_CHARACTERISTIC = UUID.fromString("00003006-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA07_CHARACTERISTIC = UUID.fromString("00003007-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA08_CHARACTERISTIC = UUID.fromString("00003008-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA09_CHARACTERISTIC = UUID.fromString("00003009-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA10_CHARACTERISTIC = UUID.fromString("0000300A-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA11_CHARACTERISTIC = UUID.fromString("0000300B-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA12_CHARACTERISTIC = UUID.fromString("0000300C-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA13_CHARACTERISTIC = UUID.fromString("0000300D-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA14_CHARACTERISTIC = UUID.fromString("0000300E-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA15_CHARACTERISTIC = UUID.fromString("0000300F-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA16_CHARACTERISTIC = UUID.fromString("00003010-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA17_CHARACTERISTIC = UUID.fromString("00003011-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA18_CHARACTERISTIC = UUID.fromString("00003012-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA19_CHARACTERISTIC = UUID.fromString("00003013-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA20_CHARACTERISTIC = UUID.fromString("00003014-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA21_CHARACTERISTIC = UUID.fromString("00003015-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA22_CHARACTERISTIC = UUID.fromString("00003016-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA23_CHARACTERISTIC = UUID.fromString("00003017-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA24_CHARACTERISTIC = UUID.fromString("00003018-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_JSON_MEASDATA25_CHARACTERISTIC = UUID.fromString("00003019-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_CONTROL_SERVICE = UUID.fromString("00002001-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_CONTROL_COMMAND_CHARACTERISTIC = UUID.fromString("00003100-0000-1000-8000-00805f9b34fb"); | |
public static final UUID UUID_CONTROL_STATUS_CHARACTERISTIC = UUID.fromString("00003101-0000-1000-8000-00805f9b34fb"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment