diff --git a/ampel-firmware/lorawan.cpp b/ampel-firmware/lorawan.cpp
index 2d0496e2c4753198e91303c3270e766f66cb3552..99b3c4b9ae98297c7dbc91114e689a6e5c24797d 100644
--- a/ampel-firmware/lorawan.cpp
+++ b/ampel-firmware/lorawan.cpp
@@ -41,58 +41,6 @@ namespace config {
 //   co2ampel-test/devices/esp3a7c94/up {"app_id":"co2ampel-test","dev_id":"esp3a7c94","hardware_serial":"00xxxxxxxx","port":1,"counter":5,"payload_raw":"TJd7","payload_fields":{"co2":760,"rh":61.5,"temp":20.2},"metadata":{"time":"2020-12-23T23:00:51.44020438Z","frequency":867.5,"modulation":"LORA","data_rate":"SF7BW125","airtime":51456000,"coding_rate":"4/5","gateways":[{"gtw_id":"eui-xxxxxxxxxxxxxxxxxx","timestamp":1765406908,"time":"2020-12-23T23:00:51.402519Z","channel":5,"rssi":-64,"snr":7.5,"rf_chain":0,"latitude":22.7,"longitude":114.24,"altitude":450}]}}
 // More info : https://www.thethingsnetwork.org/docs/applications/mqtt/quick-start.html
 
-uint8_t hexToByte(char c) {
-  int v = -1;
-  if ((c >= '0') && (c <= '9')) {
-    v = (c - '0');
-  } else if ((c >= 'A') && (c <= 'F')) {
-    v = (c - 'A' + 10);
-  } else if ((c >= 'a') && (c <= 'f')) {
-    v = (c - 'a' + 10);
-  }
-  return v;
-}
-
-void parseConfig(uint8_t *buf, const char *hex, uint max_n, int step) {
-  int n = util::min(strlen(hex) / 2, max_n);
-
-  Serial.println(hex);
-  Serial.print("Size : ");
-  Serial.println(n);
-
-  for (int i = 0; i < n; i++) {
-    int j;
-    if (step == 1) {
-      // MSB
-      j = i;
-    } else {
-      // LSB
-      j = n - 1 - i;
-    }
-    uint8_t r = hexToByte(hex[j * 2]) * 16 + hexToByte(hex[j * 2 + 1]);
-    buf[i] = r;
-  }
-
-  for (int var = 0; var < max_n; ++var) {
-    Serial.print(buf[var], HEX);
-    Serial.print(" ");
-  }
-  Serial.println();
-  Serial.println("-----");
-}
-
-void os_getArtEui(u1_t *buf) {
-  parseConfig(buf, config::lorawan_app_eui, 8, -1);
-}
-
-void os_getDevEui(u1_t *buf) {
-  parseConfig(buf, config::lorawan_device_eui, 8, -1);
-}
-
-void os_getDevKey(u1_t *buf) {
-  parseConfig(buf, config::lorawan_app_key, 16, 1);
-}
-
 namespace lorawan {
   bool waiting_for_confirmation = false;
   bool connected = false;
@@ -281,4 +229,53 @@ namespace lorawan {
 void onEvent(ev_t ev) {
   lorawan::onEvent(ev);
 }
+
+// 'A' -> 10, 'F' -> 15, 'f' -> 15, 'z' -> -1
+int8_t hexCharToInt(char c) {
+  int8_t v = -1;
+  if ((c >= '0') && (c <= '9')) {
+    v = (c - '0');
+  } else if ((c >= 'A') && (c <= 'F')) {
+    v = (c - 'A' + 10);
+  } else if ((c >= 'a') && (c <= 'f')) {
+    v = (c - 'a' + 10);
+  }
+  return v;
+}
+
+/**
+ * Parses hex string and saves the corresponding bytes in buf.
+ * msb is true for most-significant-byte, false for least-significant-byte.
+ *
+ * "112233" will be loaded into {0x11, 0x22, 0x33} in MSB, {0x33, 0x22, 0x11} in LSB.
+ */
+void hexStringToByteArray(uint8_t *buf, const char *hex, uint max_n, bool msb) {
+  int n = util::min(strlen(hex) / 2, max_n);
+
+  for (int i = 0; i < n; i++) {
+    int j;
+    if (msb) {
+      j = i;
+    } else {
+      j = n - 1 - i;
+    }
+    uint8_t r = hexCharToInt(hex[j * 2]) * 16 + hexCharToInt(hex[j * 2 + 1]);
+    buf[i] = r;
+  }
+}
+
+// Load config into LMIC byte arrays.
+
+void os_getArtEui(u1_t *buf) {
+  hexStringToByteArray(buf, config::lorawan_app_eui, 8, false);
+}
+
+void os_getDevEui(u1_t *buf) {
+  hexStringToByteArray(buf, config::lorawan_device_eui, 8, false);
+}
+
+void os_getDevKey(u1_t *buf) {
+  hexStringToByteArray(buf, config::lorawan_app_key, 16, true);
+}
+
 #endif