昨天咱們已經知道怎麼建置 History Data 類別,也了解如何觸發並儲存它們,接下來的問題就是客戶端怎麼把這些資料取回。
IDD Record Access Control Point 是讓 GATT Client 取得 History Data 的 characteristic,其指令格式如下:
有 6 種 Op Code:
咱們來看 Report Stored Records
的命令格式:
由上表知道它支援 6 種運算子,那現在首要問題就是:怎麼從昨天使用的 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 Point
和 IDD History Data
這兩個 characteristics 的實作,咱們的 IDD Server 便大功告成!