Stream AMG8833 via WiFi AP

Hi guys, just getting into wifi stuff now with the ESP32 and I am a bit stuck..

I would like to run the following sketch as an access point rather that a server (I hope I am using the right terminoligy)

Basically instead of connecting my ESP32 to my router then connecting to it via the router, I would like to be able to connect directly to the ESP32.

Any tips?

#include <WiFi.h> // Part of ESP32 board libraries
#include <WebServer.h> // Part of ESP32 board libraries
#include <WebSocketsServer.h> // Installed "WebSockets" library
#include <Adafruit_AMG88xx.h> // Installed "Adafruit_AMG88xx" library

Adafruit_AMG88xx amg;

float pixels[AMG88xx_PIXEL_ARRAY_SIZE];

WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);

char* ssid = "wifi_ssid_to_connect_to";
char* password = "wifi_password";

char webpage[] PROGMEM = R"=====(
<html>
<head>
	<style>
		#thermcam td {
		  width: 30;
		  height: 30;
		}
	</style>
	<script>
		var Socket;
		var streamframestimer;
		var sizesensor = [8,8];
		var minTsensor = 0.0;
		var maxTsensor = 80.0;
		var minT = 15.0; // initial low range of the sensor (this will be blue on the screen)
		var maxT = 50.0; // initial high range of the sensor (this will be red on the screen)
		var currentFrame = [];
		var minTframe = maxTsensor;
		var maxTframe = minTsensor;
		var minTframelocation = [0,0];
		var maxTframelocation = [0,0];
		var camColors = [
		"1500BF", "0900BF", "0003C0", "0010C0", "001DC1", "002AC2", "0037C2", "0044C3",
		"0052C3", "005FC4", "006DC5", "007AC5", "0088C6", "0095C6", "00A3C7", "00B1C8",
		"00BFC8", "00C9C4", "00C9B8", "00CAAB", "00CB9E", "00CB90", "00CC83", "00CC76",
		"00CD68", "00CE5B", "00CE4D", "00CF40", "00CF32", "00D024", "00D116", "00D109",
		"05D200", "13D200", "21D300", "2FD400", "3DD400", "4CD500", "5AD500", "69D600",
		"78D700", "86D700", "95D800", "A4D800", "B3D900", "C2DA00", "D1DA00", "DBD500",
		"DBC700", "DCB900", "DDAA00", "DD9C00", "DE8E00", "DE7F00", "DF7100", "E06200",
		"E05300", "E14400", "E13500", "E22600", "E31700", "E30800", "E40006", "E50015",
		];
		function mapto( val, minin, maxin, minout ,maxout ){
			if ( val >= maxin ){
				return maxout;
			} else if ( val <= minin ){
				return minout;
			} else {
				return ((( ( maxout - minout )/( maxin - minin ) ) * val ) + ( minout - ( ( maxout - minout )/( maxin - minin ) ) * minin ));
			}
		}
		function adjusttemrange(range,adjustment){
			if ( range == "min" ){
				if ( adjustment == 0){
					minT = minTframe;
				} else {
					minT += adjustment;
				}
			}
			if ( range == "max" ){
				if ( adjustment == 0){
					maxT = maxTframe;
				} else {
					maxT += adjustment;
				}
			}
			if ( minT < minTsensor ){
				minT = minTsensor;
			}
			if ( maxT > maxTsensor ){
				maxT = maxTsensor;
			}
			if ( minT >= maxT ){
				minT = maxT - 1.0;
			}
			fillthermcamtable(currentFrame);
			document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
			document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
		}
		function ctof(tempc){
			return (tempc * ( 9 / 5 ) ) + 32;
		}
		function buildthermcamtable(){
			var thermcamTable = document.getElementById("thermcam");
			for(i=0;i<sizesensor[0];i++){
				var row = thermcamTable.insertRow(i);
				for(j=0;j<sizesensor[1];j++){
					var cell = row.insertCell(j);
					cell.id = "tccell"+((i*8)+j);
				}
			}
		}
		function fillthermcamtable(pixelarray){
			minTframe = maxTsensor;
			maxTframe = minTsensor;
			// Fill table
			// Temps in C and F in cells
			// BG color of cells use camColors
			// Update minTframe and maxTframe
			for(i=0;i<sizesensor[0];i++){
				for(j=0;j<sizesensor[1];j++){
					var idx = ((i*8)+j);
					var cell = document.getElementById("tccell"+idx);
					var camcolorvalue = Math.round( mapto( pixelarray[idx], minT , maxT, 0 ,63 ) );
					cell.innerHTML = pixelarray[idx].toFixed(2) + "C " + ctof( pixelarray[idx] ).toFixed(2) + "F";
					cell.style.backgroundColor = "#" + camColors[camcolorvalue];
					cell.className = "camcolorvalue" + camcolorvalue;
					if ( pixelarray[idx] < minTframe ){
						minTframe = pixelarray[idx];
						minTframelocation = [j,i];
					}
					if ( pixelarray[idx] > maxTframe ){
						maxTframe = pixelarray[idx];
						maxTframelocation = [j,i];
					}
				}
			}
			document.getElementById("minTframedata").innerHTML = minTframe.toFixed(2) + "C " + ctof( minTframe ).toFixed(2) + "F (" + minTframelocation[0] + "," + minTframelocation[1] + ")";
			document.getElementById("maxTframedata").innerHTML = maxTframe.toFixed(2) + "C " + ctof( maxTframe ).toFixed(2) + "F (" + maxTframelocation[0] + "," + maxTframelocation[1] + ")";
		}
		function init() {
			// Build table
			buildthermcamtable();
			document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
			document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
			Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
			Socket.onmessage = function(event){
				if ( event.data[0] == '[' ){
					currentFrame = JSON.parse(event.data);
					fillthermcamtable(currentFrame);
				}
			}
		}
		function sendText(){
			Socket.send(document.getElementById("txBar").value);
			document.getElementById("txBar").value = "";
		}
		function getframe(){
			Socket.send("F");
		}
		function streamframes(){
			streamframestimer = setTimeout( streamframes , 200 );
			getframe();
		}
		function stopstreamframes(){
			clearTimeout( streamframestimer );
		}
	</script>
</head>
<body onload="init()">
	<table id="thermcam">
	</table>
	<hr/>
	<table id="thermcamcontrols">
		<tr>
			<td>Min Temp</td>
			<td id="minT"></td>
			<td><button type="button" onclick="adjusttemrange('min',-5);">-5C</button></td>
			<td><button type="button" onclick="adjusttemrange('min',-1);">-1C</button></td>
			<td><button type="button" onclick="adjusttemrange('min', 0);">lowest in current frame</button></td>
			<td><button type="button" onclick="adjusttemrange('min',+1);">+1C</button></td>
			<td><button type="button" onclick="adjusttemrange('min',+5);">+5C</button></td>
			<td id="minTframedata"></td>
		</tr>
		<tr>
			<td>Max Temp</td>
			<td id="maxT"></td>
			<td><button type="button" onclick="adjusttemrange('max',-5);">-5C</button></td>
			<td><button type="button" onclick="adjusttemrange('max',-1);">-1C</button></td>
			<td><button type="button" onclick="adjusttemrange('max', 0);">highest in current frame</button></td>
			<td><button type="button" onclick="adjusttemrange('max',+1);">+1C</button></td>
			<td><button type="button" onclick="adjusttemrange('max',+5);">+5C</button></td>
			<td id="maxTframedata"></td>
		</tr>
	</table>
	<hr/>
	<div>
		<button type="button" onclick="getframe();">Get Frame</button>
		<button type="button" onclick="streamframes();">Start Stream Frames</button>
		<button type="button" onclick="stopstreamframes();">Stop Stream Frames</button>
	</div>
</body>
</html>
)=====";

void setup()
{
  WiFi.begin(ssid,password);
  Serial.begin(115200);
  while(WiFi.status()!=WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  server.on("/",[](){
    server.send_P(200, "text/html", webpage);  
  });
  server.begin();
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

  Wire.begin(13,15); // AMG8833 sensor usin 13 as SDA and 15 as SCL
 if (!amg.begin()) {
    Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
    while (1);
  }
}

void loop()
{
  webSocket.loop();
  server.handleClient();
  if(Serial.available() > 0){
    char c[] = {(char)Serial.read()};
    webSocket.broadcastTXT(c, sizeof(c));
  }
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){
  if(type == WStype_TEXT){
    if(payload[0] == 'F'){ // i.e. "Frame"
		amg.readPixels(pixels);

		String thermalFrame = "[";

		for (int i = 1; i < AMG88xx_PIXEL_ARRAY_SIZE + 1; i++) { // Starts at 1 so that (i % 8) will be 0 at end of 8 pixels and newline will be added
			thermalFrame += pixels[i - 1];
			if ( i != AMG88xx_PIXEL_ARRAY_SIZE ){
				thermalFrame += ", ";
				if ( i % 8 == 0 ) thermalFrame += "\n";
			}
		}
		thermalFrame += "]";

		char tf[thermalFrame.length()+1];

		thermalFrame.toCharArray( tf, thermalFrame.length()+1 );

		Serial.println(tf);

		webSocket.broadcastTXT(tf, sizeof(tf)-1);

    } else{
      for(int i = 0; i < length; i++)
        Serial.print((char) payload[i]);
      Serial.println();
    }
  }
  
}

Check out this tutorial about different mode https://randomnerdtutorials.com/esp32-useful-wi-fi-functions-arduino/#1

The ESP32 library comes with an example that does exactly that. It is under

File -> Examples -> WiFi -> WiFiAccessPoint

It starts an access point and serves a simple web page. You will still run a server. That is the part that is serving the web page. The access point is the part that creates a WiFi network, where you connect your computer/phone to a SSID and type in the WiFi password.

1 Like

I have been playing around but I cant seem to get it working.

Here is what I have so far:

#include <WiFi.h>
#include <WiFiClient.h>
#include <WiFiAP.h>

#define LED_BUILTIN 2   // Set the GPIO pin where you connected your test LED or comment this line out if your dev board has a built-in LED


#include <WebSocketsServer.h> // Installed "WebSockets" library
#include <Adafruit_AMG88xx.h> // Installed "Adafruit_AMG88xx" library

// Set these to your desired credentials.
const char *ssid = "yourAP";
const char *password = "yourPassword";
char webpage[] PROGMEM = R"=====(
<html>
<head>
  <style>
    #thermcam td {
      width: 30;
      height: 30;
    }
  </style>
  <script>
    var Socket;
    var streamframestimer;
    var sizesensor = [8,8];
    var minTsensor = 0.0;
    var maxTsensor = 80.0;
    var minT = 15.0; // initial low range of the sensor (this will be blue on the screen)
    var maxT = 50.0; // initial high range of the sensor (this will be red on the screen)
    var currentFrame = [];
    var minTframe = maxTsensor;
    var maxTframe = minTsensor;
    var minTframelocation = [0,0];
    var maxTframelocation = [0,0];
    var camColors = [
    "1500BF", "0900BF", "0003C0", "0010C0", "001DC1", "002AC2", "0037C2", "0044C3",
    "0052C3", "005FC4", "006DC5", "007AC5", "0088C6", "0095C6", "00A3C7", "00B1C8",
    "00BFC8", "00C9C4", "00C9B8", "00CAAB", "00CB9E", "00CB90", "00CC83", "00CC76",
    "00CD68", "00CE5B", "00CE4D", "00CF40", "00CF32", "00D024", "00D116", "00D109",
    "05D200", "13D200", "21D300", "2FD400", "3DD400", "4CD500", "5AD500", "69D600",
    "78D700", "86D700", "95D800", "A4D800", "B3D900", "C2DA00", "D1DA00", "DBD500",
    "DBC700", "DCB900", "DDAA00", "DD9C00", "DE8E00", "DE7F00", "DF7100", "E06200",
    "E05300", "E14400", "E13500", "E22600", "E31700", "E30800", "E40006", "E50015",
    ];
    function mapto( val, minin, maxin, minout ,maxout ){
      if ( val >= maxin ){
        return maxout;
      } else if ( val <= minin ){
        return minout;
      } else {
        return ((( ( maxout - minout )/( maxin - minin ) ) * val ) + ( minout - ( ( maxout - minout )/( maxin - minin ) ) * minin ));
      }
    }
    function adjusttemrange(range,adjustment){
      if ( range == "min" ){
        if ( adjustment == 0){
          minT = minTframe;
        } else {
          minT += adjustment;
        }
      }
      if ( range == "max" ){
        if ( adjustment == 0){
          maxT = maxTframe;
        } else {
          maxT += adjustment;
        }
      }
      if ( minT < minTsensor ){
        minT = minTsensor;
      }
      if ( maxT > maxTsensor ){
        maxT = maxTsensor;
      }
      if ( minT >= maxT ){
        minT = maxT - 1.0;
      }
      fillthermcamtable(currentFrame);
      document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
      document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
    }
    function ctof(tempc){
      return (tempc * ( 9 / 5 ) ) + 32;
    }
    function buildthermcamtable(){
      var thermcamTable = document.getElementById("thermcam");
      for(i=0;i<sizesensor[0];i++){
        var row = thermcamTable.insertRow(i);
        for(j=0;j<sizesensor[1];j++){
          var cell = row.insertCell(j);
          cell.id = "tccell"+((i*8)+j);
        }
      }
    }
    function fillthermcamtable(pixelarray){
      minTframe = maxTsensor;
      maxTframe = minTsensor;
      // Fill table
      // Temps in C and F in cells
      // BG color of cells use camColors
      // Update minTframe and maxTframe
      for(i=0;i<sizesensor[0];i++){
        for(j=0;j<sizesensor[1];j++){
          var idx = ((i*8)+j);
          var cell = document.getElementById("tccell"+idx);
          var camcolorvalue = Math.round( mapto( pixelarray[idx], minT , maxT, 0 ,63 ) );
          cell.innerHTML = pixelarray[idx].toFixed(2) + "C " + ctof( pixelarray[idx] ).toFixed(2) + "F";
          cell.style.backgroundColor = "#" + camColors[camcolorvalue];
          cell.className = "camcolorvalue" + camcolorvalue;
          if ( pixelarray[idx] < minTframe ){
            minTframe = pixelarray[idx];
            minTframelocation = [j,i];
          }
          if ( pixelarray[idx] > maxTframe ){
            maxTframe = pixelarray[idx];
            maxTframelocation = [j,i];
          }
        }
      }
      document.getElementById("minTframedata").innerHTML = minTframe.toFixed(2) + "C " + ctof( minTframe ).toFixed(2) + "F (" + minTframelocation[0] + "," + minTframelocation[1] + ")";
      document.getElementById("maxTframedata").innerHTML = maxTframe.toFixed(2) + "C " + ctof( maxTframe ).toFixed(2) + "F (" + maxTframelocation[0] + "," + maxTframelocation[1] + ")";
    }
    function init() {
      // Build table
      buildthermcamtable();
      document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
      document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
      Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
      Socket.onmessage = function(event){
        if ( event.data[0] == '[' ){
          currentFrame = JSON.parse(event.data);
          fillthermcamtable(currentFrame);
        }
      }
    }
    function sendText(){
      Socket.send(document.getElementById("txBar").value);
      document.getElementById("txBar").value = "";
    }
    function getframe(){
      Socket.send("F");
    }
    function streamframes(){
      streamframestimer = setTimeout( streamframes , 200 );
      getframe();
    }
    function stopstreamframes(){
      clearTimeout( streamframestimer );
    }
  </script>
</head>
<body onload="init()">
  <table id="thermcam">
  </table>
  <hr/>
  <table id="thermcamcontrols">
    <tr>
      <td>Min Temp</td>
      <td id="minT"></td>
      <td><button type="button" onclick="adjusttemrange('min',-5);">-5C</button></td>
      <td><button type="button" onclick="adjusttemrange('min',-1);">-1C</button></td>
      <td><button type="button" onclick="adjusttemrange('min', 0);">lowest in current frame</button></td>
      <td><button type="button" onclick="adjusttemrange('min',+1);">+1C</button></td>
      <td><button type="button" onclick="adjusttemrange('min',+5);">+5C</button></td>
      <td id="minTframedata"></td>
    </tr>
    <tr>
      <td>Max Temp</td>
      <td id="maxT"></td>
      <td><button type="button" onclick="adjusttemrange('max',-5);">-5C</button></td>
      <td><button type="button" onclick="adjusttemrange('max',-1);">-1C</button></td>
      <td><button type="button" onclick="adjusttemrange('max', 0);">highest in current frame</button></td>
      <td><button type="button" onclick="adjusttemrange('max',+1);">+1C</button></td>
      <td><button type="button" onclick="adjusttemrange('max',+5);">+5C</button></td>
      <td id="maxTframedata"></td>
    </tr>
  </table>
  <hr/>
  <div>
    <button type="button" onclick="getframe();">Get Frame</button>
    <button type="button" onclick="streamframes();">Start Stream Frames</button>
    <button type="button" onclick="stopstreamframes();">Stop Stream Frames</button>
  </div>
</body>
</html>
)=====";

Adafruit_AMG88xx amg;
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
WiFiServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);
  Serial.println();
  Serial.println("Configuring access point...");

  // You can remove the password parameter if you want the AP to be open.
  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
  server.begin();

  Serial.println("Server started");



  webSocket.begin();
  webSocket.onEvent(webSocketEvent);
  Wire.begin();
amg.begin();

  
}

void loop() {
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("New Client.");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        webSocket.loop();
  server.handleClient();
  if(Serial.available() > 0){
    char c[] = {(char)Serial.read()};
    webSocket.broadcastTXT(c, sizeof(c));
  } 
    }
    // close the connection:
    client.stop();
    Serial.println("Client Disconnected.");
  }
}
}


void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){
  if(type == WStype_TEXT){
    if(payload[0] == 'F'){ // i.e. "Frame"
    amg.readPixels(pixels);

    String thermalFrame = "[";

    for (int i = 1; i < AMG88xx_PIXEL_ARRAY_SIZE + 1; i++) { // Starts at 1 so that (i % 8) will be 0 at end of 8 pixels and newline will be added
      thermalFrame += pixels[i - 1];
      if ( i != AMG88xx_PIXEL_ARRAY_SIZE ){
        thermalFrame += ", ";
        if ( i % 8 == 0 ) thermalFrame += "\n";
      }
    }
    thermalFrame += "]";

    char tf[thermalFrame.length()+1];

    thermalFrame.toCharArray( tf, thermalFrame.length()+1 );

    Serial.println(tf);

    webSocket.broadcastTXT(tf, sizeof(tf)-1);

    } else{
      for(int i = 0; i < length; i++)
        Serial.print((char) payload[i]);
      Serial.println();
    }
  }
  
}

But I get the following error message:

C:\Users\MickW\AppData\Local\Temp\arduino_modified_sketch_910285\WiFiAccessPoint.ino: In function 'void loop()':
WiFiAccessPoint:242:10: error: 'class WiFiServer' has no member named 'handleClient'
   server.handleClient();
          ^
Multiple libraries were found for "WiFi.h"
 Used: C:\Users\MickW\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi
 Not used: C:\Program Files (x86)\Arduino\libraries\WiFi
Using library WiFi at version 1.0 in folder: C:\Users\MickW\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFi 
Using library arduinoWebSockets-master at version 2.3.6 in folder: C:\Users\MickW\Documents\Arduino\libraries\arduinoWebSockets-master 
Using library WiFiClientSecure at version 1.0 in folder: C:\Users\MickW\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\WiFiClientSecure 
Using library Adafruit_AMG88xx_Library at version 1.1.0 in folder: C:\Users\MickW\Documents\Arduino\libraries\Adafruit_AMG88xx_Library 
Using library Wire at version 1.0.1 in folder: C:\Users\MickW\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.6\libraries\Wire 
exit status 1
'class WiFiServer' has no member named 'handleClient'

If I comment out server.handleClient(); The code compiles but the page is not served (times out)

Unfortunately its not my code, so Im not super familiar with it. It was designed to run as a server rather than an AP, any help to modify it to work would be greatly appreciated.

Solved!
I figured it out. I was trying to add an extra library to handle the access point, turns out It was unnecesary :slight_smile:

Here is the code incase anyone else wants to do the same thing (I also added my ironbow color pallete :wink: )

#include <WiFi.h> // Part of ESP32 board libraries
#include <WebServer.h> // Part of ESP32 board libraries
#include <WebSocketsServer.h> // Installed "WebSockets" library
#include <Adafruit_AMG88xx.h> // Installed "Adafruit_AMG88xx" library

Adafruit_AMG88xx amg;

float pixels[AMG88xx_PIXEL_ARRAY_SIZE];

WebServer server;
WebSocketsServer webSocket = WebSocketsServer(81);

char* ssid = "wifi_ssid_to_connect_to";
char* password = "wifi_password";

char webpage[] PROGMEM = R"=====(
<html>
<head>
  <style>
    #thermcam td {
      width: 60;
      height: 60;
    }
    #thermcam {
    border-spacing: 0;
    }
    
  </style>
  <script>
    var Socket;
    var streamframestimer;
    var sizesensor = [8,8];
    var minTsensor = 0.0;
    var maxTsensor = 80.0;
    var minT = 15.0; // initial low range of the sensor (this will be blue on the screen)
    var maxT = 50.0; // initial high range of the sensor (this will be red on the screen)
    var currentFrame = [];
    var minTframe = maxTsensor;
    var maxTframe = minTsensor;
    var minTframelocation = [0,0];
    var maxTframelocation = [0,0];
    var camColors = [
    "00000a","000014","00001e","000025","00002a","00002e","000032","000036","00003a","00003e","000042",
    "000046","00004a","00004f","000052","010055","010057","020059","02005c","03005e","040061","040063",
    "050065","060067","070069","08006b","09006e","0a0070","0b0073","0c0074","0d0075","0d0076","0e0077",
    "100078","120079","13007b","15007c","17007d","19007e","1b0080","1c0081","1e0083","200084","220085",
    "240086","260087","280089","2a0089","2c008a","2e008b","30008c","32008d","34008e","36008e","38008f",
    "390090","3b0091","3c0092","3e0093","3f0093","410094","420095","440095","450096","470096","490096",
    "4a0096","4c0097","4e0097","4f0097","510097","520098","540098","560098","580099","5a0099","5c0099",
    "5d009a","5f009a","61009b","63009b","64009b","66009b","68009b","6a009b","6c009c","6d009c","6f009c",
    "70009c","71009d","73009d","75009d","77009d","78009d","7a009d","7c009d","7e009d","7f009d","81009d",
    "83009d","84009d","86009d","87009d","89009d","8a009d","8b009d","8d009d","8f009c","91009c","93009c",
    "95009c","96009b","98009b","99009b","9b009b","9c009b","9d009b","9f009b","a0009b","a2009b","a3009b",
    "a4009b","a6009a","a7009a","a8009a","a90099","aa0099","ab0099","ad0099","ae0198","af0198","b00198",
    "b00198","b10197","b20197","b30196","b40296","b50295","b60295","b70395","b80395","b90495","ba0495",
    "ba0494","bb0593","bc0593","bd0593","be0692","bf0692","bf0692","c00791","c00791","c10890","c10990",
    "c20a8f","c30a8e","c30b8e","c40c8d","c50c8c","c60d8b","c60e8a","c70f89","c81088","c91187","ca1286",
    "ca1385","cb1385","cb1484","cc1582","cd1681","ce1780","ce187e","cf187c","cf197b","d01a79","d11b78",
    "d11c76","d21c75","d21d74","d31e72","d32071","d4216f","d4226e","d5236b","d52469","d62567","d72665",
    "d82764","d82862","d92a60","da2b5e","da2c5c","db2e5a","db2f57","dc2f54","dd3051","dd314e","de324a",
    "de3347","df3444","df3541","df363d","e0373a","e03837","e03933","e13a30","e23b2d","e23c2a","e33d26",
    "e33e23","e43f20","e4411d","e4421c","e5431b","e54419","e54518","e64616","e74715","e74814","e74913",
    "e84a12","e84c10","e84c0f","e94d0e","e94d0d","ea4e0c","ea4f0c","eb500b","eb510a","eb520a","eb5309",
    "ec5409","ec5608","ec5708","ec5808","ed5907","ed5a07","ed5b06","ee5c06","ee5c05","ee5d05","ee5e05",
    "ef5f04","ef6004","ef6104","ef6204","f06303","f06403","f06503","f16603","f16603","f16703","f16803",
    "f16902","f16a02","f16b02","f16b02","f26c01","f26d01","f26e01","f36f01","f37001","f37101","f37201",
    "f47300","f47400","f47500","f47600","f47700","f47800","f47a00","f57b00","f57c00","f57e00","f57f00",
    "f68000","f68100","f68200","f78300","f78400","f78500","f78600","f88700","f88800","f88800","f88900",
    "f88a00","f88b00","f88c00","f98d00","f98d00","f98e00","f98f00","f99000","f99100","f99200","f99300",
    "fa9400","fa9500","fa9600","fb9800","fb9900","fb9a00","fb9c00","fc9d00","fc9f00","fca000","fca100",
    "fda200","fda300","fda400","fda600","fda700","fda800","fdaa00","fdab00","fdac00","fdad00","fdae00",
    "feaf00","feb000","feb100","feb200","feb300","feb400","feb500","feb600","feb800","feb900","feb900",
    "feba00","febb00","febc00","febd00","febe00","fec000","fec100","fec200","fec300","fec400","fec500",
    "fec600","fec700","fec800","fec901","feca01","feca01","fecb01","fecc02","fecd02","fece03","fecf04",
    "fecf04","fed005","fed106","fed308","fed409","fed50a","fed60a","fed70b","fed80c","fed90d","ffda0e",
    "ffda0e","ffdb10","ffdc12","ffdc14","ffdd16","ffde19","ffde1b","ffdf1e","ffe020","ffe122","ffe224",
    "ffe226","ffe328","ffe42b","ffe42e","ffe531","ffe635","ffe638","ffe73c","ffe83f","ffe943","ffea46",
    "ffeb49","ffeb4d","ffec50","ffed54","ffee57","ffee5b","ffee5f","ffef63","ffef67","fff06a","fff06e",
    "fff172","fff177","fff17b","fff280","fff285","fff28a","fff38e","fff492","fff496","fff49a","fff59e",
    "fff5a2","fff5a6","fff6aa","fff6af","fff7b3","fff7b6","fff8ba","fff8bd","fff8c1","fff8c4","fff9c7",
    "fff9ca","fff9cd","fffad1","fffad4","fffbd8","fffcdb","fffcdf","fffde2","fffde5","fffde8","fffeeb",
    "fffeee","fffef1","fffef4","fffff6"
    ];
    function mapto( val, minin, maxin, minout ,maxout ){
      if ( val >= maxin ){
        return maxout;
      } else if ( val <= minin ){
        return minout;
      } else {
        return ((( ( maxout - minout )/( maxin - minin ) ) * val ) + ( minout - ( ( maxout - minout )/( maxin - minin ) ) * minin ));
      }
    }
    function adjusttemrange(range,adjustment){
      if ( range == "min" ){
        if ( adjustment == 0){
          minT = minTframe;
        } else {
          minT += adjustment;
        }
      }
      if ( range == "max" ){
        if ( adjustment == 0){
          maxT = maxTframe;
        } else {
          maxT += adjustment;
        }
      }
      if ( minT < minTsensor ){
        minT = minTsensor;
      }
      if ( maxT > maxTsensor ){
        maxT = maxTsensor;
      }
      if ( minT >= maxT ){
        minT = maxT - 1.0;
      }
      fillthermcamtable(currentFrame);
      document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
      document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
    }
    function ctof(tempc){
      return (tempc * ( 9 / 5 ) ) + 32;
    }
    function buildthermcamtable(){
      var thermcamTable = document.getElementById("thermcam");
      for(i=0;i<sizesensor[0];i++){
        var row = thermcamTable.insertRow(i);
        for(j=0;j<sizesensor[1];j++){
          var cell = row.insertCell(j);
          cell.id = "tccell"+((i*8)+j);
        }
      }
    }
    function fillthermcamtable(pixelarray){
      minTframe = maxTsensor;
      maxTframe = minTsensor;
      // Fill table
      // Temps in C and F in cells
      // BG color of cells use camColors
      // Update minTframe and maxTframe
      for(i=0;i<sizesensor[0];i++){
        for(j=0;j<sizesensor[1];j++){
          var idx = ((i*8)+j);
          var cell = document.getElementById("tccell"+idx);
          var camcolorvalue = Math.round( mapto( pixelarray[idx], minT , maxT, 0 ,433 ) );
          //cell.innerHTML = pixelarray[idx].toFixed(2) + "C " + ctof( pixelarray[idx] ).toFixed(2) + "F";
          cell.style.backgroundColor = "#" + camColors[camcolorvalue];
          cell.className = "camcolorvalue" + camcolorvalue;
          if ( pixelarray[idx] < minTframe ){
            minTframe = pixelarray[idx];
            minTframelocation = [j,i];
          }
          if ( pixelarray[idx] > maxTframe ){
            maxTframe = pixelarray[idx];
            maxTframelocation = [j,i];
          }
        }
      }
      //document.getElementById("minTframedata").innerHTML = minTframe.toFixed(2) + "C " + ctof( minTframe ).toFixed(2) + "F (" + minTframelocation[0] + "," + minTframelocation[1] + ")";
     // document.getElementById("maxTframedata").innerHTML = maxTframe.toFixed(2) + "C " + ctof( maxTframe ).toFixed(2) + "F (" + maxTframelocation[0] + "," + maxTframelocation[1] + ")";
    }
    function init() {
      // Build table
      buildthermcamtable();
      document.getElementById("minT").innerHTML = minT.toFixed(2) + "C";
      document.getElementById("maxT").innerHTML = maxT.toFixed(2) + "C";
      Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
      Socket.onmessage = function(event){
        if ( event.data[0] == '[' ){
          currentFrame = JSON.parse(event.data);
          fillthermcamtable(currentFrame);
        }
      }
    }
    function sendText(){
      Socket.send(document.getElementById("txBar").value);
      document.getElementById("txBar").value = "";
    }
    function getframe(){
      Socket.send("F");
    }
    function streamframes(){
      streamframestimer = setTimeout( streamframes , 200 );
      getframe();
    }
    function stopstreamframes(){
      clearTimeout( streamframestimer );
    }
  </script>
</head>
<body onload="init()">
  <table id="thermcam">
  
  </table>
  <hr/>
  <table id="thermcamcontrols">
    <tr>
      <td>Min Temp</td>
      <td id="minT"></td>
      <td><button type="button" onclick="adjusttemrange('min',-5);">-5C</button></td>
      <td><button type="button" onclick="adjusttemrange('min',-1);">-1C</button></td>
      <td><button type="button" onclick="adjusttemrange('min', 0);">lowest in current frame</button></td>
      <td><button type="button" onclick="adjusttemrange('min',+1);">+1C</button></td>
      <td><button type="button" onclick="adjusttemrange('min',+5);">+5C</button></td>
      <td id="minTframedata"></td>
    </tr>
    <tr>
      <td>Max Temp</td>
      <td id="maxT"></td>
      <td><button type="button" onclick="adjusttemrange('max',-5);">-5C</button></td>
      <td><button type="button" onclick="adjusttemrange('max',-1);">-1C</button></td>
      <td><button type="button" onclick="adjusttemrange('max', 0);">highest in current frame</button></td>
      <td><button type="button" onclick="adjusttemrange('max',+1);">+1C</button></td>
      <td><button type="button" onclick="adjusttemrange('max',+5);">+5C</button></td>
      <td id="maxTframedata"></td>
    </tr>
  </table>
  <hr/>
  <div>
    <button type="button" onclick="getframe();">Get Frame</button>
    <button type="button" onclick="streamframes();">Start Stream Frames</button>
    <button type="button" onclick="stopstreamframes();">Stop Stream Frames</button>
  </div>
</body>
</html>
)=====";

void setup()
{
 WiFi.softAP(ssid, password);
   IPAddress myIP = WiFi.softAPIP();
  Serial.begin(115200);

  Serial.println("");
  Serial.print("IP Address: ");
  Serial.println(myIP);

  server.on("/",[](){
    server.send_P(200, "text/html", webpage);  
  });
  server.begin();
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);


  Wire.begin(); 
 amg.begin();
}

void loop()
{
  webSocket.loop();
  server.handleClient();
  if(Serial.available() > 0){
    char c[] = {(char)Serial.read()};
    webSocket.broadcastTXT(c, sizeof(c));
  }
}

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length){
  if(type == WStype_TEXT){
    if(payload[0] == 'F'){ // i.e. "Frame"
    amg.readPixels(pixels);

    String thermalFrame = "[";

    for (int i = 1; i < AMG88xx_PIXEL_ARRAY_SIZE + 1; i++) { // Starts at 1 so that (i % 8) will be 0 at end of 8 pixels and newline will be added
      thermalFrame += pixels[i - 1];
      if ( i != AMG88xx_PIXEL_ARRAY_SIZE ){
        thermalFrame += ", ";
        if ( i % 8 == 0 ) thermalFrame += "\n";
      }
    }
    thermalFrame += "]";

    char tf[thermalFrame.length()+1];

    thermalFrame.toCharArray( tf, thermalFrame.length()+1 );

    webSocket.broadcastTXT(tf, sizeof(tf)-1);

    } 
  }
  
}
1 Like

Thank you. I have an AMG8833 and started working on a similar project, but simpler...just one-way only, using the ESP32 Async library and Server-Sent Events approach here: https://github.com/me-no-dev/ESPAsyncWebServer#async-event-source-plugin I will probably give your approach a try.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.