From e46fe9e4d3e19d0f172d2dc4b7f669ad2da66845 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Thu, 10 Oct 2019 19:59:52 +0200 Subject: [PATCH 1/2] Remove double /* to fix compiler error --- TWANG32/TWANG32.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/TWANG32/TWANG32.ino b/TWANG32/TWANG32.ino index ac6eeeb..2507b0c 100644 --- a/TWANG32/TWANG32.ino +++ b/TWANG32/TWANG32.ino @@ -1170,7 +1170,6 @@ void getInput(){ // -------------- SFX -------------- // --------------------------------- -/* /* This is used sweep across (up or down) a frequency range for a specified duration. A sin based warble is added to the frequency. This function is meant to be called From 6375c8e2c0be4ff50da8b29f8bfbdd16ba4213a5 Mon Sep 17 00:00:00 2001 From: Georg Gadinger Date: Thu, 10 Oct 2019 20:18:17 +0200 Subject: [PATCH 2/2] Add /metrics endpoint to be used with Prometheus --- TWANG32/config.h | 4 +- TWANG32/wifi_ap.h | 248 +++++++++++++++++++++++++++------------------- 2 files changed, 147 insertions(+), 105 deletions(-) diff --git a/TWANG32/config.h b/TWANG32/config.h index fa93e1e..a52cbb4 100644 --- a/TWANG32/config.h +++ b/TWANG32/config.h @@ -64,6 +64,8 @@ #define MIN_REDRAW_INTERVAL 1000.0 / 60.0 // divide by frames per second..if you tweak adjust player speed #endif - +// Comment or remove the next #define to disable the /metrics endpoint on the HTTP server. +// This endpoint provides the Twang32 stats for ingestion via Prometheus. +#define ENABLE_PROMETHEUS_METRICS_ENDPOINT #endif diff --git a/TWANG32/wifi_ap.h b/TWANG32/wifi_ap.h index d880693..faf6a24 100644 --- a/TWANG32/wifi_ap.h +++ b/TWANG32/wifi_ap.h @@ -1,7 +1,7 @@ #include #include "settings.h" -const char* ssid = "TWANG_AP"; +const char* ssid = "TWANG_AP"; const char* passphrase = "esp32rocks"; WiFiServer server(80); @@ -9,146 +9,186 @@ WiFiServer server(80); char linebuf[80]; int charcount=0; +enum PAGE_TO_SEND +{ + Stats, + Metrics +}; + void ap_setup() { - bool ret; - - + bool ret; - /* - * Set up an access point - * @param ssid Pointer to the SSID (max 63 char). - * @param passphrase (for WPA2 min 8 char, for open use NULL) - * @param channel WiFi channel number, 1 - 13. - * @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID) - */ - ret = WiFi.softAP(ssid, passphrase, 2, 0); - - //Serial.println("\r\nWiFi AP online ..."); - server.begin(); - + /* + * Set up an access point + * @param ssid Pointer to the SSID (max 63 char). + * @param passphrase (for WPA2 min 8 char, for open use NULL) + * @param channel WiFi channel number, 1 - 13. + * @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID) + */ + ret = WiFi.softAP(ssid, passphrase, 2, 0); + //Serial.println("\r\nWiFi AP online ..."); + server.begin(); } void sendStatsPage(WiFiClient client) { - // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) - // and a content-type so the client knows what's coming, then a blank line: - client.println("HTTP/1.1 200 OK"); - client.println("Content-type:text/html"); - client.println(); - client.println(""); - client.println(""); - client.println("

TWANG32 Play Stats

"); - client.println("
    "); - - - client.print("
  • Games played: "); client.print(user_settings.games_played); client.println("
  • "); - if (user_settings.games_played > 0) { // prevent divide by 0 + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + client.println(""); + client.println(""); + client.println("

    TWANG32 Play Stats

    "); + client.println("
      "); + + client.print("
    • Games played: "); client.print(user_settings.games_played); client.println("
    • "); + if (user_settings.games_played > 0) { // prevent divide by 0 client.print("
    • Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("
    • "); - } - client.print("
    • High score: "); client.print(user_settings.high_score); client.println("
    • "); - client.print("
    • Boss kills: "); client.print(user_settings.boss_kills); client.println("
    • "); - + } + client.print("
    • High score: "); client.print(user_settings.high_score); client.println("
    • "); + client.print("
    • Boss kills: "); client.print(user_settings.boss_kills); client.println("
    • "); + client.print(""); - + client.print("

      Adjustable Settings

      "); - + client.print(""); - - - client.print(""); - - client.print(""); - + client.print(""); - + client.print(""); - + client.print(""); - + client.print(""); - - client.print("
      "); + + + client.print("
      "); client.print("LED Count (60-"); - client.print(MAX_LEDS); - client.print(")
      Brightness (10-255)
      Sound Volume (0-255)
      Joystick Deadzone (3-12)
      Attack Sensitivity (20000-35000)
      Lives Per Level (3-9)
      "); - - client.println(""); - client.println(""); - client.println(); - + + client.print(""); + +#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT + client.println(""); +#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT + + client.println(""); + client.println(""); + client.println(); + } +#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT +// We need to use print() here since println() prints newlines as CR/LF, which +// Prometheus cannot handle. +#define __prom_metric(metric_name, metric_description, value) \ + client.print("# HELP " metric_name " " metric_description "\n"); \ + client.print("# TYPE " metric_name " gauge\n"); \ + client.print(metric_name " "); \ + client.print(value); \ + client.print("\n"); + +static void sendMetricsPage(WiFiClient client) +{ + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/plain; charset=utf-8"); + client.println("Server: twang_exporter"); + client.println(); + __prom_metric("twang_games_played", "Number of games played", user_settings.games_played); + __prom_metric("twang_total_points", "Total points", user_settings.total_points); + __prom_metric("twang_high_score", "High score", user_settings.high_score); + __prom_metric("twang_boss_kills", "Boss kills", user_settings.boss_kills); +} + +#undef __prom_metric +#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT + void ap_client_check(){ - int cnt; - bool newconn=false; - int stat; - WiFiClient client = server.available(); // listen for incoming clients + int cnt; + bool newconn=false; + int stat; + WiFiClient client = server.available(); // listen for incoming clients - //if (client) { // if you get a client, - // sendStatsPage(client); - // Serial.println("printUploadForm"); - //} bool currentLineIsBlank = true; - + PAGE_TO_SEND page_to_send = Stats; + while (client.connected()) { - if (client.available()) { - char c = client.read(); - //Serial.write(c); - linebuf[charcount]=c; - if (charcount 0) - { - String line = String(linebuf); - - int start = line.indexOf('=', 0); - - char paramCode = line.charAt(start - 1); - - int finish = line.indexOf('H', start+1)-1; - String val = line.substring(start+1, finish); - // if it is not numeric, it will convert to 0. - // The the change_setting function will make sure the range is OK - - change_setting(paramCode, val.toInt()); - - - } - - // you're starting a new line - currentLineIsBlank = true; - memset(linebuf,0,sizeof(linebuf)); - charcount=0; - } else if (c != '\r') { - // you've gotten a character on the current line - currentLineIsBlank = false; - } - + break; } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + + if (strstr(linebuf,"GET /?") > 0) + { + String line = String(linebuf); + + int start = line.indexOf('=', 0); + + char paramCode = line.charAt(start - 1); + + int finish = line.indexOf('H', start+1)-1; + String val = line.substring(start+1, finish); + // if it is not numeric, it will convert to 0. + // The the change_setting function will make sure the range is OK + + change_setting(paramCode, val.toInt()); + + page_to_send = Stats; + } +#ifdef ENABLE_PROMETHEUS_METRICS_ENDPOINT + else if (strstr(linebuf, "GET /metrics")) + { + page_to_send = Metrics; + } +#endif // ENABLE_PROMETHEUS_METRICS_ENDPOINT + + // you're starting a new line + currentLineIsBlank = true; + memset(linebuf,0,sizeof(linebuf)); + charcount=0; + } else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } } - }