Reverse Engineering iTag – A Bluetooth Low Energy Button

Couple of weeks back I bought a few iTags. These are simple BLE buttons. They have a small led, a button and a buzzer. CR2032 – a 3v coin cell battery powers it. Since they are Bluetooth Low Energy devices, a single cell can power them for years. It’s easy to change batteries if they run out of power. Bought individually they cost about ₹200 but on AliBaba you can buy a dozen for ₹1500. They are usually used with phones as an extra remote button or as a leash for key chain. I wanted to use them as a remote button with an App I was building. Hence the reverse engineering.

I began with installing nRF Connect android App. nRF Connect is a BLE Swiss army knife. You can scan, advertise and explore BLE devices with it. You can also connect and communicate with them.

<server-configuration name="iTag">
<!-- BATTERY_SERVICE -->
   <service uuid="0000180f-0000-1000-8000-00805f9b34fb">
      <characteristic uuid="00002a19-0000-1000-8000-00805f9b34fb">
         <descriptor configure="CCCD"/>
         <permission name="READ"/>
         <property name="READ"/>
         <property name="NOTIFY"/>
      </characteristic>
   </service>
   <!-- IMMEDIATE ALERT SERVICE -->
   <service uuid="00001802-0000-1000-8000-00805f9b34fb">
      <characteristic uuid="00002a06-0000-1000-8000-00805f9b34fb">
         <descriptor configure="CCCD"/>
         <permission name="WRITE"/>
         <property name="WRITE"/>
         <property name="WRITE_WITHOUT_RESPONSE"/>
         <property name="NOTIFY"/>
      </characteristic>
   </service>
   <!-- SIMPLE KEY OR BUTTON SERVICE -->
   <service uuid="0000ffe0-0000-1000-8000-00805f9b34fb">
      <characteristic uuid="0000ffe1-0000-1000-8000-00805f9b34fb">
         <descriptor configure="CCCD"/>
         <permission name="READ"/>
         <property name="READ"/>
         <property name="NOTIFY"/>
      </characteristic>
   </service>
</server-configuration>

Once you connect to the iTag using nRF connect, you can explore the services and characteristics. You can also press the button on iTag to see which characteristic changes. I have the XML above which is the copy of ITag services and characteristics. Its copied using nRF connect. You can see it supports two standard services Battery service and Immediate alert service. They are very well-defined and works as defined.

The third one which is a custom service is the interesting one. It is attached to the button. It sends a notification when the button is clicked. On a client (Eg: Mobile app) you can subscribe to notification on this characteristics. You will get notified every time the button gets clicked.

Play store has many apps that can be used with iTags. They provide options like taking a selfie using the button etc. There are other apps which allow you to attach events to tasker app. I found an open source app called ITracing2. This one is the most versatile app that allows you to send events to other apps or internet. The app code is clean and very readable. Since I was studying the protocol, I took time to read code and fixed a bug while I was there. Hence this is my recommended app :) I use this app in two ways. The diagram clearly shows the flow of event. You can set up these flows the Itracing App. Itracing App also provides the feature of double-click. Two successive clicks from iTag button within a preset time period is a double-click. I have this double-click period set as 300ms. You can change this period. So if I click the button twice within 300ms then its a double-click else single click. That gives an extra event for us to play with.

Other than these generic app setups. If you are an app developer then you can integrate this feature into your own app. Almost every iTag manufacturer now uses characteristics 0000ffe1-0000-1000-8000-00805f9b34fb to send button click. It’s almost a standard now. So if your app needs an external button feature then this is an option.

On Android its super simple. Enable notification of the simple key service and characteristics.

//Define UUID
public static final UUID FIND_ME_SERVICE = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
public static final UUID FIND_ME_CHARACTERISTIC = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb");

//once you discovered services, enable notificaton
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
//....
//....
for (BluetoothGattService service : gatt.getServices()) {
  if (FIND_ME_SERVICE.equals(service.getUuid())) {
        if (!service.getCharacteristics().isEmpty()) {
            buttonCharacteristic = service.getCharacteristics().get(0);
            setCharacteristicNotification(gatt, buttonCharacteristic, true);
        }
  }
}
//....
//....
}//end of onServicesDiscovered


//enable notifcations by setting the respective config flag
private void setCharacteristicNotification(BluetoothGatt bluetoothgatt, BluetoothGattCharacteristic bluetoothgattcharacteristic, boolean flag) {
	//enable notification
    bluetoothgatt.setCharacteristicNotification(bluetoothgattcharacteristic, flag);
    if (FIND_ME_CHARACTERISTIC.equals(bluetoothgattcharacteristic.getUuid())) {
        BluetoothGattDescriptor descriptor = bluetoothgattcharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
        if (descriptor != null) {
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            bluetoothgatt.writeDescriptor(descriptor);
        }
    }
}



//when the remote notification gets changed, call back gets called. 
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
//Do whatever you want to do here
}

if you are react native fan its equally easy using react-native-ble-manager

const FIND_ME_SERVICE = "0000ffe0-0000-1000-8000-00805f9b34fb";
const FIND_ME_CHARACTERISTIC = "0000ffe1-0000-1000-8000-00805f9b34fb";

constructor(){
    //......
    //register all other handlers	
    //this is what gets called when the value changes or notification comes in
    this.handleUpdateValueForCharacteristic = this.handleUpdateValueForCharacteristic.bind(this);
    //......
}

//register for notification
BleManager.startNotification(peripheral, FIND_ME_SERVICE, FIND_ME_CHARACTERISTIC).then(() => {
	console.log('Notification started');
}).catch((error) => {
  console.log('Notification error', error);
  reject(error);
});


//Handle when the notification comes in
handleUpdateValueForCharacteristic(data) {
	console.log('Received '+ data.value + ' from ' + data.peripheral + ' characteristic ' + data.characteristic);
	if(data.characteristic == FIND_ME_CHARACTERISTIC ){
	  //do what you want to do when button is pressed
	} 
}

Let me know if you have any questions or used the button in an innovative way. I would love to hear.

A note about Privacy; These low-cost iTags have a hard-coded mac address. Hence they can be tracked quite easily. This is something that you need to keep in mind. I will write about BLE privacy issues later.

You may also like...

1 Response

  1. Andrew says:

    I want to use mine as a keyfinder, but the problem is, when it goes out of range, it starts beeping, which is annoying. It also has a power saving mode that shuts it down if it isn’t connected to anything.

    Ideally, my plan would be to reprogram it to disable the power saving mode, so that I can connect to the device only whenever I lose it.

Leave a Reply

Your email address will not be published. Required fields are marked *