diff --git a/ampel-firmware/co2_sensor.cpp b/ampel-firmware/co2_sensor.cpp
index 11db5c3dad0fb2097a4574a3d300af6115722666..0fa5e8e3bc86a6fcba64f74d0f81fb5c139c531c 100644
--- a/ampel-firmware/co2_sensor.cpp
+++ b/ampel-firmware/co2_sensor.cpp
@@ -103,15 +103,14 @@ namespace sensor {
     Serial.println(F(" s during acclimatization."));
     scd30.setMeasurementInterval(config::measurement_timestep_bootup); // [s]
 
-    sensor_console::defineIntCommand("co2", setCO2forDebugging, F(" 1500 (Sets co2 level, for debugging purposes)"));
-    sensor_console::defineIntCommand("timer", setTimer, F(" 30 (Sets measurement interval, in s)"));
-    sensor_console::defineCommand("calibrate", startCalibrationProcess, F(" (Starts calibration process)"));
+    sensor_console::defineIntCommand("co2", setCO2forDebugging, F("1500 (Sets co2 level, for debugging purposes)"));
+    sensor_console::defineIntCommand("timer", setTimer, F("30 (Sets measurement interval, in s)"));
+    sensor_console::defineCommand("calibrate", startCalibrationProcess, F("(Starts calibration process)"));
     sensor_console::defineIntCommand("calibrate", calibrateSensorToSpecificPPM,
-        F(" 600 (Starts calibration process, to given ppm)"));
+        F("600 (Starts calibration process, to given ppm)"));
     sensor_console::defineIntCommand("calibrate!", calibrateSensorRightNow,
-        F(" 600 (Calibrates right now, to given ppm)"));
-    sensor_console::defineIntCommand("auto_calibrate", setAutoCalibration,
-        F(" 0/1 (Disables/enables autocalibration)"));
+        F("600 (Calibrates right now, to given ppm)"));
+    sensor_console::defineIntCommand("auto_calibrate", setAutoCalibration, F("0/1 (Disables/enables autocalibration)"));
   }
 
   bool hasSensorSettled() {
diff --git a/ampel-firmware/csv_writer.cpp b/ampel-firmware/csv_writer.cpp
index a83bed666455545d2d5cb7c68a3d583d88f7b40a..d0828a40999dc7326d1ce19f9a4808be10dd6852 100644
--- a/ampel-firmware/csv_writer.cpp
+++ b/ampel-firmware/csv_writer.cpp
@@ -118,9 +118,9 @@ namespace csv_writer {
     showFilesystemContent();
     Serial.println();
 
-    sensor_console::defineIntCommand("csv", setCSVinterval, F(" 60 (Sets CSV writing interval, in s)"));
-    sensor_console::defineCommand("format_filesystem", formatFilesystem, F(" (Deletes the whole filesystem)"));
-    sensor_console::defineCommand("show_csv", showCSVContent, F(" (Displays the complete CSV file on Serial)"));
+    sensor_console::defineIntCommand("csv", setCSVinterval, F("60 (Sets CSV writing interval, in s)"));
+    sensor_console::defineCommand("format_filesystem", formatFilesystem, F("(Deletes the whole filesystem)"));
+    sensor_console::defineCommand("show_csv", showCSVContent, F("(Displays the complete CSV file on Serial)"));
   }
 
   File openOrCreate() {
diff --git a/ampel-firmware/led_effects.cpp b/ampel-firmware/led_effects.cpp
index ee0fccde5222ecf935dc444d86ed8663d5291a77..061b6f869b2c57494dfdbdbe3495b8a90736ef05 100644
--- a/ampel-firmware/led_effects.cpp
+++ b/ampel-firmware/led_effects.cpp
@@ -70,11 +70,19 @@ namespace led_effects {
     onBoardLEDOff();
   }
 
+  void showColor(int32_t color) {
+    config::night_mode = true; // In order to avoid overwriting the desired color next time CO2 is displayed
+    pixels.setBrightness(255);
+    pixels.fill(color);
+    pixels.show();
+  }
+
   void setupRing() {
     pixels.begin();
     pixels.setBrightness(config::max_brightness);
     LEDsOff();
-    sensor_console::defineCommand("night_mode", toggleNightMode, F(" (Toggles night mode on/off)"));
+    sensor_console::defineCommand("night_mode", toggleNightMode, F("(Toggles night mode on/off)"));
+    sensor_console::defineIntCommand("color", showColor, F("0xFF0015 (Shows color, specified as RGB, for debugging)"));
   }
 
   void toggleNightMode() {
diff --git a/ampel-firmware/lorawan.cpp b/ampel-firmware/lorawan.cpp
index 784b46fb61b25bc8d3868a3a541baa14f241150a..746893b3698137ff14417158e5a2728fd8ad4a25 100644
--- a/ampel-firmware/lorawan.cpp
+++ b/ampel-firmware/lorawan.cpp
@@ -47,7 +47,7 @@ namespace lorawan {
     LMIC_reset();
     // Join, but don't send anything yet.
     LMIC_startJoining();
-    sensor_console::defineIntCommand("lora", setLoRaInterval, F(" 300 (Sets LoRaWAN sending interval, in s)"));
+    sensor_console::defineIntCommand("lora", setLoRaInterval, F("300 (Sets LoRaWAN sending interval, in s)"));
   }
 
   // Checks if OTAA is connected, or if payload should be sent.
@@ -96,7 +96,7 @@ namespace lorawan {
           printHex2(artKey[i]);
         }
         Serial.println();
-        Serial.print("  NwkSKey: ");
+        Serial.print(F("  NwkSKey: "));
         for (size_t i = 0; i < sizeof(nwkKey); ++i) {
           if (i != 0)
             Serial.print("-");
diff --git a/ampel-firmware/mqtt.cpp b/ampel-firmware/mqtt.cpp
index 5c0e67cb43fc0ad46bd80fd74278f54219ad3d40..cb0c5019c00d14094d6389684bb120eb061197f6 100644
--- a/ampel-firmware/mqtt.cpp
+++ b/ampel-firmware/mqtt.cpp
@@ -36,9 +36,9 @@ namespace mqtt {
     // mqttClient.setSocketTimeout(config::mqtt_timeout); //NOTE: somehow doesn't seem to have any effect on connect()
     mqttClient.setServer(config::mqtt_server, config::mqtt_port);
 
-    sensor_console::defineIntCommand("mqtt", setMQTTinterval, F(" 60 (Sets MQTT sending interval, in s)"));
+    sensor_console::defineIntCommand("mqtt", setMQTTinterval, F("60 (Sets MQTT sending interval, in s)"));
     sensor_console::defineCommand("send_local_ip", sendInfoAboutLocalNetwork,
-        F(" (Sends local IP and SSID via MQTT. Can be useful to find sensor)"));
+        F("(Sends local IP and SSID via MQTT. Can be useful to find sensor)"));
   }
 
   void publish(const char *timestamp, int16_t co2, float temperature, float humidity) {
@@ -79,7 +79,7 @@ namespace mqtt {
       command[i] = message[i];
     }
     command[length] = 0;
-    sensor_console::runCommand(command);
+    sensor_console::execute(command);
     led_effects::onBoardLEDOff();
   }
 
diff --git a/ampel-firmware/sensor_console.cpp b/ampel-firmware/sensor_console.cpp
index 5f1876ddda8f2405b4f1a2eea253408123408824..5fc3377ced8a4d77b9337fad19c71483159ac74c 100644
--- a/ampel-firmware/sensor_console.cpp
+++ b/ampel-firmware/sensor_console.cpp
@@ -6,75 +6,112 @@ namespace sensor_console {
 
   uint8_t commands_count = 0;
 
+  enum input_type {
+    NONE,
+    INT32,
+    STRING
+  };
+
   struct Command {
     const char *name;
     union {
+      void (*voidFunction)();
       void (*intFunction)(int32_t);
-      void (*voidFunction)(void);
+      void (*strFunction)(char*);
     };
     const char *doc;
-    bool has_parameter;
+    input_type parameter_type;
+  };
+
+  struct CommandLine {
+    char function_name[MAX_COMMAND_SIZE];
+    input_type argument_type;
+    int32_t int_argument;
+    char str_argument[MAX_COMMAND_SIZE];
   };
 
   Command commands[MAX_COMMANDS];
 
-  //NOTE: Probably possible to DRY (with templates?)
-  void defineCommand(const char *name, void (*function)(void), const __FlashStringHelper *doc_fstring) {
-    const char *doc = (const char*) doc_fstring;
+  bool addCommand(const char *name, const __FlashStringHelper *doc_fstring) {
     if (commands_count < MAX_COMMANDS) {
       commands[commands_count].name = name;
-      commands[commands_count].voidFunction = function;
-      commands[commands_count].doc = doc;
-      commands[commands_count].has_parameter = false;
-      commands_count++;
+      commands[commands_count].doc = (const char*) doc_fstring;
+      return true;
     } else {
       Serial.println(F("Too many commands have been defined."));
+      return false;
+    }
+  }
+
+  void defineCommand(const char *name, void (*function)(), const __FlashStringHelper *doc_fstring) {
+    if (addCommand(name, doc_fstring)) {
+      commands[commands_count].voidFunction = function;
+      commands[commands_count++].parameter_type = NONE;
     }
   }
 
   void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring) {
-    const char *doc = (const char*) doc_fstring;
-    if (commands_count < MAX_COMMANDS) {
-      commands[commands_count].name = name;
+    if (addCommand(name, doc_fstring)) {
       commands[commands_count].intFunction = function;
-      commands[commands_count].doc = doc;
-      commands[commands_count].has_parameter = true;
-      commands_count++;
-    } else {
-      Serial.println(F("Too many commands have been defined."));
+      commands[commands_count++].parameter_type = INT32;
+    }
+  }
+
+  void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring) {
+    if (addCommand(name, doc_fstring)) {
+      commands[commands_count].strFunction = function;
+      commands[commands_count++].parameter_type = STRING;
     }
   }
 
   /*
-   * Tries to split a string command (e.g. 'mqtt 60' or 'show_csv') into a function_name and an argument.
-   * Returns 0 if both are found, 1 if there is a problem and 2 if no argument is found.
+   * Tries to split a string command (e.g. 'mqtt 60' or 'show_csv') into
+   * a CommandLine struct (function_name, argument_type and argument)
    */
-  uint8_t parseCommand(const char *command, char *function_name, int32_t &argument) {
-    char split_command[MAX_COMMAND_SIZE];
-    strlcpy(split_command, command, MAX_COMMAND_SIZE);
-    char *arg;
-    char *part1;
-    part1 = strtok(split_command, " ");
-    if (!part1) {
+  void parseCommand(const char *command, CommandLine &command_line) {
+    if (strlen(command) == 0) {
       Serial.println(F("Received empty command"));
-      // Empty string
-      return 1;
+      command_line.argument_type = NONE;
+      return;
     }
-    strlcpy(function_name, part1, MAX_COMMAND_SIZE);
-    arg = strtok(NULL, " ");
-    uint8_t code = 0;
-    if (arg) {
-      char *end;
-      argument = strtol(arg, &end, 10);
-      if (*end) {
-        // Second argument isn't a number
-        code = 2;
-      }
+
+    char *first_space;
+    first_space = strchr(command, ' ');
+
+    if (first_space == NULL) {
+      command_line.argument_type = NONE;
+      strlcpy(command_line.function_name, command, MAX_COMMAND_SIZE);
+      return;
+    }
+
+    strlcpy(command_line.function_name, command, first_space - command + 1);
+    strlcpy(command_line.str_argument, first_space + 1, MAX_COMMAND_SIZE - (first_space - command) - 1);
+
+    char *end;
+    command_line.int_argument = strtol(command_line.str_argument, &end, 0); // Accepts 123 or 0xFF00FF
+
+    if (*end) {
+      command_line.argument_type = STRING;
     } else {
-      // No argument
-      code = 2;
+      command_line.argument_type = INT32;
+    }
+  }
+
+  int compareCommandNames(const void *s1, const void *s2) {
+    struct Command *c1 = (struct Command*) s1;
+    struct Command *c2 = (struct Command*) s2;
+    return strcmp(c1->name, c2->name);
+  }
+
+  void listAvailableCommands() {
+    qsort(commands, commands_count, sizeof(commands[0]), compareCommandNames);
+    for (uint8_t i = 0; i < commands_count; i++) {
+      Serial.print(F("  "));
+      Serial.print(commands[i].name);
+      Serial.print(F(" "));
+      Serial.print(commands[i].doc);
+      Serial.println(F("."));
     }
-    return code;
   }
 
   /*
@@ -88,7 +125,7 @@ namespace sensor_console {
     case '\n': // end of text
       Serial.println();
       input_line[input_pos] = 0;
-      runCommand(input_line);
+      execute(input_line);
       input_pos = 0;
       break;
     case '\r': // discard carriage return
@@ -112,50 +149,40 @@ namespace sensor_console {
     }
   }
 
-  int compareName(const void *s1, const void *s2) {
-    struct Command *c1 = (struct Command*) s1;
-    struct Command *c2 = (struct Command*) s2;
-    return strcmp(c1->name, c2->name);
-  }
-
-  void listAvailableCommands() {
-    qsort(commands, commands_count, sizeof(commands[0]), compareName);
-    for (uint8_t i = 0; i < commands_count; i++) {
-      Serial.print("  ");
-      Serial.print(commands[i].name);
-      Serial.print(commands[i].doc);
-      Serial.println(".");
-    }
-  }
-
   /*
-   * Tries to find the corresponding callback for a given command. Name and number of argument should fit.
+   * Tries to find the corresponding callback for a given command. Name and parameter type should fit.
    */
-  void runCommand(const char *command) {
-    char function_name[MAX_COMMAND_SIZE];
-    int32_t argument = 0;
-    bool has_argument;
-    has_argument = (parseCommand(command, function_name, argument) == 0);
-
+  void execute(const char *command_str) {
+    CommandLine input;
+    parseCommand(command_str, input);
     for (uint8_t i = 0; i < commands_count; i++) {
-      if (!strcmp(function_name, commands[i].name) && has_argument == commands[i].has_parameter) {
+      if (!strcmp(input.function_name, commands[i].name) && input.argument_type == commands[i].parameter_type) {
         Serial.print(F("Calling : "));
-        Serial.print(function_name);
-        if (has_argument) {
-          Serial.print(F("("));
-          Serial.print(argument);
-          Serial.println(F(")"));
-          commands[i].intFunction(argument);
-        } else {
+        Serial.print(input.function_name);
+        switch (input.argument_type) {
+        case NONE:
           Serial.println(F("()"));
           commands[i].voidFunction();
+          return;
+        case INT32:
+          Serial.print(F("("));
+          Serial.print(input.int_argument);
+          Serial.println(F(")"));
+          commands[i].intFunction(input.int_argument);
+          return;
+        case STRING:
+          Serial.print(F("('"));
+          Serial.print(input.str_argument);
+          Serial.println(F("')"));
+          commands[i].strFunction(input.str_argument);
+          return;
         }
-        return;
       }
     }
     Serial.print(F("'"));
-    Serial.print(command);
+    Serial.print(command_str);
     Serial.println(F("' not supported. Available commands :"));
     listAvailableCommands();
   }
+
 }
diff --git a/ampel-firmware/sensor_console.h b/ampel-firmware/sensor_console.h
index b46e212e06c308e15ba7497509c33ffd104932ad..5cf4450d19535d19e871f5d4d48b11d09521070e 100644
--- a/ampel-firmware/sensor_console.h
+++ b/ampel-firmware/sensor_console.h
@@ -8,11 +8,13 @@
  */
 
 namespace sensor_console {
-  void defineCommand(const char *command, void (*function)(void), const __FlashStringHelper *ifsh);
-  void defineIntCommand(const char *command, void (*function)(int32_t), const __FlashStringHelper *ifsh);
+  void defineCommand(const char *name, void (*function)(), const __FlashStringHelper *doc_fstring);
+  void defineIntCommand(const char *name, void (*function)(int32_t), const __FlashStringHelper *doc_fstring);
+  void defineStringCommand(const char *name, void (*function)(char*), const __FlashStringHelper *doc_fstring);
 
   void processSerialInput(const byte in_byte);
-  void runCommand(const char *command);
+
+  void execute(const char *command_line);
 }
 
 #endif
diff --git a/ampel-firmware/util.cpp b/ampel-firmware/util.cpp
index e3b2d6e8913172cce6e4dd868aace8c03e8be02f..841b08ff3a6b04d2dde6e39094d38c601f7d2e72 100644
--- a/ampel-firmware/util.cpp
+++ b/ampel-firmware/util.cpp
@@ -74,11 +74,11 @@ char* getSensorId() {
 
 Ampel::Ampel() :
     board(current_board), sensorId(getSensorId()), max_loop_duration(0) {
-  sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F(" 1618829570 (Sets time to the given UNIX time)"));
-  sensor_console::defineCommand("free", Ampel::showFreeSpace, F(" (Displays available heap space)"));
+  sensor_console::defineIntCommand("set_time", ntp::setLocalTime, F("1618829570 (Sets time to the given UNIX time)"));
+  sensor_console::defineCommand("free", Ampel::showFreeSpace, F("(Displays available heap space)"));
   sensor_console::defineCommand("reset", []() {
     ESP.restart();
-  }, F(" (Restarts the sensor)"));
+  }, F("(Restarts the sensor)"));
 }
 
 Ampel ampel;
diff --git a/ampel-firmware/web_server.cpp b/ampel-firmware/web_server.cpp
index c885ae9749ef8099544f941151d2e3edcf45ae2c..98d18fb6f98e6573f9df8d1689037833e341fbb3 100644
--- a/ampel-firmware/web_server.cpp
+++ b/ampel-firmware/web_server.cpp
@@ -292,7 +292,7 @@ namespace web_server {
     }
     http.sendHeader("Location", "/");
     http.send(303);
-    sensor_console::runCommand(http.arg("send").c_str());
+    sensor_console::execute(http.arg("send").c_str());
   }
 
   void handlePageNotFound() {
diff --git a/ampel-firmware/wifi_util.cpp b/ampel-firmware/wifi_util.cpp
index 335f94b45d8ca228496fa2957853e0ad4ba25511..4cdc7a2a597d3d66523c6e37b837346e5231311e 100644
--- a/ampel-firmware/wifi_util.cpp
+++ b/ampel-firmware/wifi_util.cpp
@@ -43,8 +43,8 @@ namespace wifi {
   // Initialize Wi-Fi
   void connect(const char *hostname) {
 
-    sensor_console::defineCommand("wifi_scan", scanNetworks, F(" (Scans available WiFi networks)"));
-    sensor_console::defineCommand("local_ip", showLocalIp, F(" (Displays local IP and current SSID)"));
+    sensor_console::defineCommand("wifi_scan", scanNetworks, F("(Scans available WiFi networks)"));
+    sensor_console::defineCommand("local_ip", showLocalIp, F("(Displays local IP and current SSID)"));
 
     //NOTE: WiFi Multi could allow multiple SSID and passwords.
     WiFi.persistent(false); // Don't write user & password to Flash.