Decent 電子秤

開源藍牙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
        }