chenders/emay-sleepo2
GitHub: chenders/emay-sleepo2
逆向工程得到的 EMAY SleepO2 脉搏血氧仪多语言 BLE SDK,提供统一的跨平台实时数据采集接口。
Stars: 0 | Forks: 0
# EMAY SleepO2 BLE SDK
每个包都暴露了**相同且简单的 API**。选择您的语言 —— 在 Swift、Python、Node.js、Rust、Go 和 Kotlin 中,`EMAYClient` 接口完全一致。
## 快速入门
### Swift
```
import EMAYSleepO2
let emay = EMAYClient()
emay.onReading = { reading in
print("SpO₂: \(reading.spo2 ?? 0)% HR: \(reading.pulse ?? 0)")
}
try await emay.start()
```
### Python
```
import asyncio
from emay_sleepo2 import EMAYClient
async def main():
emay = EMAYClient()
emay.on_reading = lambda r: print(f"SpO₂: {r.spo2}% HR: {r.pulse}")
await emay.start()
await asyncio.sleep(30) # stream for 30 seconds
await emay.stop()
asyncio.run(main())
```
### Node.js
```
import { EMAYClient } from 'emay-sleepo2';
const emay = new EMAYClient();
emay.on('reading', (r) => {
console.log(`SpO₂: ${r.spo2}% HR: ${r.pulse}`);
});
await emay.start();
// ... stream ...
await emay.stop();
```
### Rust
```
use emay_sleepo2::EMAYClient;
#[tokio::main]
async fn main() {
let mut emay = EMAYClient::new().await?;
emay.on_reading(|r| println!("SpO₂: {}% HR: {}", r.spo2, r.pulse));
emay.start().await?;
tokio::time::sleep(Duration::from_secs(30)).await;
emay.stop().await?;
}
```
### Go
```
package main
import (
"fmt"
"time"
emay "github.com/chenders/emay-sleepo2"
)
func main() {
client, _ := emay.NewClient(emay.DefaultAdapter())
client.OnReading = func(r emay.Reading) {
fmt.Printf("SpO₂: %d%% HR: %d\n", r.SpO2, r.Pulse)
}
client.Start()
time.Sleep(30 * time.Second)
client.Stop()
}
```
### Kotlin (Android)
```
val emay = EMAYClient(context)
emay.onReading = { reading ->
println("SpO₂: ${reading.spo2}% HR: ${reading.pulse}")
}
emay.start(scope = lifecycleScope)
```
## API 参考
每个绑定都暴露了相同的最小化接口:
```
class EMAYClient {
// Lifecycle
start() — connect and begin streaming
stop() — stop streaming and disconnect
isStreaming: bool — whether currently streaming
// Data
onReading: (Reading) -> void — called at ~1 Hz with new readings
// Status
status: Status — Idle | Scanning | Connecting | Streaming | Failed
onStatusChange: (Status) -> void
// Advanced
start(address) — connect to a specific device by address
batteryLevel: Int? — battery percentage (after connection)
heartbeatInterval: Duration — default 1.5s
// CSV (parse only, no BLE)
static parseCSV(data) -> [Reading]
static parseCSVFile(path) -> [Reading]
}
```
## 读取类型
```
Reading {
spo2: Int? // SpO₂ percent (0–100), nil when finger off
pulse: Int? // Pulse rate in bpm, nil when no reading
timestamp: Instant // When this reading was captured
}
```
## 协议说明 (太长不看)
- BLE 服务 `FF12`,写入 `FF01`,通知 `FF02`
- 命令格式:`payload + sum(payload) & 0x7F`
- 启动序列:`hello → deviceState → startRealtime → getBattery`
- 每隔约 1.5 秒发送一次心跳命令以维持连接
- 数据帧:8 字节 — `EB 01 05 [PR] [SpO2] 7F 00 [cks]`
- 完整规范:[`spec.md`](spec.md)
## 包
| 语言 | 源码 | 平台 | BLE 库 |
|----------|------------------|----------------|----------------|
| Swift | [`swift/`](swift)| iOS/macOS | CoreBluetooth |
| Python | [`python/`](python) | macOS/Linux/Windows/RPi | bleak |
| Node.js | [`node/`](node) | macOS/Linux/Windows/RPi | noble |
| Rust | [`rust/`](rust) | macOS/Linux/Windows | btleplug |
| Go | [`go/`](go) | macOS/Linux/Windows/embedded | TinyGo BLE |
| Kotlin | [`kotlin/`](kotlin) | Android 8.0+ | Android BLE |
## 关于
EMAY SleepO2 是一款售价 30 美元的连续式脉搏血氧仪,支持夜间数据流传输。
此前没有关于其协议的公开文档。我们对其进行了逆向工程,并将结果开源,以便健康应用开发者、研究人员和极客们无需自己破解协议即可传输血氧数据。
## 许可证
MIT
标签:MITM代理, 云资产清单, 医疗设备, 可视化界面, 日志审计, 物联网, 蓝牙(BLE), 血氧仪, 跨平台SDK, 逆向工具, 逆向工程