Unity-Android-Bluetooth-Low-Energy icon indicating copy to clipboard operation
Unity-Android-Bluetooth-Low-Energy copied to clipboard

Subscription has a problem recognizing messages.

Open MichauCorp opened this issue 11 months ago • 3 comments

Hello, im exepriencing some issues in making the subscription work with my arduino.

I have an arduino sending incremental messages every second: "hello - 1" , "hello - 2" , "hello - 3" , etc...

I wrote a small ConnectionManager script and when i tried using the subscribe to characteristic command, it either didnt work at all, or didnt invoke the "CharacteristicChanged" whenever a message was recieved.

the thing is, the BleManager does recieve and log the messages live, and when i try using the ReadFromCharacteristic command to read "manually", it does work.

I might be missing something basic and if it will help ill share the code, but for now i couldnt get it to work so I wanted to ask here for assistance.

thanks in advance :)

MichauCorp avatar Jan 22 '25 08:01 MichauCorp

Can you attach your ConnectionManager class. I'd like to take a look.

paulhayes avatar Jan 22 '25 09:01 paulhayes

here is the current version:

using UnityEngine;
using Android.BLE;
using Android.BLE.Commands;
using TMPro;
using System.Text;

public class BLEConnectionManager : MonoBehaviour
{
    public TextMeshProUGUI messageText;
    public bool read = true;
    public bool write = false;
    public bool subscribe = false;

    [Header("BLE Settings")]
    public string targetDeviceName = "BLE messenger"; // Name of your Arduino BLE device
    public string messageServiceUuid = "19B10000-E8F2-537E-4F6C-D104768A1214"; // your service UUID
    public string messageCharacteristicUuid = "19B10001-E8F2-537E-4F6C-D104768A1214"; // your characteristic UUID

    private string targetDeviceAddress = null;
    private bool isConnected = false;
    private DiscoverDevices discoverCommand;
    private ConnectToDevice connectCommand;
    private SubscribeToCharacteristic subscribeCommand;
    private ReadFromCharacteristic readCommand;
    private WriteToCharacteristic writeCommand;

    private void Start()
    {
        // Ensure the BLE Manager is initialized
        if (!BleManager.IsInitialized)
        {
            BleManager.Instance.Initialize();
        }

        // Start scanning for devices
        Debug.Log("Starting BLE device discovery...");
        BleManager.Instance.QueueCommand(discoverCommand = new DiscoverDevices(OnDeviceDiscovered, OnDiscoveryFinished));
    }

    private void OnDeviceDiscovered(string deviceAddress, string deviceName)
    {
        Debug.Log($"Discovered Device: {deviceName} - {deviceAddress}");

        // Check if the discovered device matches the target device name
        if (deviceName == targetDeviceName)
        {
            Debug.Log($"Target device found: {deviceName}");
            targetDeviceAddress = deviceAddress;

            // Stop scanning and connect to the device
            discoverCommand.End();
            ConnectToDevice();
        }
    }

    private void OnDiscoveryFinished()
    {
        Debug.Log("Device discovery finished.");
        if (targetDeviceAddress == null)
        {
            Debug.LogWarning("Target device not found during discovery.");
        }
    }

    private void ConnectToDevice()
    {
        if (targetDeviceAddress == null)
        {
            Debug.LogError("Target device address is null. Cannot connect.");
            return;
        }

        Debug.Log($"Connecting to device: {targetDeviceName} - {targetDeviceAddress}");

        // Create the ConnectToDevice command and use it
        connectCommand = new ConnectToDevice(targetDeviceAddress, OnDeviceConnected, OnDeviceDisconnected);
        BleManager.Instance.QueueCommand(connectCommand);
    }

    private void OnDeviceConnected(string deviceAddress)
    {
        if (deviceAddress == targetDeviceAddress)
        {
            Debug.Log($"Connected to device: {targetDeviceName} - {deviceAddress}");
            isConnected = true;

            if (read)
            {
                // Start periodic reading
                InvokeRepeating(nameof(ReadFromCharacteristic), 1f, 1f); // Start reading every second
            }

            if (write)
            {
                // Start periodic writing
                InvokeRepeating(nameof(WriteTimeSinceStart), 1f, 1f);
            }

            if (subscribe)
            {
                // Subscribe to the characteristic after connecting
                SubscribeToCharacteristic();
            }
        }
    }

    private void ReadFromCharacteristic()
    {
        if (!isConnected)
        {
            Debug.LogWarning("Device not connected. Skipping read.");
            return;
        }

        readCommand = new ReadFromCharacteristic(
            targetDeviceAddress,
            messageServiceUuid,
            messageCharacteristicUuid,
            DecodeMessage,
            true
        );

        BleManager.Instance.QueueCommand(readCommand);
    }

    private void DecodeMessage(byte[] value)
    {
        string message = System.Text.Encoding.UTF8.GetString(value);
        Debug.Log($"Decoded message: {message}");
        messageText.text = message;
    }
    private void WriteToCharacteristic(string data)
    {
        if (!isConnected)
        {
            Debug.LogWarning("Device not connected. Cannot write.");
            return;
        }

        // Encode the data in Base64
        string base64EncodedData = Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
        //Debug.Log($"Writing Base64-encoded data: {base64EncodedData}");

        writeCommand = new WriteToCharacteristic(
            targetDeviceAddress,
            messageServiceUuid,
            messageCharacteristicUuid,
            base64EncodedData,
            true);

        BleManager.Instance.QueueCommand(writeCommand);
        Debug.Log($"Write command queued, sending message: {data}");
    }

    private void SubscribeToCharacteristic()
    {
        if (string.IsNullOrEmpty(messageServiceUuid) || string.IsNullOrEmpty(messageCharacteristicUuid))
        {
            Debug.LogError("Service UUID or Characteristic UUID is not set. Cannot subscribe.");
            return;
        }

        Debug.Log($"Subscribing to characteristic: {messageCharacteristicUuid} in service: {messageServiceUuid}");

        // Create the SubscribeToCharacteristic command
        subscribeCommand = new SubscribeToCharacteristic(
            targetDeviceAddress,
            messageServiceUuid,
            messageCharacteristicUuid,
            OnCharacteristicChanged,
            customGatt: true
        );
        BleManager.Instance.QueueCommand(subscribeCommand);
        Debug.Log("Subscription command queued.");
    }

    private void WriteTimeSinceStart()
    {
        WriteToCharacteristic("Time elapsed since app started: " + Time.time.ToString());
    }


    private void OnCharacteristicChanged(byte[] value)
    {
        Debug.Log($"Raw data received: {value}");

        string message = System.Text.Encoding.UTF8.GetString(value);
        Debug.Log($"Characteristic value changed: {message}");

        // Process the incoming message from the BLE device here
    }

    private void OnDeviceDisconnected(string deviceAddress)
    {
        if (deviceAddress == targetDeviceAddress)
        {
            Debug.LogWarning($"Disconnected from device: {deviceAddress}");
            isConnected = false;

            // Stop periodic reading
            CancelInvoke(nameof(ReadFromCharacteristic));
        }
    }

    private void OnDestroy()
    {
        // Clean up resources on destruction
        if (isConnected && connectCommand != null)
        {
            Debug.Log("Disconnecting from device...");
            connectCommand.Disconnect(); // Use Disconnect from ConnectToDevice
        }

        // Stop periodic reading
        CancelInvoke(nameof(ReadFromCharacteristic));
    }
}

MichauCorp avatar Jan 22 '25 14:01 MichauCorp

for me the issue was the ids are caps vs non caps

                if (CustomGatt)
                {
                    if (string.Equals(obj.Device, DeviceAddress, StringComparison.OrdinalIgnoreCase) &&
                        string.Equals(obj.Service, Service, StringComparison.OrdinalIgnoreCase) &&
                        string.Equals(obj.Characteristic, Characteristic, StringComparison.OrdinalIgnoreCase))
                    {
                        
                        OnCharacteristicChanged?.Invoke(obj.GetByteMessage());
                    }
                }

jeffgenexr avatar Apr 15 '25 01:04 jeffgenexr