iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0

昨天咱們已經知道怎麼建置 History Data 類別,也了解如何觸發並儲存它們,接下來的問題就是客戶端怎麼把這些資料取回。

1. IDD Record Access Control Point

IDD Record Access Control Point 是讓 GATT Client 取得 History Data 的 characteristic,其指令格式如下:
https://ithelp.ithome.com.tw/upload/images/20250829/201777996LBnuUDmfr.png

有 6 種 Op Code:

  • Report Stored Records
  • Report Number of Stored Records
  • Delete Stored Records
  • Abort Operation
  • Number of Stored Records Response
  • Response Code

咱們來看 Report Stored Records 的命令格式:
https://ithelp.ithome.com.tw/upload/images/20250829/201777997JrHmNy9Rg.png

由上表知道它支援 6 種運算子,那現在首要問題就是:怎麼從昨天使用的 BTree database,取得特定範圍內的資料。

2. BTree database

還記得昨天是怎麼儲存 History Data 的嗎?假設有 5 筆 History Data:

Key (Sequence Number) Value (Event Type + Sequence Number + Relative Offset + Event Data)
1 value 1
2 value 2
3 value 3
4 value 4
5 value 5

Sequence Number 是由小排到大(若不考慮因為 History Data 筆數超過規定上限,而繞回到開頭的情況),那麼在 MicroPython 的 BTree database 裡,與 IDD RACP 運算子相應的動作如下:

運算子 運算元 1 運算元 2 BTree 操作
All records n/a n/a tuple(btree.values())
Less than or equal to 3 n/a tuple(btree.values(None, bytes((0, 0, 0, 4))))
Greater than or equal to 2 n/a tuple(btree.values(bytes((0, 0, 0, 2))))
Within range of (inclusive) 2 4 tuple(btree.values(bytes((0, 0, 0, 2)), bytes((0, 0, 0, 5))))
First record n/a n/a tuple(btree.values())[0]
Last record n/a n/a tuple(btree.values())[-1]

btree.values() 的原型如下:

btree.values([start_key[, end_key[, flags]]])

由上面的例子可以發現,當 end_key 有指定值時,傳回的項目並不包括 end_key,若想要讓其包含 end_key 指代的項目,可以如下使用:

tuple(
    btree.values(
        None,
        bytes((0, 0, 0, 3)),
        btree.INCL
    )
)

# 傳回一樣的結果
tuple(
    btree.values(
        None,
        bytes((0, 0, 0, 4))
    )
)

看官可以到官方網站看 btree.values 的完整說明,定會發現比目前介紹的更好的使用方式。

既然知道如何由 BTree 取得資料了,那麼就將這些功能加進 HistoryManager 類別:

class HistoryManager:
    def get_first_history(self) -> bytes | None:
        try:
            return next(iter(self._db.values()))
        except StopIteration:
            return None

    def get_last_history(self) -> bytes | None:
        try:
            return next(iter(self._db.values(None, None, btree.DESC)))
        except StopIteration:
            return None

    def get_histories(self, start: int | None, end: int | None):
        """取得 Sequence Number 在 start 和 end (含) 之間的資料。支援:
        All: start == None and end == None
        Less than or equal to: start == None and end != None
        Greater than or equal to: start != None and end == None
        Within range of (inclusive): start != None and end != None"""

        yield from self._db.values(self._get_key(start), self._get_key(end), btree.INCL)

那麼 HistoryManager 類別的功能便算是完成了,接下來只要完成 IDD Record Access Control PointIDD History Data 這兩個 characteristics 的實作,咱們的 IDD Server 便大功告成!


上一篇
Day 28 - 留下足跡吧 - History Data
下一篇
Day 30 - 取回 History Data (2) - IDD RACP & IDD History Data
系列文
以MicroPython在ESP32上實作Insulin Delivery Service31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言