Examples
Python
Runnable ingest and subscribe scripts.
These scripts work against api.raeh.io with just a raeh_* API key and a device_model_id from the dashboard. No other setup.
Install deps:
pip install httpx websocketsSet env:
export RAEH_CLIENT_KEY=raeh_...
export RAEH_DEVICE_MODEL_ID=<uuid from dashboard>Ingest: stream synthetic PPG
Good for smoke-testing your key and device model without a real wearable.
# ingest_synth.py
import os, asyncio, json, time, uuid, struct, math
from urllib.parse import quote
import websockets
KEY = os.environ["RAEH_CLIENT_KEY"]
DM_ID = os.environ["RAEH_DEVICE_MODEL_ID"]
async def main():
url = (
f"wss://api.raeh.io/stream/ingest"
f"?api_key={quote(KEY)}"
f"&device_id=demo-{uuid.uuid4().hex[:8]}"
f"&device_model_id={quote(DM_ID)}"
)
async with websockets.connect(url) as ws:
handshake = json.loads(await ws.recv())
slot_id = handshake["slots"][0]["slot_id"]
print(f"session: {handshake['session_id']}")
# 60 one-second frames of synthetic 1.2 Hz sinusoid (→ 72 bpm)
for i in range(60):
t0 = int(time.time() * 1000)
samples = [int(2048 + 500 * math.sin(2 * math.pi * 1.2 * k / 100))
for k in range(100)]
header = struct.pack(">BqHB", slot_id, t0, len(samples), 0)
payload = b"".join(s.to_bytes(2, "little", signed=True) for s in samples)
await ws.send(header + payload)
print(f" frame {i + 1}/60", end="\r", flush=True)
await asyncio.sleep(1.0)
print()
asyncio.run(main())Subscribe: print insights live
Run this first, in its own terminal, then start ingest.
# subscribe.py
import os, asyncio, json
from urllib.parse import quote
import websockets
KEY = os.environ["RAEH_CLIENT_KEY"]
async def main():
async with websockets.connect(
f"wss://api.raeh.io/stream/subscribe?api_key={quote(KEY)}"
) as ws:
await ws.recv() # drain subscribe ack
while True:
msg = json.loads(await ws.recv())
t, v, u = msg.get("type"), msg.get("value"), msg.get("unit", "")
if t:
print(f"{t:<5} {v:>6.1f} {u}")
asyncio.run(main())Ingest: real PPG from a file
If you have a CSV of PPG samples (one value per line, int16), stream it at the sensor's native rate:
# ingest_csv.py
import os, asyncio, json, time, uuid, struct, sys
from urllib.parse import quote
import websockets
KEY = os.environ["RAEH_CLIENT_KEY"]
DM_ID = os.environ["RAEH_DEVICE_MODEL_ID"]
CSV_PATH = sys.argv[1]
RATE_HZ = 100 # match your device model's modality sample rate
async def main():
samples = [int(line.strip()) for line in open(CSV_PATH)]
frames = [samples[i:i + RATE_HZ] for i in range(0, len(samples), RATE_HZ)]
url = (
f"wss://api.raeh.io/stream/ingest"
f"?api_key={quote(KEY)}"
f"&device_id=csv-{uuid.uuid4().hex[:8]}"
f"&device_model_id={quote(DM_ID)}"
)
async with websockets.connect(url) as ws:
handshake = json.loads(await ws.recv())
slot_id = handshake["slots"][0]["slot_id"]
print(f"session: {handshake['session_id']}")
print(f"streaming {len(frames)} frames ({len(frames)}s of data)")
for i, frame_samples in enumerate(frames):
t0 = int(time.time() * 1000)
header = struct.pack(">BqHB", slot_id, t0, len(frame_samples), 0)
payload = b"".join(s.to_bytes(2, "big", signed=True) for s in frame_samples)
await ws.send(header + payload)
await asyncio.sleep(1.0)
asyncio.run(main())python ingest_csv.py my_recording.csvWhat you should see in the subscribe terminal
About 15 seconds after ingest_synth.py starts:
hr 71.8 bpm
spo2 98.0 %
hr 72.1 bpm
rr 15.2 brpm
hr 72.0 bpm
...