diff --git a/sim/fakes/leds.py b/sim/fakes/leds.py
index c8b78d8dc18ae1fdaf8639072bb263498b453393..c650049c5d6fa1099ded219702ff60680c57e345 100644
--- a/sim/fakes/leds.py
+++ b/sim/fakes/leds.py
@@ -1,4 +1,6 @@
 from _sim import _sim
+from sys_colors import hsv_to_rgb
+from math import tau
 
 import pygame
 
@@ -30,11 +32,7 @@ def set_all_rgb(r, g, b):
 
 
 def set_hsv(ix, h, s, v):
-    color = pygame.Color(0)
-    h = int(h)
-    h = h % 360
-    color.hsva = (h, s * 100, v * 100, 1.0)
-    set_rgb(ix, color.r / 255, color.g / 255, color.b / 255)
+    set_rgb(ix, *hsv_to_rgb(h / 360 * tau, s, v))
 
 
 def set_all_hsv(h, s, v):
diff --git a/sim/fakes/sys_colors.py b/sim/fakes/sys_colors.py
index 636b2a519c274970667cd5be65c151b57b075bfe..e45b9a6959623ec7dcd9ffa01d7d7b7d0f73779c 100644
--- a/sim/fakes/sys_colors.py
+++ b/sim/fakes/sys_colors.py
@@ -1 +1,18 @@
-from colorsys import hsv_to_rgb, rgb_to_hsv
+from typing import Tuple
+import pygame
+from math import tau
+
+
+def hsv_to_rgb(h: float, s: float, v: float) -> Tuple[float, float, float]:
+    color = pygame.Color(0)
+    color.hsva = ((h % tau) / tau * 360, s * 100, v * 100, 100)
+    return color.normalize()[:3]
+
+
+def rgb_to_hsv(r: float, g: float, b: float) -> Tuple[float, float, float]:
+    r = min(1, max(0, r))
+    g = min(1, max(0, g))
+    b = min(1, max(0, b))
+    color = pygame.Color(r, g, b)
+    h, s, v, a = color.hsva
+    return (h / 360 * tau, s / 100, v / 100)