Guest

Untitled 1062

Apr 5th, 2026
11
0
Never
Not a member of GistPad yet? Sign Up, it unlocks many cool features!
None 9.65 KB | None | 0 0
  1. import time
  2. import numpy as np
  3. from smbus2 import SMBus
  4. import requests
  5.  
  6. # =========================
  7. # 1) SUPABASE CONFIG
  8. # =========================
  9. SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJucnFvb3Z5YXd4eWpiZHFtdGl4Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjE2NjA3ODEsImV4cCI6MjA3NzIzNjc4MX0.2aXc6ZDLss-nXsj2WQNkvD9AnImr73xVGExKK1LQerM"
  10. TABLE = "heart_reading"
  11.  
  12. UPLOAD_INTERVAL = 5.0 # Upload every 5 seconds
  13.  
  14. def send_to_supabase(bpm, ir, red, spo2=98):
  15. url = f"{SUPABASE_URL}/rest/v1/{TABLE}"
  16. headers = {
  17. "apikey": SUPABASE_ANON_KEY,
  18. "Authorization": f"Bearer {SUPABASE_ANON_KEY}",
  19. "Content-Type": "application/json",
  20. "Prefer": "return=minimal",
  21. }
  22. payload = {
  23. "bpm": int(round(bpm)) if bpm else None,
  24. "spo2": int(spo2),
  25. "ir": int(ir),
  26. "red": int(red)
  27. }
  28. try:
  29. r = requests.post(url, headers=headers, json=payload, timeout=5)
  30. return r.ok
  31. except:
  32. return False
  33.  
  34. # =========================
  35. # 2) MAX30102 CORE
  36. # =========================
  37. MAX30102_ADDR = 0x57
  38. REG_FIFO_DATA = 0x07
  39. REG_MODE_CONFIG = 0x09
  40. REG_SPO2_CONFIG = 0x0A
  41. REG_LED1_PA = 0x0C
  42. REG_LED2_PA = 0x0D
  43.  
  44. def init_max30102(bus):
  45. bus.write_byte_data(MAX30102_ADDR, REG_MODE_CONFIG, 0x40) # Reset
  46. time.sleep(0.1)
  47. bus.write_byte_data(MAX30102_ADDR, REG_MODE_CONFIG, 0x03) # SpO2 Mode
  48. bus.write_byte_data(MAX30102_ADDR, REG_SPO2_CONFIG, 0x27) # 100Hz
  49. bus.write_byte_data(MAX30102_ADDR, REG_LED1_PA, 0x24)
  50. bus.write_byte_data(MAX30102_ADDR, REG_LED2_PA, 0x24)
  51.  
  52. def read_fifo(bus):
  53. d = bus.read_i2c_block_data(MAX30102_ADDR, REG_FIFO_DATA, 6)
  54. red = ((d[0] << 16) | (d[1] << 8) | d[2]) & 0x3FFFF
  55. ir = ((d[3] << 16) | (d[4] << 8) | d[5]) & 0x3FFFF
  56. return red, ir
  57.  
  58. def estimate_bpm_autocorr(ir_signal, fs_hz):
  59. x = np.array(ir_signal, dtype=np.float64)
  60. x = x - np.mean(x)
  61. w = 3 # Smaller smoothing window for smaller buffer
  62. x = np.convolve(x, np.ones(w)/w, mode='same')
  63. ac = np.correlate(x, x, mode='full')
  64. ac = ac[len(ac)//2:]
  65. min_lag = int(fs_hz * 60 / 180)
  66. max_lag = int(fs_hz * 60 / 45)
  67. if max_lag >= len(ac): return None
  68. seg = ac[min_lag:max_lag]
  69. if len(seg) == 0: return None
  70. return 60.0 * fs_hz / (np.argmax(seg) + min_lag)
  71.  
  72. # =========================
  73. # 3) MAIN LOGIC
  74. # =========================
  75. def main():
  76. fs = 50
  77. N = fs * 2 # <--- CHANGED: Buffer is now 2 seconds (100 samples)
  78. ir_buf = []
  79. last_upload_time = time.time()
  80. bpm_smooth = None
  81.  
  82. with SMBus(1) as bus:
  83. init_max30102(bus)
  84. print("System Online. Buffer: 2 Seconds. Uploading every 5 seconds.")
  85.  
  86. while True:
  87. try:
  88. red_raw, ir_raw = read_fifo(bus)
  89. except:
  90. continue
  91.  
  92. if ir_raw > 35000: # Finger detected
  93. ir_buf.append(ir_raw)
  94. if len(ir_buf) > N: ir_buf.pop(0)
  95.  
  96. if len(ir_buf) == N:
  97. bpm = estimate_bpm_autocorr(ir_buf, fs)
  98. if bpm and 40 < bpm < 180:
  99. # Smoothing factor (slightly faster response)
  100. bpm_smooth = bpm if bpm_smooth is None else 0.7*bpm_smooth + 0.3*bpm
  101.  
  102. print(f"RED: {red_raw} | IR: {ir_raw} | BPM: {int(bpm_smooth) if bpm_smooth else 'Wait 2s...'}")
  103. else:
  104. ir_buf = []
  105. bpm_smooth = None
  106. print("Searching for Finger...")
  107.  
  108. # Upload Check
  109. current_time = time.time()
  110. if (current_time - last_upload_time) >= UPLOAD_INTERVAL:
  111. if ir_raw > 35000 and bpm_smooth is not None:
  112. print(">>> Uploading snapshot...")
  113. send_to_supabase(bpm_smooth, ir_raw, red_raw)
  114. last_upload_time = current_time
  115.  
  116. time.sleep(1/fs)
  117.  
  118. if __name__ == "__main__":
  119. main()
RAW Paste Data Copied