diff --git a/preload/apps/spo2/__init__.py b/preload/apps/spo2/__init__.py
index 10b25ff65e04c1f9d416fa8457f6060200aab7dd..7caf8f9ecf100decb9f6dcd701a3424517b9d783 100644
--- a/preload/apps/spo2/__init__.py
+++ b/preload/apps/spo2/__init__.py
@@ -2,17 +2,21 @@ import max86150
 import display
 import utime
 import buttons
+import spo2_algo
+import utime
+import color
 
 
 class SPO2:
     def __init__(self):
         self.sensor = None
         self.RATE = 100
-        self.HISTORY_MAX = self.RATE * 4
-        self.history = []
+        self.HISTORY_MAX = self.RATE * 5
+        self.ir_history = []
+        self.red_history = []
         self.update_screen = 0
         self.disp = display.open()
-        self.DRAW_AFTER_SAMPLES = 5
+        self.DRAW_AFTER_SAMPLES = 100
         self.histogram_offset = 0
         self.WIDTH = 160
         self.SCALE_FACTOR = 30
@@ -22,9 +26,10 @@ class SPO2:
         self.avg_pos = 0
         self.last_sample = 0.0
         self.filtered_value = 0.0
-        self.source = "Red"
         self.average = 0
-        self.prev_w = 0
+        self.prev_w_ir = 0
+        self.prev_w_red = 0
+        self.t0 = utime.time_ms()
 
     def open(self):
         def callback(datasets):
@@ -34,30 +39,65 @@ class SPO2:
 
             # don't update on every callback
             if self.update_screen >= self.DRAW_AFTER_SAMPLES:
-                self.draw_histogram()
+                self.disp.clear(self.COLOR_BACKGROUND)
+                self.draw_histogram(self.ir_history, color.RED)
+                self.draw_histogram(self.red_history, color.GREEN)
+                spo2, spo2_valid, hr, hr_valid = spo2_algo.maxim_rd117(self.ir_history, self.red_history)
+
+                print(utime.time_ms() - self.t0, spo2, spo2_valid, hr, hr_valid)
+                self.t0 = utime.time_ms()
+                if hr_valid:
+                    self.disp.print('HR: {0:3} bpm'.format(hr), posy=20)
+                else:
+                    self.disp.print('HR: --- bpm'.format(hr), posy=20)
+
+                if spo2_valid:
+                    self.disp.print('SpO2: {0:3}%'.format(spo2), posy=0)
+                else:
+                    self.disp.print('SpO2: ---%'.format(spo2), posy=0)
+
 
+                self.disp.update()
+                """
+                if hr_valid and hr > x:
+                    with open("ir.txt", "w") as ir:
+                        for sample in self.ir_history:
+                            ir.write("%d\n" % sample)
+
+                    with open("red.txt", "w") as ir:
+                        for sample in self.red_history:
+                            ir.write("%d\n" % sample)
+
+                    print("Wrote data")
+                    while True: pass
+                """
+                self.update_screen = 0
+
+        # 4x over sampling is active ATM
         self.sensor = max86150.MAX86150(callback=callback, sample_rate=self.RATE * 4)
         while True:
             utime.sleep(.1)
             if buttons.read(buttons.BOTTOM_RIGHT):
-                if self.source == "Red":
-                    self.source = "IR"
-                else:
-                    self.source = "Red"
+                pass
             while buttons.read(buttons.BOTTOM_RIGHT): pass
 
     def update_history(self, datasets):
-        alpha = 0.9975
         for val in datasets:
-            print("%d,%d" % (val.red, val.infrared))
-            if self.source == "Red":
-                d = val.red
-            else:
-                d = val.infrared
+            #print("%d,%d" % (val.red, val.infrared))
+
+            self.ir_history.append(val.infrared)
+            self.red_history.append(val.red)
+
+            """
+            w_ir = val.infrared + self.prev_w_ir * 0.95
+            self.ir_history.append(w_ir - self.prev_w_ir)
+            self.prev_w = w_ir
+
+            w_red = val.red + self.prev_w_red * 0.95
+            self.red_history.append(w - self.prev_w_red)
+            self.prev_w = w_red
+            """
 
-            w = d + self.prev_w * 0.95
-            self.history.append(w - self.prev_w)
-            self.prev_w = w
             """
             self.avg[self.avg_pos] = d
 
@@ -72,44 +112,35 @@ class SPO2:
                 self.filtered_value + avg_data - self.last_sample
             )
             self.last_sample = avg_data
-            self.history.append(self.filtered_value)
-            """
-
-            """
-            self.average = alpha * self.average + (1 - alpha) * d
-            d -= self.average
-            self.history.append(d)
+            self.ir_history.append(self.filtered_value)
             """
 
         # trim old elements
-        self.history = self.history[-self.HISTORY_MAX :]
-
-    def draw_histogram(self):
-        self.disp.clear(self.COLOR_BACKGROUND)
-        self.disp.print('Source: {0} '.format(self.source))
+        self.ir_history = self.ir_history[-self.HISTORY_MAX :]
+        self.red_history = self.red_history[-self.HISTORY_MAX :]
 
+    def draw_histogram(self, history, col):
         # offset in pause_histogram mode
-        window_end = len(self.history) - self.histogram_offset
+        window_end = len(history) - self.histogram_offset
         s_start = max(0, window_end - (self.RATE * 2))
         s_end = max(0, window_end)
         s_draw = max(0, s_end - self.WIDTH)
 
+        average = sum(history[s_start:s_end]) / (s_end - s_start)
         # get max value and calc scale
-        value_max = max(abs(x) for x in self.history[s_start:s_end])
+        value_max = max(abs(x - average) for x in history[s_start:s_end])
         scale = self.SCALE_FACTOR / (value_max if value_max > 0 else 1)
 
         # draw histogram
         draw_points = (
-            int(x * scale + self.OFFSET_Y) for x in self.history[s_draw:s_end]
+            int((x - average) * scale + self.OFFSET_Y) for x in history[s_draw:s_end]
         )
 
         prev = next(draw_points)
         for x, value in enumerate(draw_points):
-            self.disp.line(x, prev, x + 1, value)
+            self.disp.line(x, prev, x + 1, value, col=col)
             prev = value
 
-        self.disp.update()
-        self.update_screen = 0
 
     def close(self):
         if self.self is not None: