Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
#include <esp_now.h>
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Arduino_JSON.h>
// Replace with your network credentials (STATION)
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
int id;
float temp;
float hum;
unsigned int readingId;
} struct_message;
struct_message incomingReadings;
JSONVar board;
AsyncWebServer server(80);
AsyncEventSource events("/events");
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {
// Copies the sender mac address to a string
char macStr[18];
Serial.print("Packet received from: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
board["id"] =;
board["temperature"] = incomingReadings.temp;
board["humidity"] = incomingReadings.hum;
board["readingId"] = String(incomingReadings.readingId);
String jsonString = JSON.stringify(board);
events.send(jsonString.c_str(), "new_readings", millis());
Serial.printf("Board ID %u: %u bytes\n",, len);
Serial.printf("t value: %4.2f \n", incomingReadings.temp);
Serial.printf("h value: %4.2f \n", incomingReadings.hum);
Serial.printf("readingID value: %d \n", incomingReadings.readingId);
const char index_html[] PROGMEM = R"rawliteral(
<title>ESP-NOW DASHBOARD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src=""></script>
<link rel="stylesheet" href="" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="icon" href="data:,">
html {font-family: Arial; display: inline-block; text-align: center;}
p { font-size: 1.2rem;}
body { margin: 0;}
.topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }
.content { padding: 20px; }
.card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
.cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.reading { font-size: 2.8rem; }
.packet { color: #bebebe; }
.card.temperature { color: #fd7e14; }
.card.humidity { color: #1b78e2; }
<div class="topnav">
<div class="content">
<div class="cards">
<div class="card temperature">
<h4><i class="fas fa-thermometer-half"></i> BOARD #1 - TEMPERATURE</h4><p><span class="reading"><span id="t1"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt1"></span></p>
<div class="card humidity">
<h4><i class="fas fa-tint"></i> BOARD #1 - HUMIDITY</h4><p><span class="reading"><span id="h1"></span> &percnt;</span></p><p class="packet">Reading ID: <span id="rh1"></span></p>
<div class="card temperature">
<h4><i class="fas fa-thermometer-half"></i> BOARD #2 - TEMPERATURE</h4><p><span class="reading"><span id="t2"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt2"></span></p>
<div class="card humidity">
<h4><i class="fas fa-tint"></i> BOARD #2 - HUMIDITY</h4><p><span class="reading"><span id="h2"></span> &percnt;</span></p><p class="packet">Reading ID: <span id="rh2"></span></p>
<div class="content">
<div class="cards">
<div class="card chart">
<div id="chart-temperature"></div>
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'chart-temperature' },
title: { text: 'BME280 Temperature' },
series: [{
showInLegend: false,
data: []
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
series: { color: '#059e8a' }
xAxis: { type: 'datetime',
dateTimeLabelFormats: { second: '%H:%M:%S' }
yAxis: {
title: { text: 'Temperature (Celsius)' }
//title: { text: 'Temperature (Fahrenheit)' }
credits: { enabled: false }
if (!!window.EventSource) {
var source = new EventSource('/events');
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if ( != EventSource.OPEN) {
console.log("Events Disconnected");
}, false);
source.addEventListener('message', function(e) {
}, false);
source.addEventListener('new_readings', function(e) {
var obj = JSON.parse(;
document.getElementById("t" = obj.temperature.toFixed(2);
document.getElementById("h" = obj.humidity.toFixed(2);
document.getElementById("rt" = obj.readingId;
document.getElementById("rh" = obj.readingId;
var x = (new Date()).getTime(),
y = Number(obj.temperature.toFixed(2));
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);
}, false);
void setup() {
// Initialize Serial Monitor
// Set the device as a Station and Soft Access Point simultaneously
// Set device as a Wi-Fi Station
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("Setting as a Wi-Fi Station..");
Serial.print("Station IP Address: ");
Serial.print("Wi-Fi Channel: ");
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
// Once ESPNow is successfully Init, we will register for recv CB to
// get recv packer info
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html);
events.onConnect([](AsyncEventSourceClient *client){
Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
// send event with message "hello!", id current millis
// and set reconnect delay to 1 second
client->send("hello!", NULL, millis(), 10000);
void loop() {
static unsigned long lastEventTime = millis();
static const unsigned long EVENT_INTERVAL_MS = 5000;
if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
lastEventTime = millis();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment