     "<body>"
     "<center><h1>ESP8266 IR MQTT Server</h1></center>"
     "<br><hr>"
-    "<h3>Connection details</h3>"
-    "<p>IP address: " + WiFi.localIP().toString() + "</p>"
+    "<h3>Information</h3>"
+    "<p>IP address: " + WiFi.localIP().toString() + "<br>"
+    "Booted: " + timeSince(1) + "<br>" +
+    "IR Lib Version: " _IRREMOTEESP8266_VERSION_ "<br>"
+    "Total send requests: " + String(sendReqCounter) + "</p>"
 #ifdef MQTT_ENABLE
-    "<p>MQTT server: " MQTT_SERVER ":" + String(MQTT_PORT) + " ("+
-    (mqtt_client.connected() ? "Connected" : "Disconnected") + ")<br>"
+    "<h4>MQTT Information</h4>"
+    "<p>Server: " MQTT_SERVER ":" + String(MQTT_PORT) + " <i>(" +
+    (mqtt_client.connected() ? "Connected" : "Disconnected") + ")</i><br>"
+    "Client id: " + mqtt_clientid + "<br>"
     "Command topic: " MQTTcommand "<br>"
-    "Acknowledgements topic: " MQTTack "</p>"
+    "Acknowledgements topic: " MQTTack "<br>"
+    "Last command seen: " +
+    // lastMqttCmd is unescaped untrusted input.
+    // Avoid any possible HTML/XSS when displaying it.
+    (hasUnsafeHTMLChars(lastMqttCmd) ?
+        "<i>Contains unsafe HTML characters</i>" : lastMqttCmd) +
+    " <i>(" + timeSince(lastMqttCmdTime) + ")</i></p>"
 #endif  // MQTT_ENABLE
     "<br><hr>"
     "<h3>Hardcoded examples</h3>"

    case TROTEC:  // 28
    case TOSHIBA_AC:  // 32
    case FUJITSU_AC:  // 33
      parseStringAndSendAirCon(ir_type, code_str);
      break;
#if SEND_DENON

  uint32_t now = millis();
  Serial.printf("%07u.%03u: %s\n", now / 1000, now % 1000, str.c_str());
#endif  // DEBUG
}

String timeSince(uint32_t const start) {
  if (start == 0)
    return "Never";
  uint32_t diff = 0;
  uint32_t now = millis();
  if (start < now)
    diff = now - start;
  else
    diff = UINT32_MAX - start + now;
  diff /= 1000;  // Convert to seconds.
  if (diff == 0)  return "Now";

  // Note: millis() can only count up to 45 days, so uint8_t is safe.
  uint8_t days = diff / (60 * 60 * 24);
  uint8_t hours = (diff / (60 * 60)) % 24;
  uint8_t minutes = (diff / 60) % 60;
  uint8_t seconds = diff % 60;

  String result = "";
  if (days)
    result += String(days) + " day";
  if (days > 1)  result += "s";
  if (hours)
    result += " " + String(hours) + " hour";
  if (hours > 1)  result += "s";
  if (minutes)
    result += " " + String(minutes) + " minute";
  if (minutes > 1)  result += "s";
  if (seconds)
    result += " " + String(seconds) + " second";
  if (seconds > 1)  result += "s";
  result.trim();
  return result + " ago";
}

// Quick and dirty check for any unsafe chars in a string
// that may cause HTML shenanigans. e.g. An XSS.
bool hasUnsafeHTMLChars(String input) {
  static char unsafe[] = "';!-\"<>=&{}()";
  for (uint8_t i = 0; unsafe[i]; i++)
    if (input.indexOf(unsafe[i]) != -1) return true;
  return false;
}

// Root web page with example usage etc.
