Decent 电子秤

开放BLE API文件

论坛   薄款Decent蓝牙秤扩展API   联络我们


我们希望提供多种编程语言的代码示例,展示如何与Decent蓝牙秤操作。
请发送电子邮件给我们,并分享您自己的scale talking代码,以便我们可以帮助其他人更快地开始。

快速入门指南: 重量和按键提示、去皮和计时器

  1. 按住O按钮2秒钟,打开decent蓝牙秤。
  2. 在设备上进行蓝牙搜索,然后连接到“decent蓝牙秤”
  3. 向电子秤发送去皮或LED开启命令,使APP显示在电子秤上。电子秤将不会称重,直到向电子秤发送某种写入命令,让它识别到你的应用程序。
  4. 打开LED:“030A0101000108”或关闭LED,“030A0000000009”
  5. 要求接收来自 FFF4 的重量通知(“0000FFF4-0000-1000-8000-00805F9B34FB”)。重量通知作为有符号的两字节(短)整数,现在将以每秒 10 次的速度接收,在字节 3 和 4 上。
  6. 固件v1.0和v1.1以7个字节格式发送重量数据。 固件v1.2版本以10个字节格式发送带有时间信息的重量数据。
  7. 可选:通过发送“030B030000000B”和暂停计时器和“030B0000000008”启动计时器和用“030B020000000A”将计时器重置为零
  8. 蓝牙秤去皮命令“030F000000010D”
  9. 观看Light Blue执行这些命令的演示。
  10. 已知bug:在Decent蓝牙秤 v1.0固件中,有时可能会丢失命令(例如去皮或计时器启动)。 为安全起见,向秤发送命令两次,延迟时间为 50 毫秒或更长。 这将在 v1.1 固件中解决。 v1.1 固件中将添加用于确定当前固件版本的新BLE命令,让您写入逻辑条件来实现不发送命令两次。
  11. 如果至少每5秒没有接收到“03 0a 03 ff 00 0a”的信号,则薄款Decent蓝牙秤将断开连接。 这是一个非常有用的功能,可以断开僵尸蓝牙连接,这种情况在 Android 9 及更早版本中经常发生。 向较老的秤发送信号不会产生任何负面影响。 去皮和LED开启命令的第6个字节都应设置为01,否则薄款Decent蓝牙秤将假定您的应用程序不知道心跳功能并且不会强制执行它。
  12. 如遇到麻烦,下载 LightBlue iosAndroidMac 并按照上面视频中显示的步骤进行操作。
  13. 程序员指南:薄款Decent蓝牙秤。

命令参考:

重量FFF4 (0000FFF4-0000-1000-8000-00805F9B34FB)

固件v1.0和v1.1以7个字节格式发送重量数据。
  • 03CE 0000 0000 CD = 0.0 克
  • 03CE 0065 0000 A8 = 10.1 克
  • 03CE 0794 0000 5E = 194.0 克
  • 03CE 1B93 0000 5E = 705.9 克
  • 03CE 2BAC 0000 4A = 1118.0 克

    固件v1.2版本以10个字节格式发送带有时间信息的重量数据。
  • 03CE 0000 010203 0000 CD = 0.0 克 - (1分2秒0.3秒)
  • 03CE 0065 010204 0000 A8 = 10.1 克 - (1分2秒0.4秒)
  • 03CE 0794 010205 0000 5E = 194.0 克 - (1分2秒0.5秒)
  • 03CE 1B93 010206 0000 5E = 705.9 克 - (1分2秒0.6秒)
  • 03CE 2BAC 010207 0000 4A = 1118.0 克 - (1分2秒0.7秒)
  • 去皮(重量归零)030F000000010E
    打开LED显示030A0101000108 (克)
    关闭LED显示030A0000000009
    计时开始030B030000000B
    计时暂停030B0000000008
    计时归零030B020000000A
    关机
    (v1.2 固件中的新功能)
    030A020000000B

    蓝牙配对和超时

    1. 使用USB供电时,秤将自动开启并开启蓝牙配对模式,蓝色LED将闪烁。蓝牙设备名为“Decent Scale”。
    2. 该秤将永久可供蓝牙配对使用,蓝牙不会关闭。
    3. 如果您将应用与秤断开连接,则秤将返回蓝牙配对模式。
    4. 如果使用电池供电,如果秤未连接app且未称重,则秤将在2分钟(v1.1固件为10分钟)后自动关机。
    5. 使用USB供电时,蓝牙秤将不会自动关机。
    6. 当您成功连接app时,蓝牙秤显示“app”1秒,并且蓝色灯停止闪烁。
    7. 提供了Decent蓝牙秤的快速使用视频

    Decent蓝牙秤的特点

    1. 重量信息是故意不线性展示的,因为我们认为线性的信息可以在计算设备上通过软件更好地实现,而不是在秤固件中完成。
    2. Decent蓝牙秤没有“稳定重量”的概念。称重传感器的当前读数立即通过蓝牙传输给app。
    3. 如果您想要线性的重量变化信息,您应该在秤接收到的原始数据之后自行实现。
    4. 重量变化会立即发送。
    5. 没有“阈值重量(重量必须达到某个数值,秤才会识别并增加重量度数。例如:阈值重量为0.5克,首次放置重量必须大于0.5克,称重传感器才能识别重量并显示,如果首次放置小于0.5克的物体,秤将无法识别,读数依然是零)”。
    6. 该秤旨在极快地响应重量变化,精度低至0.1克。
    7. 如果您的称重介质(例如液体)在运动,您可能会看到由于该运动而导致的小的重量变化。
    8. 如果在您的使用环境里,您希望隐藏电子秤LED显示的重量变化,您可以选择禁用它们。因此,您可以选择仅在应用程序中显示重量。这将会大大延长电池使用寿命。
    9. 固件 v1.2 及更新版本在每次重量测量时都包含0.1秒精度的时间信息。 这是:(1)帮助您计算实际流量,(2)了解您是否丢失了重量测量值或,(3)是否收到了无序重量消息。

    按键

    1. decent蓝牙秤有两个按键,分别标有圆形(按钮 0)和正方形(按钮 1)。
    2. 当秤没有蓝牙连接时,这些按钮控制电源、去皮和定时器。
    3. 一旦秤有蓝牙连接,这些按钮就完全在您的应用程序的控制之下,并且点击不再对秤产生任何影响。

    注意事项

    1. 最大重量为2000克。
    2. 称重非常热的物体可能会导致秤读数不准确。
      1. 这是因为它们加热称重传感器,改变了传感器的电阻。
      2. 通常这表现为重量不会超过某个数字。
      3. 您可以通过在秤和称重物之间使用绝缘垫来解决这个问题,例如一块硅胶或木头。
    3. Decent蓝牙秤在出厂时已使用1000g和2000g砝码进行过校准。
      1. 但是,校准可能会受到运输的影响。
      2. 请参阅用户手册或此校准视频 a> 了解更多信息。
      3. 重量数值以10hz的频率发送。
      4. 电池状态在重量数据传输中返回,以响应LED开启或关闭蓝牙命令。
        1. 请参阅“发送命令以打开或关闭 LED”视频。
        2. 电池电量不足3%或更低时,秤会在开机时显示LO信息。
      5. 我们不建议在秤上长时间放置重物,否则会慢慢使称重传感器变形,使其无法校准。
      6. 秤可以无限次重新校准。
      7. 没有用于设置秤显示克与盎司的蓝牙命令。
        1. 必须手动操作,打开秤后立即同时按下○和□按钮。更多信息,请参阅用户手册
        2. 通过读取LED开启或关闭的蓝牙命令的响应,您可以发现电子秤显示的是克还是盎司。请参阅“发送打开或关闭LED的命令”
      8. 如果在执行完第一条命令之前向秤发送了第二条蓝牙命令,则秤将忽略第二条命令。
        1. 例如:一个去皮命令紧跟一个计时启动命令。
        2. 建议发送到秤的命令之间有200毫秒的间隔。
        3. 或者,您可以延迟发送第二个命令,直到您确认第一个命令已执行。
        4. 例如:在去皮(或LED开/关命令)之后,设置一个6字节的FE响应被发送回您的应用程序,以执行成功。


      蓝牙介绍

      “0000FFF4-0000-1000-8000-00805F9B34FB”体现了decent蓝牙秤的数据包

      所有Decent秤的蓝牙数据包都具有以下7字节结构:

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      0A=LED开启/关闭
      0B=计时开始/关闭
      0F=去皮
      命令/数据 (1)命令/数据 (2)命令/数据 (3)命令/数据 (4)异或验证
      用于验证的6字节异或条件
      下面给出了有关每个命令和信息类型的更多详细信息。

      这是一个Tcl过程,它构建了7个字节的二进制数据包以发送到 Decent秤。它首先构建为文本字符串,然后在过程结束时转换为7字节的二进制文件:

        proc decent_scale_make_command {cmdtype cmdddata {cmddata2 {}} } {
            if {$cmddata2 == ""} {
                msg "1 part decent scale command"
                set hex [subst {03${cmdtype}${cmdddata}000000[decent_scale_calc_xor "0x$cmdtype" "0x$cmdddata"]}]
            } else {
                msg "2 part decent scale command"
                set hex [subst {03${cmdtype}${cmdddata}${cmddata2}0000[decent_scale_calc_xor4 "0x$cmdtype" "0x$cmdddata" "0x$cmddata2"]}]
            }
            msg "hex is '$hex' for '$cmdtype' '$cmdddata' '$cmddata2'"
            return [binary decode hex $hex]
        }


      异或计算

      要进行异或计算,应该对前6个字节进行数学异或计算。

      下面的Tcl编程代码,为一个只接受一个参数的简单命令(例如:去皮)异或计算:

        proc decent_scale_calc_xor {cmdtype cmdddata} {
            set xor [format %02X [expr {0x03 ^ $cmdtype ^ $cmdddata ^ 0x00 ^ 0x00 ^ 0x00}]]
            msg "decent_scale_calc_xor for '$cmdtype' '$cmdddata' is '$xor'"
            return $xor
        }
        

      这个Tcl编程代码,是用于计算两个参数命令的异或计算,例如启用LED显示:

        proc decent_scale_calc_xor4 {cmdtype cmdddata1 cmdddata2} {
            set xor [format %02X [expr {0x03 ^ $cmdtype ^ $cmdddata1 ^ $cmdddata2 ^ 0x00 ^ 0x00}]]
            msg "decent_scale_calc_xor4 for '$cmdtype' '$cmdddata1' '$cmdddata2' is '$xor'"
            return $xor
        }
        

      接收重量

      接收重量数据是一种稍微特殊的情况,因为重量是作为克重量*10的两字节有符号短整数发送的:

      固件v1.0和v1.1以7个字节格式发送重量数据。

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      CE=重量稳定
      CA=重量变化
      Data (1)
      克重*10

      有符号短整数的高位字节
      Data (2)
      克重*10

      有符号短整数的低位字节
      Data (3)
      变化*10

      有符号短整数的高位字节
      Data (4)
      变化*10

      有符号短整数的低位字节
      异或验证
      用于验证的6字节异或条件
      固件v1.2版本以10个字节格式发送带有时间信息的重量数据。

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节字节 8字节 9字节 10
      型号
      03 = Decent
      类型
      CE=重量稳定
      CA=重量变化
      Data (1)
      克重*10

      有符号短整数的高位字节
      Data (2)
      克重*10

      有符号短整数的低位字节
      Data (3)
      分钟
      Data (4)
      秒(0-59 十六进制)
      数据(5)
      分秒数(0-9)
      数据(6)
      供将来使用
      数据(7)
      供将来使用
      异或验证
      用于验证的6字节异或条件
      注意:
      1. 您的应用程序应该查看接收到的消息的长度,并支持两者的解析。 大多数应用程序只需要知道当前的重量:只需查看字节3和4即可,与所有Decent蓝牙秤固件兼容。 或者,您可以检查固件版本是否等于或大于03。
      2. 当前重量在数据字节1和2上以两字节短的大端有符号整数的形式传达。
      3. 每秒重量变化以两字节无符号大端字节的形式出现。但是,此功能目前存在问题,不建议使用。如果你需要重量变化数据,您可以自己计算。 自固件v1.2起,重量变化率功能已停用。
      4. 重量数据以每秒10次的频率发送。
      5. 秤尝试确定重量何时稳定(不再变化)并将第二个字节设置为CE。当重量发生变化时,第二个字节是CA。但是,您可以选择忽略这一点并实施您自己的逻辑来决定重量何时稳定,因为我们没有对重量数据做数据平滑或稳定处理。
      6. 查看本页顶部的7字节和10字节消息示例。


      接收按钮点击信号

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      AA
      Data (1)
      01=圆形按键
      02=方形按键
      Data (2)
      01=短按
      02=长按
      Data (3)Data (4)异或验证
      00
      注意:
      1. 当有蓝牙连接时,按钮轻敲无功能相应,并且您可以编程您喜欢的任何功能。
      2. 在de秤v1.1固件上,按下圆形按钮不会通过蓝牙发送信号。如果您的应用需要去皮,您的应用应向秤发送去皮命令。

      以下是Light Blue应用程序日志中的触控按钮示例:
        16:59:51.479 - 特征 (FFF4) 通知: 03aa0101 0000a9 (短按圆形按钮)
        17:35:49.591 - 特征 (FFF4) 通知: 03aa0102 0000aa (长按圆形按钮)
        17:38:16.702 - 特征 (FFF4) 通知: 03aa0201 0000aa  (短按方形按钮)
        17:39:08.003 - 特征 (FFF4) 通知: 03aa0202 0000a9  (长按方形按钮)
        
        



      发送去皮命令(将重量重置为零)

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      0F
      Data (1)
      递增整数
      (可以一直为零)
      Data (2)
      00
      Data (3)
      00
      Data (4)
      00=disable heartbeat requirement
      01=maintain heartbeat
      异或验证
      计算
      注意:
      1. “递增整数”是可选的,并且可以始终为零。
      2. 030F000000000C字符串将始终为去皮。
      3. 确保您正确计算了7字节的异或运算,否则去皮命令将被忽略。
      4. 如果至少每5秒没有接收到“03 0a 03 ff 00 0a”的信号,则薄款Decent蓝牙秤将断开连接。 如果你想禁用这个要求,字节6应该是00。 如果你想保持这个要求,字节6应该是01。 将字节6设置为01对不支持心跳功能的模型没有负面影响。
      下面是一段代码,展示了如何构建一个7字节的去皮命令:

        proc tare_counter_incr {} {
        
            if {[info exists ::decent_scale_tare_counter] != 1} {
                set ::decent_scale_tare_counter 0
            } elseif {$::decent_scale_tare_counter >= 255} {
                set ::decent_scale_tare_counter 0
            } else {
                incr ::decent_scale_tare_counter
            }
        
            # alternatively: the tare counter can in fact be any not-recently-used integer, such as this random digit-picker
            # set ::decent_scale_tare_counter [expr {int(rand() * 255)}]
        
        }
        
        proc decent_scale_tare_cmd {} {
            tare_counter_incr
            set cmd [decent_scale_make_command "0F" [format %02X $::decent_scale_tare_counter]]
            return $cmd
        }
        


      Decent秤将在发出去皮命令后发回应答。 该应答具有以下结构:

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      0F
      Data (1)
      去皮计数器
      Data (2)
      00
      Data (3)
      00
      Data (4)
      FE
      异或验证


      发送命令以打开或关闭LED显示

      第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
      型号
      03 = Decent
      类型
      0A
      Data (1)
      重量LED显示开/关
      00=关
      01=开
      02=关机
      Data (2)
      计时器LED显示开/关
      00=关
      01=开
      Data (3)
      00=克
      01=盎司
      Data (4)
      00
      异或验证
      计算
      注意:
      1. 保持LED显示关闭可延长电池寿命。
      2. 即使两个LED显示都关闭,秤仍将继续工作。
      3. 固件v1.2中增加了关机命令。
      4. 显示“重量变化”的单个LED 将亮起,即使两个LED都已关闭。
        1. 从v1.1固件开始,方形按钮上方的LED在重量变化时不再亮起。
        2. 而当按下任一按钮时,该LED会亮起。
        3. 这是为了向用户提供视觉反馈,即秤已感应到按钮按下。
        示例:使用克单位时,所有LED亮起命令:
          03 0A 01 01 00 00 09
          
        示例:使用盎司单位时,所有LED亮起命令:[需要 v1.1 固件]
          03 0A 01 01 01 00 08
          
        示例:所有LED关闭命令:
          03 0A 00 00 00 00 09
          
        示例:关机命令:
          03 0A 02 00 00 00 0B
          
        在LED开/关命令(固件 v1.1)后,Decent秤将在重量数据反馈中发回应答,包括克与盎司信息、电池电量和固件版本。 数据结构如下:

        第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
        型号
        03 = Decent
        类型
        0A
        Data (1)
        00
        Data (2)
        显示的重量单位
        00=克
        01=盎司
        Data (3)
        电池电量
        在3%(低电量)和100%(满电)之间。
        FF (255) = USB供电
        Data (4)
        固件版本
        FE=V1.0
        02=V1.1
        03=v1.2固件版本
        异或验证
        由于电子秤PCB的限制,电池电量始终会显示100%。
        以下是从Light Blue app应用日志中读取电池电量的示例:
          16:02:36.005 - 特征(36F5)写入新值: <030a0101 000009> (我们使用应用程序发送此值,打开LED)
          16:02:36.061 - 特征(36F5)读取:(空)
          16:02:36.135 - 特征 (FFF4) 通知: 030a0000 64026f (64 hex = 100%, 使用电池运行
          
          15:59:50.421 - 特征(36F5)写入新值: <030a0101 000009> (我们使用应用程序发送此值,打开LED)
          15:59:50.485 - 特征(36F5)读取:(空)
          15:59:50.522 - 特征 (FFF4) 通知: 030a0000ff0ac7  (FF 十六进制 = 255%,使用USB电源供电)
          


        发送命令来控制计时器

        第一个字节第二个字节第三个字节第四个字节第五个字节第六个字节第七个字节
        型号
        03 = Decent
        类型
        0B
        Data (1)
        计时开始/停止/重置
        00=停止
        02=重置归零
        03=开始
        Data (2)
        00
        Data (3)
        00
        Data (4)
        00
        异或验证
        计算
        例如:计时开始命令
          03 0B 03 00 00 00 0B
          
        例如:计时停止命令
          03 0B 00 00 00 00 08
          
        例如:计时重置命令
          03 0B 02 00 00 00 0A
          

        用于从Decent秤接收各种数据的大型示例代码

        Github上更大的bluetooth.tcl示例

        以下代码(使用 Tcl 语言,但希望您能理解)可以实现:
        1. 接收重量信息
        2. 接收按键操作信息
        3. 接收当前时间值
        set ::de1(cuuid_decentscale_read) "0000FFF4-0000-1000-8000-00805F9B34FB"
        set ::de1(cuuid_decentscale_write) "000036F5-0000-1000-8000-00805F9B34FB"
        set ::de1(cuuid_decentscale_writeback) "83CDC3D4-3BA2-13FC-CC5E-106C351A9352" 
        
        if {$cuuid eq $::de1(cuuid_decentscale_read)} {
            # decent scale
            parse_decent_scale_recv $value weightarray
        
            if {[ifexists weightarray(command)] == [expr 0x0F] && [ifexists weightarray(data6)] == [expr 0xFE]} {
                # tare cmd success is a msg back to us with the tare in 'command', and a byte6 of 0xFE
                msg "- decent scale: tare confirmed"
        
                return
            } elseif {[ifexists weightarray(command)] == 0xAA} {
                msg "Decentscale BUTTON $weightarray(data3) pressed"
                if {[ifexists $weightarray(data3)] == 1} {
                    # button 1 "O" pressed
                    decentscale_tare
                } elseif {[ifexists $weightarray(data3)] == 2} {
                    # button 2 "[]" pressed
                }
            } elseif {[ifexists weightarray(command)] != ""} {
                msg "scale command received: [array get weightarray]"
        
            }
        
            if {[info exists weightarray(weight)] == 1} {
                set sensorweight [expr {$weightarray(weight) / 10.0}]
                #msg "decent scale: ${sensorweight}g [array get weightarray] '[convert_string_to_hex $value]'"
                #msg "decentscale recv read: '[convert_string_to_hex $value]'"
                ::device::scale::process_weight_update $sensorweight $event_time
            } else {
                msg "decent scale recv: [array get weightarray]"
            }
        }
        
        proc parse_decent_scale_recv {packed destarrname} {
            upvar $destarrname recv
            unset -nocomplain recv
        
               ::fields::unpack $packed [decent_scale_generic_read_spec] recv bigeendian
        
               if {$recv(command) == 0xCE || $recv(command) == 0xCA} {
                   unset -nocomplain recv
                   ::fields::unpack $packed [decent_scale_weight_read_spec2] recv bigeendian
               } elseif {$recv(command) == 0xAA} {
                   msg "Decentscale BUTTON pressed: [array get recv]"
               } elseif {$recv(command) == 0x0C} {
                   unset -nocomplain recv
                   ::fields::unpack $packed [decent_scale_timing_read_spec] recv bigeendian
                   msg "Decentscale time received: [array get recv]"
               }
        }
        
        proc decent_scale_generic_read_spec {} {
            set spec {
                model {char {} {} {unsigned} {}}
                command {char {} {} {unsigned} {}}
                data3 {char {} {} {unsigned} {}}
                data4 {char {} {} {unsigned} {}}
                data5 {char {} {} {unsigned} {}}
                data6 {char {} {} {unsigned} {}}
                xor {char {} {} {unsigned} {}}
            }
            return $spec
        }
        
        proc decent_scale_weight_read_spec2 {} {
            set spec {
                model {char {} {} {unsigned} {}}
                wtype {char {} {} {unsigned} {}}
                weight {Short {} {} {signed} {}}
                rate {Short {} {} {unsigned} {}}
                xor {char {} {} {unsigned} {}}
            }
            return $spec
        }