Hey guys,
I am designing my own smartwatch, it has a PPG sensor and an accelerometer that both have a sample rate of 128Hz.
I want to plot in real time every point on a web server with no data loss. I am using an ESP32 s3.
I am already capable of ploting data from my accelerometer, but there is a non negligeable delay between when the data has been sent by the controler and when it has been ploted. (About 2 to 3 seconds)
First question: How can I improve the delay and plot data as fast as I'm getting it ?
Also, in order to plot data 128 times a second, at the moment I force an intervalle between two point that corresponds to 128Hz. It does not feel like the correct way, I should to send data and plot it whenever the SENSOR is giving me data, not whenever the software wants it.
Second question: what is the correct way to get data in real time using wifi? Is there some sort of ".notify()" like for bluetooth?
here are my codes: (Don't give too much attention on the variables named temperature, pressure etc. The code mostly come from a tutorial unrelated to my accelerometer, that's why)
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include "accelerometer.h"
uint16_t ax, ay, az;
uint16_t fall, move = 1; //Interrupt active low
const char *ssid = "***";
const char *password = "***!";
AsyncWebServer server(80);
//don't worry, this will be transformed to only one function. And yes these are //unsigned int I know.
String acc_X(uint16_t ax, uint16_t ay, uint16_t az) {
readAccelData(ax, ay, az);
return String(ax);
}
String acc_Y(uint16_t ax, uint16_t ay, uint16_t az) {
readAccelData(ax, ay, az);
return String(ay);
}
String acc_Z(uint16_t ax, uint16_t ay, uint16_t az) {
readAccelData(ax, ay, az);
return String(az);
}
void setup() {
Serial.begin(115200);
accel_innit();
if (!LittleFS.begin()) {
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP()); //
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(LittleFS, "/index.html");
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/plain", acc_X(ax, ay, az).c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/plain", acc_Y(ax, ay, az).c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send_P(200, "text/plain", acc_Z(ax, ay, az).c_str());
});
// Start server
server.begin();
}
void loop() {
}
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/highcharts.js"></script>
<style>
body {
min-width: 310px;
max-width: 800px;
height: 400px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
</head>
<body>
<h2>Plot</h2>
<div id="Chart_X_axis" class="container"></div>
<div id="Chart_Y_axis" class="container"></div>
<div id="Chart_Z_axis" class="container"></div>
</body>
<script>
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'Chart_X_axis' },
title: { text: 'Accelerometer data' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: false }
},
series: { color: '#059e8a' }
},
xAxis: { type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Acceleration X axis (m/s^2)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
if(chartT.series[0].data.length > 40) {
chartT.series[0].addPoint([x, y], true, true, true);
} else {
chartT.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 300 ) ;
var chartH = new Highcharts.Chart({
chart:{ renderTo:'Chart_Y_axis' },
title: { text: 'Accelerometer Y axis' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: false }
}
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Acceleration Y axis (m/s^2)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
if(chartH.series[0].data.length > 40) {
chartH.series[0].addPoint([x, y], true, true, true);
} else {
chartH.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 300 ) ;
var chartP = new Highcharts.Chart({
chart:{ renderTo:'Chart_Z_axis' },
title: { text: 'Acceleration Z axis (m/s^2)' },
series: [{
showInLegend: false,
data: []
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: false }
},
series: { color: '#18009c' }
},
xAxis: {
type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
},
yAxis: {
title: { text: 'Acceleration (m/^2)' }
},
credits: { enabled: false }
});
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = (new Date()).getTime(),
y = parseFloat(this.responseText);
if(chartP.series[0].data.length > 40) {
chartP.series[0].addPoint([x, y], true, true, true);
} else {
chartP.series[0].addPoint([x, y], true, false, true);
}
}
};
xhttp.open("GET", "/pressure", true);
xhttp.send();
}, 300 ) ;
</script>
</html>