Android BLE 血糖通知

2023-12-03

我厌倦了使用 Android BLE SDK 与我的 Glucose 设备进行通信。 我需要 UUID 2a18 和 2a34 的 setCharacteristicNotification。我参考Android官方SDK如下:

http://developer.android.com/guide/topics/connectivity/bluetooth-le.html#notification

BluetoothGattCharacteristic charGM = 
mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
    .getCharacteristic(UUID.fromString(BleUuid.CHAR_GLUCOSE_MEASUREMENT_STRING));
mConnGatt.setCharacteristicNotification(charGM, enabled);
BluetoothGattDescriptor descGM = charGM.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descGM.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mConnGatt.writeDescriptor(descGM);

但它甚至无法进入 onCharacteristicChanged 回调。

我的 onCharacteristicChanged 如下:

        public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(getApplicationContext(),"onCharacteristicChanged",Toast.LENGTH_LONG).show();
                setProgressBarIndeterminateVisibility(false);
            };
        });
    }

如果我按如下方式设置电池电量通知,它就会起作用。

BluetoothGattCharacteristic charBarrery = 
    mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_BATTERY))
        .getCharacteristic(UUID.fromString(BleUuid.CHAR_BATTERY_LEVEL_STRING));
mConnGatt.setCharacteristicNotification(charBarrery, enabled);
BluetoothGattDescriptor descBarrery = charBarrery.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
descBarrery.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mConnGatt.writeDescriptor(descBarrery);

我不知道电池和血糖通知有什么不同。

如果有人知道我应该做什么,请帮助我。

额外的:

当我使用电池服务时,我的logcat如下:

07-29 10:28:17.924: D/BluetoothGatt(947): setCharacteristicNotification() - uuid: 00002a19-0000-1000-8000-00805f9b34fb enable: true
07-29 10:28:17.924: D/BluetoothGatt(947): writeDescriptor() - uuid: 00002902-0000-1000-8000-00805f9b34fb
07-29 10:28:18.484: D/BluetoothGatt(947): onDescriptorWrite() - Device=B4:AB:2C:06:9E:F4 UUID=00002a19-0000-1000-8000-00805f9b34fb
07-29 10:28:18.604: D/BluetoothGatt(947): onNotify() - Device=B4:AB:2C:06:9E:F4 UUID=00002a19-0000-1000-8000-00805f9b34fb

但是当我使用 Glucose 时,我的 logcat 丢失了 onNotify(),如下所示:

07-29 10:31:23.729: D/BluetoothGatt(1763): setCharacteristicNotification() - uuid: 00002a18-0000-1000-8000-00805f9b34fb enable: true
07-29 10:31:23.729: D/BluetoothGatt(1763): writeDescriptor() - uuid: 00002902-0000-1000-8000-00805f9b34fb
07-29 10:31:24.324: D/BluetoothGatt(1763): onDescriptorWrite() - Device=B4:AB:2C:06:9E:F4 UUID=00002a18-0000-1000-8000-00805f9b34fb

我不知道为什么 logcat 失去了 onNotify()...

附加(8/4):

感谢您的回复 ! 我尝试启用记录访问控制点特征的指示,但失败了。 我的流程如下:

  1. 启用有关血糖测量特征和血糖测量上下文特征的通知 & 启用记录访问控制点特征的指示

        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        for (BluetoothGattService service : gatt.getServices()) {
            if ((service == null) || (service.getUuid() == null)) {
                continue;
            }
            if (BleUuid.SERVICE_GLUCOSE.equalsIgnoreCase(service
                    .getUuid().toString())) {
    
                BluetoothGattCharacteristic charGM = 
                        mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
                            .getCharacteristic(UUID.fromString(BleUuid.CHAR_GLUCOSE_MEASUREMENT_STRING));
                mConnGatt.setCharacteristicNotification(charGM, enabled);
                BluetoothGattDescriptor descGM = charGM.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
                descGM.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mConnGatt.writeDescriptor(descGM);
    
                BluetoothGattCharacteristic charGMC = 
                    mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
                        .getCharacteristic(UUID.fromString(BleUuid.CHAR_GLUCOSE_MEASUREMENT_CONTEXT_STRING));
                mConnGatt.setCharacteristicNotification(charGMC, enabled);
                BluetoothGattDescriptor descGMC = charGMC.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
                descGMC.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mConnGatt.writeDescriptor(descGMC);
    
                BluetoothGattCharacteristic charRACP = 
                    mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
                        .getCharacteristic(UUID.fromString(BleUuid.CHAR_RECORD_ACCESS_CONTROL_POINT_STRING));
                mConnGatt.setCharacteristicNotification(charRACP, enabled);
                BluetoothGattDescriptor descRACP = charRACP.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
                descRACP.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                mConnGatt.writeDescriptor(descRACP);
    
                BluetoothGattCharacteristic charBarrery = 
                        mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_BATTERY))
                            .getCharacteristic(UUID.fromString(BleUuid.CHAR_BATTERY_LEVEL_STRING));
                mConnGatt.setCharacteristicNotification(charBarrery, enabled);
                BluetoothGattDescriptor descBarrery = charBarrery.getDescriptor(UUID.fromString(BleUuid.CHAR_CLIENT_CHARACTERISTIC_CONFIG_STRING));
                descBarrery.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mConnGatt.writeDescriptor(descBarrery);
    
                runOnUiThread(new Runnable() {
                    public void run() {
                        btnUpdateData.setEnabled(true);
                    };
                });
            }
        }
    };
    
  2. 发送0x0101记录访问控制点

        case R.id.btnUpdateData:
        try{
            //***SEND 0x0101 TO RECORD ACCESS CONTROL POINT   
            BluetoothGattCharacteristic writeRACPchar = 
                    mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
                        .getCharacteristic(UUID.fromString(BleUuid.CHAR_RECORD_ACCESS_CONTROL_POINT_STRING));
            byte[] data = new byte[1];
            data[0] = (byte)0x0101;
            writeRACPchar.setValue(data);
            mConnGatt.writeCharacteristic(writeRACPchar);
        }catch(Exception e){
            e.printStackTrace();
        }
        break;
    
  3. 我的回调函数

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic, 
                                     int status) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }
    
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt,
            BluetoothGattCharacteristic characteristic, int status) {
    };
    
    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
    }
    

&

    private void broadcastUpdate(final String action,
        final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);
        if (BleUuid.CHAR_SERIAL_NUMBEAR_STRING
                .equalsIgnoreCase(characteristic.getUuid().toString())) {
            displayResult(characteristic.getStringValue(0));
        }else if(BleUuid.CHAR_MANUFACTURER_NAME_STRING
                .equalsIgnoreCase(characteristic.getUuid().toString())){
            displayResult(characteristic.getStringValue(0));
        } else if(BleUuid.CHAR_BATTERY_LEVEL_STRING
                .equalsIgnoreCase(characteristic.getUuid().toString())){
            final byte[] data = characteristic.getValue();
            String dataStr = "";
            dataStr = String.format("%02X", data[0]);
            int a = Integer.parseInt(dataStr, 16);
            String result = "battery level: " + Integer.toString(a)+ "%";
            displayResult(result);
        } else {
            // For all other profiles, writes the data formatted in HEX.
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for(byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                displayResult(stringBuilder.toString());
            }
        }
}

&

    private void displayResult(String result){
    adUpdateData.add(result);
    runOnUiThread(new Runnable() {
        public void run() {
            lvUpdateData.setAdapter(adUpdateData);
        };
    });
}

我试图理解“GLS_SPEC”pdf... 我使用了 Nordic Semiconductor 的葡萄糖服务示例应用程序,它可以工作。 我尝试学习如何实现该功能。

我注意到 LogCat 上显示了一些类似“unregisterIRListener() is called”的日志,但我不确定是否与我的问题有关......

谢谢阅读。


葡萄糖和电池服务存在逻辑差异。当您启用电池电量通知时(取决于实施方式),设备通常会立即向您发送电池电量。这就是为什么你在那里得到 onNotify 的原因。当然,在某些实现中,它仅在值更改时或使用其他规则时通知您,但在您的情况下,它看起来像这样。

血糖服务的作用有所不同。在血糖服务中(https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.glucose.xml) 你有 3 个强制性特征。我们在这里跳过葡萄糖功能。 其中之一是血糖测量,您可以在其中收到血糖读数通知。您启用这些通知的实现是正确的,它将起作用。但为了获取通知,您必须使用记录访问控制点特性来请求它们。它允许您获取所有葡萄糖读数,仅最新的,仅第一个,从设备中删除保存的读数等。例如,当您:

  1. 启用有关血糖测量特征的通知(就像您所做的那样)
  2. 启用记录访问控制点特征的指示
  3. 发送费0x0101 = 报告存储的记录|所有记录

您应该会收到有关血糖测量字符的 N 个通知。随后是 RACP 字符上的指示。值为:0x06000101 = “报告存储的记录”的响应 |成功。 如果葡萄糖设备上没有保存任何读数,N 可能为 0。如果您使用 Nordic Semiconductor 的葡萄糖服务示例应用程序,您可以尝试按按钮 0(?) 在板上生成新结果(最多 20 个)并再次请求。

阅读 GLS 文档:https://www.bluetooth.org/en-us/specification/adopted-specifications-> GLS -> PDF 了解有关血糖服务和记录访问控制点格式的更多信息。

EDIT

您写的记录访问控制点值错误。这是工作代码:

case R.id.btnUpdateData:
    try{
        //***SEND 0x0101 TO RECORD ACCESS CONTROL POINT   
        BluetoothGattCharacteristic writeRACPchar = 
                mConnGatt.getService(UUID.fromString(BleUuid.SERVICE_GLUCOSE))
                    .getCharacteristic(UUID.fromString(BleUuid.CHAR_RECORD_ACCESS_CONTROL_POINT_STRING));
        byte[] data = new byte[2];
        data[0] = 0x01; // Report Stored records
        data[1] = 0x01; // All records
        writeRACPchar.setValue(data);

        // or:
        // byte[] data = new byte[2];
        // writeRACPchar.setValue(data);
        // writeRACPchar.setIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1, 0); // Report Stored records
        // writeRACPchar.setIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1, 1); // Read all (offset 1)
        mConnGatt.writeCharacteristic(writeRACPchar);
    }catch(Exception e){
        e.printStackTrace();
    }
    break;

您必须写入 2 个字节,每个字节为 8 个字节,但可以写为 2 位十六进制,例如0xAB 读 0x01。值 0x0101 有 2 个字节,您可能不

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android BLE 血糖通知 的相关文章

  • onActivityResult 中的完成活动不起作用

    我有一对必须同生共死的活动 基本上 AlphaActivity 会做一些工作 然后发送一个意图 startActivityForResult 对于 Beta 活动 当 Beta 活动完成时 我希望它发送一个意图 startActivity
  • Espresso - 检查使用按钮按下意图打开哪个活动?

    是否可以跟踪按下某个按钮后打开了哪个 Activity 我有一个测试 其中当单击 按下按钮时 it 向服务器发送请求 直到发送请求时 它打开一个活动 验证是否执行成功在测试中 我需要检查打开的 Activity 是什么 我的测试示例 检查
  • ACTION_VIEW 的 Intent.createChooser 仅显示默认浏览器

    我正在尝试使用 Intent createChooser 显示应用程序选择器对话框 该对话框将列出用户手机中所有可用的网络浏览器 我正在使用下面的代码 Intent browserIntent new Intent Intent ACTIO
  • android - EditText 打字速度很慢

    我的 EditText 在打字时响应速度很慢 这种滞后现象足以让我找到解决方案 我做了一些研究 发现了一个 SO 线程输入文本时 EditText 滞后 https stackoverflow com questions 6173591 a
  • 未找到 Gradle DSL 方法:“versionCode()”

    构建我的 Android 项目时遇到问题 我使用Grgit https github com ajoberstar grgit填写versionCode and versionName在 gradle 中 一切工作正常 直到我将 Andro
  • 合并两个位图图像(并排)

    任何人都可以帮助将两个位图图像合并为单个位图 在android中 并排 谢谢 尤瓦拉吉 您可以使用Canvas 查看这篇文章 http www jondev net articles Combining 2 Images in Androi
  • 为什么 Kotlin 数据类可以在 Gson 的不可空字段中包含空值?

    在 Kotlin 中你可以创建一个data class data class CountriesResponse val count Int val countries List
  • doInBackground 运行时是否可以停止 asynctask?

    我正在 ActivityB Oncreate 中创建异步任务 在该任务中 我正在运行无限 while 循环doInBackground 当我转到上一个活动并再次回到该活动时 创建了另一个异步任务 我的问题现在是两个无限 while 循环正在
  • 方法断点可能会大大减慢调试速度

    每当向方法声明行添加断点 在 Intellij IDEA 或 Android Studio 中 时 都会出现一个弹出窗口 方法断点可能会大大减慢调试速度 为什么会这样戏剧性地减慢调试速度 是我的问题吗 将断点放在函数的第一行有什么不同 Th
  • Android 手机应用意图

    我想在手机上启动手机应用程序作为意图 我正在使用这个代码 startActivity getPackageManager getLaunchIntentForPackage com android phone 但该函数抛出一个空指针异常 因
  • 6:需要显示BuyFlow UI

    There is a problem when i am click on payWithGoogle Button I am implementing Google Pay in my Android Application and wh
  • Locale.getDefault().getCountry() 返回空字符串

    我正在尝试使用国家 地区代码获取用户语言 例如en US es es 但是当我使用Locale getDefault getCountry 它返回空字符串 虽然它给了我正确的语言Locale getDefault getLanguage N
  • Android 在启动时启动服务,如何在设备重启后重新启动服务类?

    我需要在启动时启动一项服务 我搜索了很多 他们正在谈论广播接收器 由于我是 Android 开发新手 所以我对 Android 上的服务并没有清楚的了解 请提供一些源代码 您的接收者 public class MyReceiver exte
  • 如何覆盖日期选择器的高度和宽度以填充父布局

    我有一个活动包含一个日期选择器 我想设置DatePicker适合屏幕 我试过这个答案 https stackoverflow com questions 6674667 how to customize date pickers width
  • 版本 5 上带有 getBackground().setAlpha 的按钮 - 棒棒糖无法正常工作

    我有这段代码 适用于自 API 14 以来的每个版本 但在 Android 5 0 Lollipop 上无法正常工作 以下是我希望按钮出现的方式 单击按钮1 buttonArrivals getBackground setAlpha 180
  • 点击监听器的公共类

    我的所有 6 项活动中有 7 个按钮 所有 6 个按钮在所有活动中都具有相同的功能 如何为这 6 个按钮执行通用的单击事件侦听器 您可以创建一个实现 View OnClickListener 的新类 如下所示 public class My
  • 如何在android sdk上使用PowerMock

    我想为我的 android 项目编写一些单元测试和仪器测试 然而 我遇到了一个困扰我一段时间的问题 我需要模拟静态方法并伪造返回值来测试项目 经过一些论坛的调查 唯一的方法是使用PowerMock来模拟静态方法 这是我的 gradle 的一
  • gradle-experimental:0.1.0 buildConfigField

    谁知道怎么定义buildConfigField在实验性的 gradle 插件中 android productFlavors create demo applicationId com anthonymandra rawdroid buil
  • Android应用程序kill事件捕获

    我想在我的应用程序被终止时执行一些操作 可以使用哪种方法来实现此目的 我正在开发 Android 5 0 这个问题的关键在于 您必须了解您的申请是否可以收到任何 当您的应用程序在任何情况下被终止时的额外回调 下面的答案是由德文连线 http
  • 在 Android 中更新到 API 26 时,清单合并失败并出现多个错误

    我尝试使用 API 26 更新我的 gradle 安卓工作室2 3 3 但我在编译项目时遇到以下错误 这是我收到的错误的屏幕截图 应用级别build gradle Top level build file where you can add

随机推荐

  • 模板静态成员初始化顺序

    我有一个与此处发布的上一个问题相关的问题静态字段初始化顺序假设我有以下结构 有 2 个静态成员x and y 模板类型本身 include
  • Android - 为我的应用程序创建一个将从网页链接打开的架构

    我正在尝试创建一个类似 myapp somthing anotherthing 的架构 如果网页或任何其他应用程序链接到该架构将打开我的应用程序 我已将其添加到我的 AndroidManifest xml 中以用于我的主要活动
  • BufferGeometry 面材质

    使用 BufferGeometry 时 如何将材质分配给面 是否有类似数组包含相同信息的东西Face materialIndex BufferGeometry不支持MeshFaceMaterial
  • 将sql查询输出到html表中

    我试图将此 PHP SQL 查询的输出放入数据库表中 但它将所有行数据输出到一列中 if isset POST submit name htmlentities POST name parts explode name lastname a
  • OpenCV Mat 旋转得到错误结果

    我想将图像旋转 90 度 我的代码如下 int main int argc const char argv Mat img imread Users chuanliu Desktop src4 p00 JPG resize img img
  • 您没有 /var/lib/gems/2.3.0 目录的写权限

    我在 ubuntu 16 04 上安装了 ruby which ruby usr bin ruby ruby v ruby 2 3 0p0 2015 12 25 x86 64 linux gnu gem install bundler ER
  • 我可以使用 Liquid 模板在 Jekyll 中实现合适的平铺分页吗?

    I ve found this nice jekyll theme http www jacoporabolini com emerald with good looking pagination Unfortunately is only
  • 获取MySql数据并将其存储到Javascript数组中

    想要从 Mysql 检索记录数据并将其存储到 Javascript 数组中 以获取以下格式的 heatmap js 地图数据 var testData max 46 data lat 33 5363 lon 117 044 value 1
  • 什么时候我可以放心地用-O3编译程序?

    我见过很多人抱怨 O3 option GCC 程序无法使用编译选项 O3 浮点问题由 David Hammen 提供 我查看了 GCC 的手册 O3 Optimize yet more O3 turns on all optimizatio
  • Java EE 6 与 Spring 3 堆栈 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 我现在正在开始一个新项目
  • 如何在 Angular 中重现 Angular JS .broadcast() / .on() 行为?

    我正在努力用 Angular8 重写 AngularJS 应用程序 我已经阅读了组件之间通信的不同方法 但鉴于我当前的要求 似乎无法找到实现此目的的正确方法 我目前有 2 个兄弟组件 它们都使用处理基本 CRUD 功能的通用服务 表单组件调
  • 将 ORB 特征与阈值进行匹配

    我的项目是基于android的草药识别 我使用 ORB 来获取关键点 特征并匹配特征 我想使用这个算法 我使用 4 个参考图像 并将它们的特征 image1 与 image1 1 2 1 3 1 4 2 3 3 4 进行匹配 然后我将到数据
  • SQL Server Express 4GB 限制

    简单问题 4GB 限制是针对每个数据库还是针对已安装的 SQL Server 实例 如您所知 您可以在 SQL Server 实例中创建多个数据库 每个数据库的大小限制为 4GB
  • 控制范围和预测范围

    我已经回顾了模型预测控制的参考书目和 Gekko 编程结构 尽管我了解它的编程方式及其目的 例如 我想了解 Gekko 如何根据 Seborg 中的相关内容来管理控制范围和预测范围之间的差异 我看不出代码有什么区别 下面是一个用于说明的 M
  • Socket_read() 说“不是有效的资源”

    我正在学习套接字编程并尝试使用 php 我想使用客户端连接到套接字服务器并从客户端读取服务器的响应 代码 服务器 php address 127 0 0 1 port 3343 echo I am here set time limit 0
  • 将枚举列表传递给条件

    我有域名 付款 class Payment String name PaymentType paymentType PaymentType 是一个 ENUM 搜索特定付款类型的所有付款很简单 def results Payment crea
  • 单成员结构的灵气属性传播问题

    我遇到了 Spirit Qi 的编译问题 它抱怨说值类型不是以下成员标识符 由于某种原因 Qi 的属性系统将标识符视为容器类型 并尝试枚举它的值类型 这是一个类似的问题这个问题 但是 我相信原因是单个成员结构和may与此有关bug incl
  • 如何为应用程序的容器使用相同的凭证处理程序配置来生成新的密码哈希值?

    我的 Web 应用程序的上下文定义类似于
  • php 文本中最常用的单词

    我在 stackoverflow 上找到了下面的代码 它可以很好地查找字符串中最常见的单词 但我可以排除对 a if you have 等 等常用词的计数吗 或者我必须在计数后删除元素吗 我该怎么做 提前致谢
  • Android BLE 血糖通知

    我厌倦了使用 Android BLE SDK 与我的 Glucose 设备进行通信 我需要 UUID 2a18 和 2a34 的 setCharacteristicNotification 我参考Android官方SDK如下 http de