diff --git a/Documentation/index.rst b/Documentation/index.rst
index a34b597553401994ed47fe20d9a20bb69a5ae06e..06aa3b7e95c0a64495ffc5b42d9659e44031f7cd 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -29,6 +29,7 @@ Last but not least, if you want to start hacking the lower-level firmware, the
    pycardium/leds
    pycardium/light-sensor
    pycardium/os
+   pycardium/personal_state
    pycardium/utime
    pycardium/vibra
 
diff --git a/Documentation/pycardium/personal_state.rst b/Documentation/pycardium/personal_state.rst
new file mode 100644
index 0000000000000000000000000000000000000000..7bf03681840a8b407fa00cf815bdbd7127d93334
--- /dev/null
+++ b/Documentation/pycardium/personal_state.rst
@@ -0,0 +1,63 @@
+.. py:module:: personal_state
+
+``personal_state`` - Personal State
+===================================
+The :py:mod:`personal_state` module allows you to set and get the card10 users personal state from your script. The personal state is displayed on the top-left LED on the bottom of the harmonics board. While the personal state is set the LED can't be controlled by the :py:mod:`leds` module.
+
+**Example**:
+
+.. code-block:: python
+
+   import personal_state
+
+   # Enable the "camp" state only while the app is running.
+   personal_state.set(personal_state.CAMP, False)
+
+   # Enable the "chaos" state and keep it after the app exits.
+   personal_state.set(personal_state.CHAOS, True)
+
+   # Query the currently configured state and if it's persistent.
+   state, persistent = personal_state.get()
+
+   # Clear the currently configured state
+   personal_state.clear()
+
+.. py:function:: personal_state.set(state, persistent)
+
+   Set the users personal state.
+
+   :param int state: ID of the personal state to set. Must be one of :py:data:`personal_state.NO_CONTACT`, :py:data:`personal_state.CHAOS`, :py:data:`personal_state.COMMUNICATION`, :py:data:`personal_state.CAMP`.
+   :param int persistent: Controls whether the personal state is persistent. A persistent state is not reset when the pycardium application is changed or restarted. In persistent mode the personal state LED is not controllable by the pycardium application.
+
+.. py:function:: personal_state.clear()
+
+   Clears a previously set personal state.
+   
+   If no personal state was set this function does nothing. It does not matter
+   if a set state is marked as persistent or not.
+
+.. py:function:: personal_state.get()
+
+   Get the users personal state.
+   
+   :returns: A tuple containing the currently set state and a boolean indicating if it's persistent or not.
+
+.. py:data:: personal_state.NO_STATE
+
+   State ID reported when no personal state is set.
+
+.. py:data:: personal_state.NO_CONTACT
+
+   State ID for the "No Contact" personal state.
+
+.. py:data:: personal_state.CHAOS
+
+   State ID for the "Chaos" personal state.
+
+.. py:data:: personal_state.COMMUNICATION
+
+   State ID for the "Communicatoin" personal state.
+   
+.. py:data:: personal_state.CAMP
+
+   State ID for the "Camp" personal state.
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 7ecf9b5711adbb8ca8f5e8195fb6b1d8ff6a636b..87b24e8975dff763119aa4ffe6ce336e1cb75212 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -84,6 +84,7 @@ typedef _Bool bool;
 #define API_LEDS_SET_ALL           0x6a
 #define API_LEDS_SET_ALL_HSV       0x6b
 #define API_LEDS_SET_GAMMA_TABLE   0x6c
+#define API_LEDS_CLEAR_ALL         0x6d
 
 #define API_VIBRA_SET              0x70
 #define API_VIBRA_VIBRATE          0x71
@@ -101,6 +102,10 @@ typedef _Bool bool;
 
 #define API_TRNG_READ              0xB0
 
+#define API_PERSONAL_STATE_SET     0xc0
+#define API_PERSONAL_STATE_GET     0xc1
+#define API_PERSONAL_STATE_IS_PERSISTENT 0xc2
+
 /* clang-format on */
 
 typedef uint32_t api_int_id_t;
@@ -648,6 +653,75 @@ API(API_LEDS_SET_GAMMA_TABLE, void epic_leds_set_gamma_table(
 	uint8_t *gamma_table
 ));
 
+/**
+ * Set all LEDs to a certain RGB color.
+ *
+ * :param uint8_t r: Value for the red color channel.
+ * :param uint8_t g: Value for the green color channel.
+ * :param uint8_t b: Value for the blue color channel.
+ */
+API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(uint8_t r, uint8_t g, uint8_t b));
+
+/**
+ * Personal State
+ * ==============
+ * Card10 can display your personal state.
+ *
+ * If a personal state is set the top-left LED on the bottom side of the
+ * harmonics board is directly controlled by epicardium and it can't be
+ * controlled by pycardium.
+ *
+ * To re-enable pycardium control the personal state has to be cleared. To do
+ * that simply set it to ``STATE_NONE``.
+ *
+ * The personal state can be set to be persistent which means it won't get reset
+ * on pycardium application change/restart.
+ */
+
+/** Possible personal states. */
+enum personal_state {
+    /** ``0``, No personal state - LED is under regular application control. */
+    STATE_NONE = 0,
+    /** ``1``, "no contact, please!" - I am overloaded. Please leave me be - red led, continuously on. */
+    STATE_NO_CONTACT = 1,
+    /** ``2``, "chaos" - Adventure time - blue led, short blink, long blink. */
+    STATE_CHAOS = 2,
+    /** ``3``, "communication" - want to learn something or have a nice conversation - green led, long blinks. */
+    STATE_COMMUNICATION = 3,
+    /** ``4``, "camp" - I am focussed on self-, camp-, or community maintenance - yellow led, fade on and off. */
+    STATE_CAMP = 4,
+};
+
+/**
+ * Set the users personal state.
+ *
+ * Using :c:func:`epic_personal_state_set` an application can set the users personal state.
+ *
+ * :param uint8_t state: The users personal state. Must be one of :c:type:`personal_state`.
+ * :param bool persistent: Indicates whether the configured personal state will remain set and active on pycardium application restart/change.
+ * :returns: ``0`` on success, ``-EINVAL`` if an invalid state was requested.
+ */
+API(API_PERSONAL_STATE_SET, int epic_personal_state_set(uint8_t state,
+                                                        bool persistent));
+
+/**
+ * Get the users personal state.
+ *
+ * Using :c:func:`epic_personal_state_get` an application can get the currently set personal state of the user.
+ *
+ * :returns: A value with exactly one value of :c:type:`personal_state` set.
+ */
+API(API_PERSONAL_STATE_GET, int epic_personal_state_get());
+
+/**
+ * Get whether the users personal state is persistent.
+ *
+ * Using :c:func:`epic_personal_state_is_persistent` an app can find out whether the users personal state is persistent or transient.
+ *
+ * :returns: ``1`` if the state is persistent, ``0`` otherwise.
+ */
+API(API_PERSONAL_STATE_IS_PERSISTENT, int epic_personal_state_is_persistent());
+
 /**
  * Sensor Data Streams
  * ===================
diff --git a/epicardium/main.c b/epicardium/main.c
index 57b07ca4e054f41bb3ba995d1046871540249914..7074d4df20eb94450ea14c63373dd70b8a96b926 100644
--- a/epicardium/main.c
+++ b/epicardium/main.c
@@ -73,6 +73,18 @@ int main(void)
 		}
 	}
 
+	/* LEDs */
+	if (xTaskCreate(
+		    vLedTask,
+		    (const char *)"LED",
+		    configMINIMAL_STACK_SIZE,
+		    NULL,
+		    tskIDLE_PRIORITY + 1,
+		    NULL) != pdPASS) {
+		LOG_CRIT("startup", "Failed to create %s task!", "LED");
+		abort();
+	}
+
 	/* Lifecycle */
 	if (xTaskCreate(
 		    vLifecycleTask,
diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c
index 75a995e9703456ea7ceaaa57922fc2ff4ee2c14e..cb6b70b51302234ca6d2c796afb51c09de74e581 100644
--- a/epicardium/modules/hardware.c
+++ b/epicardium/modules/hardware.c
@@ -190,10 +190,22 @@ int hardware_reset(void)
 	api_interrupt_init();
 	api_dispatcher_init();
 
+	/* Personal State */
+	const int personal_state_is_persistent =
+		epic_personal_state_is_persistent();
+
+	if (personal_state_is_persistent == 0) {
+		epic_personal_state_set(STATE_NONE, 0);
+	}
+
 	/*
 	 * LEDs
 	 */
-	leds_init();
+	if (personal_state_is_persistent) {
+		epic_leds_clear_all(0, 0, 0);
+	} else {
+		leds_init();
+	}
 	epic_leds_set_rocket(0, 0);
 	epic_leds_set_rocket(1, 0);
 	epic_leds_set_rocket(2, 0);
diff --git a/epicardium/modules/leds.c b/epicardium/modules/leds.c
index 0faca35e33fc51b755c6b5e6a920ecfa23697dfc..93b80a993717adaa0d058da554e3d7f6433e2dc5 100644
--- a/epicardium/modules/leds.c
+++ b/epicardium/modules/leds.c
@@ -1,31 +1,59 @@
 #include "leds.h"
 #include "pmic.h"
-//#include "FreeRTOS.h"
-//#include "task.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "epicardium.h"
+#include "modules.h"
+
+#include <stdbool.h>
 
 //TODO: create smth like vTaskDelay(pdMS_TO_TICKS(//put ms here)) for us, remove blocking delay from /lib/leds.c to avoid process blocking
 
-void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
+#define NUM_LEDS 15 /* Take from lib/card10/leds.c */
+
+static void do_update()
 {
-	leds_prep(led, r, g, b);
+	while (hwlock_acquire(HWLOCK_LED, pdMS_TO_TICKS(1)) < 0) {
+		vTaskDelay(pdMS_TO_TICKS(1));
+	}
+
 	leds_update_power();
 	leds_update();
+
+	hwlock_release(HWLOCK_LED);
+}
+
+void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b)
+{
+	if (led == PERSONAL_STATE_LED && personal_state_enabled())
+		return;
+
+	leds_prep(led, r, g, b);
+	do_update();
 }
 
 void epic_leds_set_hsv(int led, float h, float s, float v)
 {
+	if (led == PERSONAL_STATE_LED && personal_state_enabled())
+		return;
+
 	leds_prep_hsv(led, h, s, v);
-	leds_update_power();
-	leds_update();
+	do_update();
 }
 
 void epic_leds_prep(int led, uint8_t r, uint8_t g, uint8_t b)
 {
+	if (led == PERSONAL_STATE_LED && personal_state_enabled())
+		return;
+
 	leds_prep(led, r, g, b);
 }
 
 void epic_leds_prep_hsv(int led, float h, float s, float v)
 {
+	if (led == PERSONAL_STATE_LED && personal_state_enabled())
+		return;
+
 	leds_prep_hsv(led, h, s, v);
 }
 
@@ -33,32 +61,38 @@ void epic_leds_set_all(uint8_t *pattern_ptr, uint8_t len)
 {
 	uint8_t(*pattern)[3] = (uint8_t(*)[3])pattern_ptr;
 	for (int i = 0; i < len; i++) {
+		if (i == PERSONAL_STATE_LED && personal_state_enabled())
+			continue;
+
 		leds_prep(i, pattern[i][0], pattern[i][1], pattern[i][2]);
 	}
-	leds_update_power();
-	leds_update();
+	do_update();
 }
 
 void epic_leds_set_all_hsv(float *pattern_ptr, uint8_t len)
 {
 	float(*pattern)[3] = (float(*)[3])pattern_ptr;
 	for (int i = 0; i < len; i++) {
+		if (i == PERSONAL_STATE_LED && personal_state_enabled())
+			continue;
+
 		leds_prep_hsv(i, pattern[i][0], pattern[i][1], pattern[i][2]);
 	}
-	leds_update_power();
-	leds_update();
+	do_update();
 }
 
 void epic_leds_dim_top(uint8_t value)
 {
 	leds_set_dim_top(value);
-	leds_update();
+	if (personal_state_enabled() == 0)
+		leds_update();
 }
 
 void epic_leds_dim_bottom(uint8_t value)
 {
 	leds_set_dim_bottom(value);
-	leds_update();
+	if (personal_state_enabled() == 0)
+		leds_update();
 }
 
 void epic_leds_set_rocket(int led, uint8_t value)
@@ -74,8 +108,7 @@ void epic_set_flashlight(bool power)
 
 void epic_leds_update(void)
 {
-	leds_update_power();
-	leds_update();
+	do_update();
 }
 
 void epic_leds_set_powersave(bool eco)
@@ -87,3 +120,15 @@ void epic_leds_set_gamma_table(uint8_t rgb_channel, uint8_t gamma_table[256])
 {
 	leds_set_gamma_table(rgb_channel, gamma_table);
 }
+
+void epic_leds_clear_all(uint8_t r, uint8_t g, uint8_t b)
+{
+	for (int i = 0; i < NUM_LEDS; i++) {
+		if (i == PERSONAL_STATE_LED && personal_state_enabled())
+			continue;
+
+		leds_prep(i, r, g, b);
+	}
+
+	do_update();
+}
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 4966be6c9122ed2333ca6a5ecf1b6fc5e5ceb988..5b4199b1739de26ef4a633397e0aa80dabd42c5d 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -10,6 +10,7 @@ module_sources = files(
   'lifecycle.c',
   'light_sensor.c',
   'log.c',
+  'personal_state.c',
   'pmic.c',
   'rtc.c',
   'serial.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index ccd8a900d6f0aa58fa157536ad6c3eb4c62b6fa9..3555ab52e7c8ed66707459f2b0b4c90bf123dadd 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -26,6 +26,11 @@ void return_to_menu(void);
 void vSerialTask(void *pvParameters);
 void serial_enqueue_char(char chr);
 
+/* ---------- LED Animation / Personal States ------------------------------ */
+#define PERSONAL_STATE_LED 14
+void vLedTask(void *pvParameters);
+int personal_state_enabled();
+
 /* ---------- PMIC --------------------------------------------------------- */
 /* In 1/10s */
 #define PMIC_PRESS_SLEEP           20
@@ -43,6 +48,7 @@ void hwlock_init(void);
 enum hwlock_periph {
 	HWLOCK_I2C = 0,
 	HWLOCK_ADC,
+    HWLOCK_LED,
 	_HWLOCK_MAX,
 };
 
diff --git a/epicardium/modules/personal_state.c b/epicardium/modules/personal_state.c
new file mode 100644
index 0000000000000000000000000000000000000000..cd6c52c7471af09a37560ef4b94644fc0549179c
--- /dev/null
+++ b/epicardium/modules/personal_state.c
@@ -0,0 +1,141 @@
+#include "epicardium.h"
+#include "leds.h"
+#include "modules.h"
+
+#include <math.h>
+
+uint8_t _personal_state_enabled   = 0;
+uint8_t personal_state            = STATE_NONE;
+uint8_t personal_state_persistent = 0;
+
+int led_animation_ticks = 0;
+int led_animation_state = 0;
+
+int personal_state_enabled()
+{
+	return _personal_state_enabled;
+}
+
+int epic_personal_state_set(uint8_t state, bool persistent)
+{
+	if (state < STATE_NONE || state > STATE_CAMP)
+		return -EINVAL;
+
+	led_animation_state = 0;
+	led_animation_ticks = 0;
+	personal_state      = state;
+
+	uint8_t was_enabled = _personal_state_enabled;
+
+	_personal_state_enabled   = (state != STATE_NONE);
+	personal_state_persistent = persistent;
+
+	if (was_enabled && !_personal_state_enabled) {
+		while (hwlock_acquire(HWLOCK_LED, pdMS_TO_TICKS(1)) < 0) {
+			vTaskDelay(pdMS_TO_TICKS(1));
+		}
+
+		leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
+		leds_update_power();
+		leds_update();
+
+		hwlock_release(HWLOCK_LED);
+	}
+
+	return 0;
+}
+
+int epic_personal_state_get()
+{
+	return personal_state;
+}
+
+int epic_personal_state_is_persistent()
+{
+	return personal_state_persistent;
+}
+
+void vLedTask(void *pvParameters)
+{
+	const int led_animation_rate = 1000 / 25; /* 25Hz -> 40ms*/
+	while (1) {
+		if (_personal_state_enabled) {
+			while (hwlock_acquire(HWLOCK_LED, pdMS_TO_TICKS(1)) <
+			       0) {
+				vTaskDelay(pdMS_TO_TICKS(1));
+			}
+
+			led_animation_ticks++;
+			if (personal_state == STATE_NO_CONTACT) {
+				leds_prep(PERSONAL_STATE_LED, 255, 0, 0);
+			} else if (personal_state == STATE_CHAOS) {
+				if (led_animation_state == 0) {
+					leds_prep(
+						PERSONAL_STATE_LED, 0, 0, 255
+					);
+					if (led_animation_ticks >
+					    (200 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 1;
+					}
+				} else if (led_animation_state == 1) {
+					leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
+					if (led_animation_ticks >
+					    (300 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 2;
+					}
+				} else if (led_animation_state == 2) {
+					leds_prep(
+						PERSONAL_STATE_LED, 0, 0, 255
+					);
+					if (led_animation_ticks >
+					    (1000 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 3;
+					}
+				} else if (led_animation_state == 3) {
+					leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
+					if (led_animation_ticks >
+					    (300 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 0;
+					}
+				}
+			} else if (personal_state == STATE_COMMUNICATION) {
+				if (led_animation_state == 0) {
+					leds_prep(
+						PERSONAL_STATE_LED, 255, 255, 0
+					);
+					if (led_animation_ticks >
+					    (1000 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 1;
+					}
+				} else if (led_animation_state == 1) {
+					leds_prep(PERSONAL_STATE_LED, 0, 0, 0);
+					if (led_animation_ticks >
+					    (300 / led_animation_rate)) {
+						led_animation_ticks = 0;
+						led_animation_state = 0;
+					}
+				}
+			} else if (personal_state == STATE_CAMP) {
+				leds_prep_hsv(
+					PERSONAL_STATE_LED,
+					120.0f,
+					1.0f,
+					fabs(sin(
+						led_animation_ticks /
+						(float)(1000 /
+							led_animation_rate))));
+			}
+			leds_update_power();
+			leds_update();
+
+			hwlock_release(HWLOCK_LED);
+		}
+
+		vTaskDelay(led_animation_rate / portTICK_PERIOD_MS);
+	}
+}
diff --git a/preload/personal_state.py b/preload/personal_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..7605652c95070dba46cb8e572e48e2ebd2f6c641
--- /dev/null
+++ b/preload/personal_state.py
@@ -0,0 +1,92 @@
+"""
+Personal State Script
+===========
+With this script you can 
+"""
+import buttons
+import color
+import display
+import os
+import personal_state
+
+states = [
+    ("No State", personal_state.NO_STATE),
+    ("No Contact", personal_state.NO_CONTACT),
+    ("Chaos", personal_state.CHAOS),
+    ("Communication", personal_state.COMMUNICATION),
+    ("Camp", personal_state.CAMP),
+]
+
+
+def button_events():
+    """Iterate over button presses (event-loop)."""
+    yield 0
+    button_pressed = False
+    while True:
+        v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT)
+
+        if v == 0:
+            button_pressed = False
+
+        if not button_pressed and v & buttons.BOTTOM_LEFT != 0:
+            button_pressed = True
+            yield buttons.BOTTOM_LEFT
+
+        if not button_pressed and v & buttons.BOTTOM_RIGHT != 0:
+            button_pressed = True
+            yield buttons.BOTTOM_RIGHT
+
+        if not button_pressed and v & buttons.TOP_RIGHT != 0:
+            button_pressed = True
+            yield buttons.TOP_RIGHT
+
+
+COLOR1, COLOR2 = (color.CHAOSBLUE_DARK, color.CHAOSBLUE)
+
+
+def draw_menu(disp, idx, offset):
+    disp.clear()
+
+    for y, i in enumerate(range(len(states) + idx - 3, len(states) + idx + 4)):
+        selected = states[i % len(states)]
+        disp.print(
+            " " + selected[0] + " " * (11 - len(selected[0])),
+            posy=offset + y * 20 - 40,
+            bg=COLOR1 if i % 2 == 0 else COLOR2,
+        )
+
+    disp.print(">", posy=20, fg=color.COMMYELLOW, bg=COLOR2 if idx % 2 == 0 else COLOR1)
+    disp.update()
+
+
+def main():
+    disp = display.open()
+    numstates = len(states)
+
+    current, _ = personal_state.get()
+    for ev in button_events():
+        if ev == buttons.BOTTOM_RIGHT:
+            # Scroll down
+            draw_menu(disp, current, -8)
+            current = (current + 1) % numstates
+            state = states[current]
+            personal_state.set(state[1], False)
+        elif ev == buttons.BOTTOM_LEFT:
+            # Scroll up
+            draw_menu(disp, current, 8)
+            current = (current + numstates - 1) % numstates
+            state = states[current]
+            personal_state.set(state[1], False)
+        elif ev == buttons.TOP_RIGHT:
+            state = states[current]
+            personal_state.set(state[1], True)
+            # Select & start
+            disp.clear().update()
+            disp.close()
+            os.exit(0)
+
+        draw_menu(disp, current, 0)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/pycardium/meson.build b/pycardium/meson.build
index 8d3b447a1750f369ff595d17271e43fc8e3d5707..40fabde700ce03eff4d117b7e5e87c024b5f35f5 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -9,6 +9,7 @@ modsrc = files(
   'modules/sys_leds.c',
   'modules/light_sensor.c',
   'modules/os.c',
+  'modules/personal_state.c',
   'modules/sys_display.c',
   'modules/utime.c',
   'modules/vibra.c',
diff --git a/pycardium/modules/personal_state.c b/pycardium/modules/personal_state.c
new file mode 100644
index 0000000000000000000000000000000000000000..36353534b667a3c4a48bdee9af202d5e5f05f37a
--- /dev/null
+++ b/pycardium/modules/personal_state.c
@@ -0,0 +1,67 @@
+#include "epicardium.h"
+
+#include "py/builtin.h"
+#include "py/obj.h"
+#include "py/runtime.h"
+
+static mp_obj_t
+mp_personal_state_set(mp_obj_t state_obj, mp_obj_t persistent_obj)
+{
+	int state = mp_obj_get_int(state_obj);
+	int rc = epic_personal_state_set(state, mp_obj_is_true(persistent_obj));
+	if (rc < 0)
+		mp_raise_OSError(-rc);
+	return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_2(personal_state_set, mp_personal_state_set);
+
+static mp_obj_t mp_personal_state_clear()
+{
+	int rc = epic_personal_state_set(STATE_NONE, 0);
+	if (rc < 0)
+		mp_raise_OSError(-rc);
+	return mp_const_none;
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(personal_state_clear, mp_personal_state_clear);
+
+static mp_obj_t mp_personal_state_get()
+{
+	int state               = epic_personal_state_get();
+	int persistent          = epic_personal_state_is_persistent();
+	mp_obj_t persistent_obj = mp_const_false;
+	if (persistent > 0)
+		persistent_obj = mp_const_true;
+	mp_obj_t tup[] = {
+		mp_obj_new_int(state & 0xff),
+		persistent_obj,
+	};
+	return mp_obj_new_tuple(2, tup);
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(personal_state_get, mp_personal_state_get);
+
+static const mp_rom_map_elem_t personal_state_module_globals_table[] = {
+	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_personal_state) },
+	{ MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&personal_state_set) },
+	{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&personal_state_get) },
+	{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&personal_state_clear) },
+	{ MP_ROM_QSTR(MP_QSTR_NO_STATE), MP_OBJ_NEW_SMALL_INT(STATE_NONE) },
+	{ MP_ROM_QSTR(MP_QSTR_NO_CONTACT),
+	  MP_OBJ_NEW_SMALL_INT(STATE_NO_CONTACT) },
+	{ MP_ROM_QSTR(MP_QSTR_CHAOS), MP_OBJ_NEW_SMALL_INT(STATE_CHAOS) },
+	{ MP_ROM_QSTR(MP_QSTR_COMMUNICATION),
+	  MP_OBJ_NEW_SMALL_INT(STATE_COMMUNICATION) },
+	{ MP_ROM_QSTR(MP_QSTR_CAMP), MP_OBJ_NEW_SMALL_INT(STATE_CAMP) },
+};
+static MP_DEFINE_CONST_DICT(
+	personal_state_module_globals, personal_state_module_globals_table
+);
+
+// Define module object.
+const mp_obj_module_t personal_state_module = {
+	.base    = { &mp_type_module },
+	.globals = (mp_obj_dict_t *)&personal_state_module_globals,
+};
+
+/* Register the module to make it available in Python */
+/* clang-format off */
+MP_REGISTER_MODULE(MP_QSTR_personal_state, personal_state_module, MODULE_PERSONAL_STATE_ENABLED);
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 3300907012a50e3df7d3815458832a0c8ba0ddea..9e3f3979af79ebbfb16f821b7127424cadb563ff 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -118,3 +118,12 @@ Q(INPUT)
 Q(OUTPUT)
 Q(PULL_UP)
 Q(PULL_DOWN)
+
+/* personal_state */
+Q(personal_state)
+Q(get)
+Q(NO_STATE)
+Q(NO_CONTACT)
+Q(CHAOS)
+Q(COMMUNICATION)
+Q(CAMP)
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index 0708ebe52ad745d888ac5fa0cbace2b7fc655558..309b8f7f76ba776b791288f5f9aa69d9825e4fdd 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -46,6 +46,7 @@
 #define MODULE_LEDS_ENABLED                 (1)
 #define MODULE_LIGHT_SENSOR_ENABLED         (1)
 #define MODULE_OS_ENABLED                   (1)
+#define MODULE_PERSONAL_STATE_ENABLED       (1)
 #define MODULE_UTIME_ENABLED                (1)
 #define MODULE_VIBRA_ENABLED                (1)