none
Unstable bluetooth connection - even using external dongle RRS feed

  • Question

  • Dear all,

    I am using my RaspberryPis (v3) running the latest stable Windows IoT Core version (v.10.0.17763.737) to retrieve data and control my bluetooth thermostats. I am struggling quite a long time with the stability of the bluetooth connection. Some months ago I switched all my nodes to external dongles, which improved the situation, but it is still far away from being stable.

    After a certain time (varies from minutes to days) the bluetooth connection stops working. I already implemented a powershell script to check for such situations and fire a "devcon restart *USB*" command. This helps, but only in about 50% of all failures. If it does not solve the situation, I have to reboot the node. However, this is not satisfying, because from time to time the nodes freeze while booting and I made the experience that doing too many reboots will reduce the lifetime of the micro sd card.

    After some hours of analysis I found out that the bluetooth service could be the problem. Before the connection crashes I can easily restart the bluetooth service using powershell. After the problem occured, this is not possible anymore. The service restart hangs up and the status of the service says it is pending for restart or something like this.

    Do you guys made the same experience? Or is my bluetooth connection implementation too bad? I attached the function for you to have a look:

     private async Task Connect()
            {
                try
                {
                    int count = 0;
                    do
                    {
                        count++;
                        if (count > 10)
                        {
                            m_IsInitialized = false;
                            //throw new Exception("More than 10 tries have not been successfull for connecting with thermostat module. Stopping.");
                        }
                        m_IsInitialized = false;
    
                        m_Device = await BluetoothLEDevice.FromIdAsync(m_DeviceID);
                        if (m_Device == null)
                        {
                            throw new Exception("Device was not found.");
                        }
    
                        m_Characteristics = new Dictionary<ushort, GattCharacteristic>();
                        GattDeviceServicesResult gattServices = await m_Device.GetGattServicesAsync();
                        foreach (GattDeviceService service in gattServices.Services)
                        {
                            try
                            {
                                GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();
                                IReadOnlyList<GattCharacteristic> characteristics = characteristicsResult.Characteristics;
                                foreach (GattCharacteristic characteristic in characteristics)
                                {
                                    try
                                    {
                                        m_Characteristics.Add(characteristic.AttributeHandle, characteristic);
                                        GattCharacteristicProperties properties = characteristic.CharacteristicProperties;
                                        if (properties.HasFlag(GattCharacteristicProperties.Notify))
                                        {
                                            try
                                            {
                                                GattCommunicationStatus status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                                                if (status == GattCommunicationStatus.Success)
                                                {
                                                    characteristic.ValueChanged += Characteristic_ValueChanged;
                                                    m_IsInitialized = true;
                                                    //Logger.ServiceLog(string.Format("Thermostat has been initialized successfully ({0} tries).", count));
                                                    return;
                                                }
                                            }
                                            catch (Exception ex4)
                                            {
                                                throw new Exception("4: GattCommunicationStatus: " + ex4.Message + "\nStackTrace: " + ex4.StackTrace);
                                            }
                                        }
                                    }
                                    catch (Exception ex3)
                                    {
                                        throw new Exception("3: GattCharacteristic: " + ex3.Message + "\nStackTrace: " + ex3.StackTrace);
                                    }
                                }
                            }
                            catch (Exception ex2)
                            {
                                throw new Exception("2: GattDeviceService: " + ex2.Message + "\nStackTrace: " + ex2.StackTrace);
                            }
                        }
                        //Logger.ServiceLog(string.Format("Thermostat:Connect: Unsuccessful try: {0}", count));
                        await Task.Delay(1 * 60 * 1000);
                    }
                    while (!m_IsInitialized);
                }
                catch (Exception ex)
                {
                    Logger.ServiceLog("1: Thermostat.cs Connect", ex);
                }
            }

    As you see, the code is full of debugging helps, but no exception is raised at all when the connectivity collapses. I am really looking forward to any help, because after months of struggeling I would really prefer getting to a stable solution without any hacks or workarounds.

    Thanks for all your help :-)

    Sunday, September 29, 2019 11:35 AM

All replies

  • Hello RoRoMo,

    You might try to use BluetoothLEDevice.GattServicesChanged to refresh the list of services and re-initialize the services on the device if they are gone.

    The reason of the service  hangs up  when restarting may be caused some characteristics is not disposed in the service. You might also try to following code to dispose the servce. This code is based on BluetoothLE sample

            private async Task<bool> ClearBluetoothLEDeviceAsync()
            {
                ...
    
                foreach (var ser in ServiceCollection)
                {
                    ser.service?.Dispose();
                }
    
                bluetoothLeDevice?.Dispose();
                bluetoothLeDevice = null;
                return true;
            }

    In addition, I'm confused about following code in your post. m_IsInitialized will set as false No matter what value of count.

                        count++;
                        if (count > 10)
                        {
                            m_IsInitialized = false;
                            //throw new Exception("More than 10 tries have not been successfull for connecting with thermostat module. Stopping.");
                        }
                        m_IsInitialized = false;

    BTW, could you please tell me if you set the device in power saving mode?

    Best Regards,

    Michael


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Monday, September 30, 2019 5:47 AM
    Moderator
  • Dear Michael,

    thank you very much for your reply.

    You are absolutely right. As i commented the exception after more than 10 tries, m_IsInitialized will always be set to false. However, if the exception would be thrown the assignment in the if clause would make sense.

    I changed the following line 

    m_Characteristics.Add(characteristic.AttributeHandle, characteristic);

    to

    if (m_Characteristics.ContainsKey(characteristic.AttributeHandle)) { m_Characteristics[characteristic.AttributeHandle].Service.Dispose(); m_Characteristics.Remove(characteristic.AttributeHandle); }

    m_Characteristics.Add(characteristic.AttributeHandle, characteristic);

    and also added the service disposing in my disconnect function

            public void Disconnect()
            {
                try
                {
                    if (m_Characteristics != null)
                    {
                        foreach (GattCharacteristic characteristic in m_Characteristics.Values)
                        {
                            characteristic.Service?.Dispose();
                        }
                        m_Characteristics.Clear();
                    }
                    if (m_Device != null)
                    {
                        m_Device?.Dispose();
                        m_Device = null;
                    }
                    m_IsInitialized = false;
                }
                catch (Exception ex)
                {
                    Logger.ServiceLog("Thermostat.cs Disconnect", ex);
                }
            }

    which will be also called in the outermost exception handler of the connect method.

    I will have to evaluate this changes for some time and I am really excited to see my log files.

    According your last question: I dont know how to set Windows IoT Core to run in energy saving mode? Also, I dont think my bluetooth device supports such a mode. So, the answer is probably "No, no device is running in energy saving mode".

    Thank you once again for your time. I will have a look at the effects :-)


    • Edited by RoRoMo Monday, September 30, 2019 7:52 PM
    Monday, September 30, 2019 7:51 PM