• I'm trying to read pulse data from a cheap Aldi/Lidl Bluetooth chest HRM strap (brand Medisana).

    NRF Connect can see the data fine and shows continuous value updates when connected. But I'm having no joy using some of the sample code floating around the forums and API reference on either a Pixl.js (latest 2v04 stable) or Bangle.js. The code I'm using is as follows:

    var device;
    NRF.connect("54:4a:16:52:04:30 public").then(function(d) {
      device = d;
      return d.getPrimaryService("0x180D");
    }).then(function(s) {
      Terminal.println("Service ",s);
      return s.getCharacteristic("0x2A37");
    }).then(function(c) {
      c.on('characteristicvaluechanged', function(event) {
        Terminal.println("-> "+event.target.value);
      });
      return c.startNotifications();
    }).then(function(d) {
      Terminal.println("Waiting for notifications");
    }).catch(function(e) {
      Terminal.println("Something's broken: ", e);
    });
    

    It connects fine and gets through the primary service and characteristic but it never shows any update notifications.

    It also gives the

    Uncaught InternalError: BLE task completed that wasn't scheduled (3/4)
    

    error after a few seconds.

    The Service info is:

    
    Service  BluetoothRemoteGATTService: {
      "uuid": "0x180d",
      "isPrimary": true, "start_handle": 16, "end_handle": 23 }
    
    

    and the Characteristic info is:

    BluetoothRemoteGATTCharacteristic: {
      "uuid": "0x2a37",
      "handle_value": 18, "handle_decl": 17,
      "properties": { "broadcast": false, "read": false, "writeWithoutResponse": false, "write": false,
        "notify": true, "indicate": false, "authenticatedSignedWrites": false }
     }
    

    Any suggestions for things to try?

  • Can you try one of the latest builds from: http://www.espruino.com/binaries/travis/­master/

    BLE task completed that wasn't scheduled (3) refers to the fact it disconnected when it was in the middle of doing task 4 (which was 'Find primary service'). The new firmware should fix that error (it may still disconnect but I believe you'll get a disconnection error code that might help for debugging).

    I'm not sure why it appears to have gone through the promises while the firmware still thinks it's searching for services. Still, it'd be worth trying with the new firmware. If your Bangle.js had the Nodeconf firmware I think that was before this got added.

    edit: just for the curious, BLE task numbers are listed here: https://github.com/espruino/Espruino/blo­b/master/libs/bluetooth/jswrap_bluetooth­.h#L22

  • Thanks Gordon. Just tried latest Pixl.js build. The BLE error ended up being user error. If I don't use the full UUID for the characteristic then it should be 0x2A37 not "0x2A37".

    So errors now gone but still no change notifications.

    Note that a non-changing value can be read fine e.g. Body Sensor Position gives 1 (Chest) correctly with this:

    return s.getCharacteristic(0x2a38);
    

    Just looking at NRF Connect logs, it does gatt.setCharacteristicNotification(). Is that done under the hood in c.on('characteristicvaluechanged' ?

    D 12:33:18.447 gatt.setCharacteristicNotification(00002­a37-0000-1000-8000-00805f9b34fb, true)
    D 12:33:18.448 gatt.writeDescriptor(00002902-0000-1000-­8000-00805f9b34fb, value=0x0100)
    I 12:33:18.514 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
    A 12:33:18.514 "Notifications enabled" sent
    V 12:33:18.519 Notifications enabled for 00002a37-0000-1000-8000-00805f9b34fb
    I 12:33:19.314 Connection parameters updated (interval: 1012.5ms, latency: 0, timeout: 10120ms)
    I 12:33:21.340 Notification received from 00002a37-0000-1000-8000-00805f9b34fb, value: (0x) 00-47
    A 12:33:21.340 "Heart Rate Measurement: 71 bpm,
    

    I found some info that says HRMs specifically need to be told to send updates, so I added:

     return device.getPrimaryService(0x1801);
        }).then(function (s) {
            Terminal.println("Service ", s);
            return s.getCharacteristic(0x2a05);
        }).then(function (c) {
            return c.writeValue(0x0100);
    

    But still no joy.

  • That last code Iposted can't work. NRF Connect is writing to descriptors not characteristics.

  • then it should be 0x2A37 not "0x2A37"

    I thought that might be the issue so I looked at the code, and the string should have worked (https://github.com/espruino/Espruino/blo­b/master/libs/bluetooth/bluetooth_utils.­c#L140)

    NRF Connect is writing to descriptors not characteristics.

    Yes, that's what c.startNotifications() should be doing under the hood. It finds the descriptor and writes to it to enable the notification.

    Are you still getting randomly disconnected? It's possible it is because Espruino and the device can't agree on a connection interval. NRF.connect accepts a second argument of options which corresponds to: http://www.espruino.com/Reference#l_Blue­toothRemoteGATTServer_connect

    You could try setting minInterval to 7.5 and maxInterval to 4000 to give it the max leeway in negotiating speed?

    Not sure what else to suggest without having one here to play with I'm afraid. If you're feeling like diving in then I have an nRF52DK then Nordic have some tools to let you use it with Wireshark to snoop on Bluetooth LE traffic though

  • Thanks Gordon. I'll do more poking around.

    There is something odd tho in UUID handling at the moment. The latest stable Pixl.js firmware running same code gives an error for full UUIDs saying they must only contain hex characters and dashes, when I'm using things like "8d96b002-0002-64c2-0001-9acc4838521c". Only stops giving error if I use short 0xNNNN UUIDs with no quotes.

    Bangle.js not giving that error for the same code.

  • Hi! I'm facing a similar issue on my Bangle Js 2, have you solved the issue?

  • well, "similar" issue may also be something completely different, why not to describe the exact issue you have?

  • The same error is returned when trying to get the primary service of my laptop from bangle js. I implemented a Gattserver solution on my laptop advertsing a costant value (as explained in UWP sample on Microsoft website): the bangle successuflly connects to my laptop but on finding primary services the code run into the same error. I suppose it's not able to find the service even if on scanning BLE devices nearby with relative services it seems to be visible. Here my JS code:

    
    function ReceiveData(d) { 
      g.drawString(d, g.getWidth()/2, g.getHeight()/2); 
    }
    
    
    Bluetooth.on('data', function(d) { 
      g.clear();
      g.setFont("Vector", 10);
      g.setColor(0,255,0);
      setTimeout( () => (g.drawString(Serial.read(), g.getWidth()/2, g.getHeight()/2)), 5000);
      setTimeout( () => (g.drawString('Data received', g.getWidth()/2, g.getHeight()/2)), 2000);
      });
    
    NRF.on('connect', function(addr) {
      g.clear();
      g.setFont("Vector",10);
      g.setColor(255,0,0);
      g.drawString(addr,g.getWidth()/2, g.getHeight()/2);
      g.setFont("Vector",25);
      setTimeout(()=>g.drawString("Connected",­ g.getWidth()/2, g.getHeight()/2), 3000);
      setTimeout(()=>g.clear(),1000); 
      Connect(macaddress);
    });
    
    NRF.on('disconnect', function(reason) {
      g.clear();
      g.setColor(0,0,255);
      g.drawString("Disconnected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=> g.clear(), 1000);
    });
    
    function Scandevices(){
      var devices;
      NRF.findDevices(function(d) {
      devices = d;
      console.log(devices);
      }, {timeout : 2000, filters : [{ manufacturer: "6"}] });
      }
    
    function Connect(){
      NRF.connect(macaddress).then(function(g)­ {
        gatt = g;
        return gatt.startBonding(); 
        }).then(function(service) {
        try{
            console.log(gatt.getSecurityStatus());
            console.log("Connected");
            return gatt.getPrimaryService(serviceUid).catch­(onRejected);
        }
        catch(exception){
          console.log(exception);
        }
          console.log("Service");
          return service.getCharacteristic(characteristcU­id).catch(onRejected);}).then(function(c­haracteristic) {
            //console.log(characteristic);
            //console.log("Got:", JSON.stringify(d.buffer));
            });
    }
    
    function onRejected(event){
      console.log('The code run into a problem: '+ event);
    }
    
    
    
    
    // Code
    
    g.setFontAlign(0,0); 
    g.setFont("Vector",25);
    delay = 5000;
    
    var gatt;
    macaddress = "58:74:96:7c:53:b0" + " private-resolvable";
    serviceUid = 'f150e6c7-0db4-4645-ae74-023c39598372';
    characteristicUid = "b952f9c0-218d-42b6-8ee6-4aab35753922";
    
    Scandevices();
    setTimeout(Connect, delay);
    
    
    
    
    
    
    

    After printing "Connected" the error appears!

  • And the error is "Uncaught InternalError: BLE task completed that wasn't scheduled (3/4)" ?

    I see you are calling it from NRF.on('connect', function(addr) { handler. maybe it will help if you schedule your Connect method a little bit later via setTimeout if you really want to call it at that time? Thing is that there is some communication still in progress right after something connect to the Bangle so it is not a best moment to start connecting to something else, try to wait like 500ms

    And you really want for it to work in a way that anytime something connects to bangle the bangle will immediately try to connect to something else? That's a bit odd.

  • Yes the error is that, but in debugging it return that service is null actually. The C# console application successfully creates a service and the associated characteristic, which is connetable and discoverable, but the bangle seems not able to find the primary service. I even tried to get all the primary services after connecting to the laptop but null object is returned.

    As for the connect event handler, basically what I want to achieve is that whenever something connects to the bangle a message is display on the bangle screen, as it is already doing.

  • This is the part of code running after connection.

    function Connect(){
      NRF.connect(macaddress).then(function(g)­ {
        gatt = g;
        return gatt.startBonding(); 
        }).then(function(service) {
        try{
            console.log(gatt.getSecurityStatus());
            console.log("Connected");
            return setTimeout(() => (gatt.getPrimaryService(serviceUid).catc­h(onRejected)), 2000);
        }
        catch(exception){
          console.log(exception);
        }
          console.log("Service");
          return service.getCharacteristic(characteristcU­id).catch(onRejected);}).then(function(c­haracteristic) {
            console.log(characteristic);
            console.log("Got:", JSON.stringify(d.buffer));
            });
    }
    
    

    and this is what it is returned by the console:

    [
    BluetoothDevice: {

    "id": "5b:93:7d:91:e5:7c private-resolvable",
    "rssi": -39,
    "data": new Uint8Array([2, 1, 26, 3, 3, 10, 24, 17, 7, 114, 131, 89, 57, 60, 2, 116, 174, 69, 70, 180, 13, 199, 230, 80, 241]).buffer,
    "services": [
      "180a",
      "f150e6c7-0db4-4645-ae74-023c39598372"
     ]
    

    }
    ]
    { "connected": true, "encrypted": false, "mitm_protected": false, "bonded": true }
    Connected
    The code run into a problem: Not connected

  • As for the connect event handler, basically what I want to achieve is that whenever something connects to the bangle a message is display on the bangle screen, as it is already doing.

    Yes, but why are you calling Connect from there in the last line?

  • Yeah sorry, the first connect within the .on('Connect') was removed, actually the only one is the last on the bottom.
    Just a question: is the event handler for the 'data' event called each time the Bangle receives something , correct?

    Here is my final code:

    Bluetooth.on('data', function(d) { 
      g.clear();
      g.setFont("Vector", 20);
      g.setColor(0,255,0);
      f = require("Storage").open(name, 'a');
      f.write(d + "\n");
      setTimeout(() => (g.drawString("Data", g.getWidth()/2, g.getHeight()/2)), 1000);
      setTimeout(()=>g.clear(),1500); 
      });
    
    NRF.on('connect', function(addr) {
      g.clear();
      g.setFont("Vector",15);
      g.setColor(255,0,0);
      g.drawString(addr,g.getWidth()/2, g.getHeight()/2);
      g.setFont("Vector",25);
      setTimeout(()=>g.drawString("Connected",­ g.getWidth()/2, g.getHeight()/2), 500);
      setTimeout(()=>g.clear(),1000); 
      E.setConsole(null);
    });
    
    NRF.on('disconnect', function(reason) {
      g.clear();
      g.setColor(0,0,255);
      g.drawString("Disconnected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=> g.clear(), 1000);
    });
    
    // Code
    
    g.setFontAlign(0,0); 
    g.setFont("Vector",25);
    delay = 5000;
    
    name = "MyFile";
    
    setInterval(function(){console.log(E.get­Temperature());}, 1000);
    

    The thing is that when I send something from my laptop, bangle does not seem to receive it.

  • Just a question: is the event handler for the 'data' event called each time the Bangle receives something , correct?

    not exactly. Bluetooth is instance of Serial that works as console. So yes if you send something to Nordic UART RX characteristics it will be received and data event is called just like when Serial or USB serial port receiving some characters.

    If you have your own BLE writable characteristics it is not related to Bluetooth serial object or 'data' event.
    http://www.espruino.com/Reference#l__glo­bal_Bluetooth
    http://www.espruino.com/Reference#l_Seri­al_data

  • Clear, actually my laptop console application is connected to the Nordic UART service, so it should work. Unfortunately, by now, the bangle receives only the first data buffer: when I tried to send it again, no event is triggered.

        internal class Program
        {
            static DeviceInformation _device = null;
            private static string NORDIC_UART_SERVICE = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
            static DataFormat _dataFormat = DataFormat.UTF8;
    
            static GattCommunicationStatus result;
            static GattCharacteristic _characteristic;
            static GattLocalCharacteristic _readcharacteristic;
    
    
            static GattServiceProvider _serviceProvider;
            static Guid _serviceuuid= new Guid("F150E6C7-0DB4-4645-AE74-023C395983­72");
            static Guid _characteristicuuid = new Guid("B952F9C0-218D-42B6-8EE6-4AAB357539­22");
            static GattLocalCharacteristicParameters _characteristicparameter = new GattLocalCharacteristicParameters();
    
            static DataWriter writer = new DataWriter();
    
            static async Task Main(string[] args)
            {
                // Query for extra properties you want returned
                string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
    
                DeviceWatcher deviceWatcher =
                            DeviceInformation.CreateWatcher(
                                    BluetoothLEDevice.GetDeviceSelectorFromP­airingState(false),
                                    requestedProperties,
                                    DeviceInformationKind.AssociationEndpoin­t);
    
                // Register event handlers before starting the watcher.
                // Added, Updated and Removed are required to get all nearby devices
                deviceWatcher.Added += DeviceWatcher_Added;
                deviceWatcher.Updated += DeviceWatcher_Updated;
                deviceWatcher.Removed += DeviceWatcher_Removed;
                
    
                // EnumerationCompleted and Stopped are optional to implement.
                deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
                deviceWatcher.Stopped += DeviceWatcher_Stopped;
    
                // Start the watcher.
                deviceWatcher.Start();
    
                //STARTING CREATING SERVICE
    
                GattServiceProviderResult _result = await GattServiceProvider.CreateAsync(_service­uuid);
                Console.WriteLine("Creating new service");
    
                if (_result.Error == BluetoothError.Success)
                {
                    _serviceProvider = _result.ServiceProvider;
                    Console.WriteLine($"{_result.Error}");
                }
                byte[] value = new byte[] { 0x21 };
    
                _characteristicparameter.WriteProtection­Level = GattProtectionLevel.Plain;
                _characteristicparameter.ReadProtectionL­evel = GattProtectionLevel.Plain;
                _characteristicparameter.StaticValue = value.AsBuffer();
                _characteristicparameter.UserDescription­ = "Read Characteristic";
                _characteristicparameter.CharacteristicP­roperties = GattCharacteristicProperties.Read; 
                
    
                GattLocalCharacteristicResult characteristicResult = await _serviceProvider.Service.CreateCharacter­isticAsync(_characteristicuuid, _characteristicparameter);
    
                if (characteristicResult.Error != BluetoothError.Success)
                {
                    Console.WriteLine("Errore nella creazione della caratteristica di Read");
                    return;
                }
                _readcharacteristic = characteristicResult.Characteristic;
                Console.WriteLine("Characteristic " + _characteristicuuid + " is a " + _readcharacteristic.CharacteristicProper­ties + " characteristic");
                _readcharacteristic.ReadRequested += ReadRequested;
    
                GattServiceProviderAdvertisingParameters­ advParameters = new GattServiceProviderAdvertisingParameters­
                {         
                    IsDiscoverable = true,
                    IsConnectable = true
                };
                
                
                _serviceProvider.StartAdvertising(advPar­ameters);
                Console.WriteLine(_serviceProvider.Adver­tisementStatus.ToString());
                Console.WriteLine("The service started successfully and has " + _serviceProvider.Service.Characteristics­.Count + " characteristics");
    
                while (true)
                {
                    if (_device == null)
                    {
                        Thread.Sleep(200);
                    }
                    else
                    {
                        Console.WriteLine("Press any key to connect to the Bangle. Js");
                        Console.ReadKey();
                        BluetoothLEDevice bluetoothLEDevice = await BluetoothLEDevice.FromIdAsync(_device.Id­);
                        Console.WriteLine("Pairing with the device");
    
                        GattDeviceServicesResult servicesResult = await bluetoothLEDevice.GetGattServicesAsync()­;
    
                        if (servicesResult.Status == GattCommunicationStatus.Success)
                        {
                            Console.WriteLine("Pairing succeed");
                            var services = servicesResult.Services;
                            foreach (var service in services)
                            {
                                Console.WriteLine($"Service: {service.Uuid}");
                                Console.WriteLine("---------------------­--");
    
                                if (service.Uuid.ToString() == NORDIC_UART_SERVICE)
                                {
                                    Console.WriteLine("Connected to NUS Service");
                                    Console.WriteLine("---------------------­-------------");
    
                                    GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();
                                  
                                    if (characteristicsResult.Status == GattCommunicationStatus.Success)
                                    {
                                        var characteristics = characteristicsResult.Characteristics;
                                        foreach (var characteristic in characteristics)
                                        {
                                            Console.WriteLine($"Characteristic {characteristic.Uuid}");
                                            Console.WriteLine("---------------------­-----------");
                                            GattCharacteristicProperties properties = characteristic.CharacteristicProperties;­
    
                                            if (properties.HasFlag(GattCharacteristicPr­operties.Notify))
                                            {
                                                Console.WriteLine("Notify property found");
    
                                                GattCommunicationStatus status = await characteristic.WriteClientCharacteristic­ConfigurationDescriptorAsync(GattClientC­haracteristicConfigurationDescriptorValu­e.Notify);
                                                if (status == GattCommunicationStatus.Success)
                                                {
                                                    Console.WriteLine("Server has been informed of clients interest and has set the client in notify status");
                                                    characteristic.ValueChanged += Characteristic_ValueChanged;
                                                    _characteristic = characteristic;
                                                    
                                                }
                                            }
    
                                            else if (properties.HasFlag(GattCharacteristicPr­operties.Write))
                                            {
                                                Console.WriteLine($"\t \t Characteristic {characteristic.Uuid} has a write property ");
                                                Console.WriteLine("---------------------­----------- ");
                                                
                                                writer.WriteString("Data sent");
                                                                                           
                                                result = await characteristic.WriteValueAsync(writer.De­tachBuffer());
                                                if (result == GattCommunicationStatus.Success)
                                                {
                                                    Console.WriteLine("Data sent");  
                                                }
                                            }
                                            else if (properties.HasFlag(GattCharacteristicPr­operties.WriteWithoutResponse))
                                            {
                                                Console.WriteLine($"\t \t Characteristic {characteristic.Uuid} has a write withoutresponse property ");
                                                Console.WriteLine("---------------------­----------- ");
    
                                            }
                                        }
                                    }
                                }
                            }
                        }
    
                        Console.WriteLine("Press space to disconnect or q to exit");
    
                             
                        if (Console.ReadKey().Key == ConsoleKey.Spacebar)
                        {
                            bluetoothLEDevice.Dispose();
                            return;
                        }
                        else if (Console.ReadKey().Key == ConsoleKey.Q)
                        {
                            Console.WriteLine("Closing");
                            Thread.Sleep(1000);
                            break;
                        }
    
                        if (Console.ReadKey().Key == ConsoleKey.Enter)
                        {
                            writer.WriteByte(0x12);
    
                            result = await _characteristic.WriteValueAsync(writer.D­etachBuffer());
                            if (result == GattCommunicationStatus.Success)
                            {
                                Console.WriteLine("Data sent");
                            }
                        }
    
                    }
                    
                }
    
            }
    
    
  • so this is second place where you are trying to solve the same problem and it is unrelated to the 3 years old topic. also we can hardly help you with your c# code here, so maybe lets continue in your old topic and focus on your javascript code. Gordon suggested to test your JS code by using something verified like nrfconnect android app where you can connect to Bangle and send data to characteristics and verify your JS code works as expected.

    If it works there then it is in your c# code.

    Also if you are into c# you can also test with bleconsole https://github.com/fanoush/BLEConsole it can also read/write to characteristics. subscribing to nordic tx and writing to nordic rx example is here https://gist.github.com/fanoush/c17263e5­7e5ea204de7b2bb01d2a258f#file-bleconsole­-log-L24

  • Sorry for the spam, I didn't mean to change topic. I will go through Gordon's suggestions: I already test the BLE console and I am now working on a custom solution adapted to my needs. Anyway, thank you for your time!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Uncaught InternalError: BLE task completed that wasn't scheduled (3/4)

Posted by Avatar for ConorONeill @ConorONeill

Actions