diff --git a/pycardium/modules/py/meson.build b/pycardium/modules/py/meson.build
index d2669a19213f7d0f19d66b47e1dc4d4ebeac24c5..fa858b7d12bfb2450b50de7fda180ba30f9038a0 100644
--- a/pycardium/modules/py/meson.build
+++ b/pycardium/modules/py/meson.build
@@ -9,6 +9,7 @@ python_modules = files(
   'pride.py',
   'ledfx.py',
   'simple_menu.py',
+  'smooth_vibrate.py',
 
   # MicroPython Standard-Library
   'col_defaultdict.py',
diff --git a/pycardium/modules/py/smooth_vibrate.py b/pycardium/modules/py/smooth_vibrate.py
new file mode 100644
index 0000000000000000000000000000000000000000..7aa28119ff4de2cf8135799605dbfafa1d5ed839
--- /dev/null
+++ b/pycardium/modules/py/smooth_vibrate.py
@@ -0,0 +1,51 @@
+import vibra
+import utime
+
+
+def vi(dur, sle):
+    """
+    helper for repeater()
+    see repeater() params
+    """
+    vibra.vibrate(dur)
+    utime.sleep_ms(sle)
+
+
+def repeater(times, dur, sle):
+    """
+    trigger vibration motor with three values
+    times => how often we should triger
+    dur => how long should we trigger for each iteration
+    sle => how long should we wait in between
+
+    combination out of this creates a fake PWM
+    that enables easy and smooth vibrations
+    """
+    for i in range(times):
+        vi(dur, sle)
+
+
+def simple():
+    """
+    simple() is a short way of vibration
+    for example for button push/change status suitable
+    """
+    repeater(5, 5, 10)
+
+
+def select():
+    """
+    select() is a little longer, but smoother
+    good for communicating something got selected
+    """
+    repeater(10, 5, 20)
+
+
+def pattern(n=None):
+    """
+    very distinctive but long pattern
+    feels like duk-duk-duk
+    n = 2 and n = 1 feels the same
+    """
+    n = n or 3
+    repeater(n, 20, 100)