This script runs on an ESP32 WROOM-DA Module

/*
This device will monitor the MQTT messages published by all Raspberry running at home and will detect which of these raspberry have a CPU Temperature running above a defined threshold
A Pushover notification will be sent at the end of the set-up module to publish the name of the device as well as its IP Address.
When a Raspberry is detected as too hot, a message is sent to Telegram bot created for this purpose
*/
#include <SPI.h>
#include <WiFi.h>
//#include <WiFiManager.h>
#include <WiFiClientSecure.h> // part of the esp32 framework V1.0
#include <esp_sntp.h>
#include <PubSubClient.h> // for MQTT
#include <UniversalTelegramBot.h> // https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot V1.3.0
#include <string.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
const char* ssid = "Sotong_Purnama_ext";
const char* password = "15sotong15";
const char* MyHostName = "ESP32 - CPU Temp Monitoring";
const char* hostname; // a variable to store the Hostname of ESP32
const char* ntpServer1 = "pool.ntp.org";
const char* ntpServer2 = "time.nist.gov";
const long gmtOffset_sec = 28800; // For GMT+8
const int daylightOffset_sec = 0; // No daylight offset
// For Pushover
const char* title;
const char* message;
const char* pushoverUserKey = "u6ysovfgq1nhysszxzh91qnwadch2y"; // Set the user key generated in the Pushover account settings
const char* pushoverAPIToken = "amhb2rxrc2wa8gnpbpek99g2qrh4kx"; // Set the API token generated in the Pushover account settings
//Pushover API endpoint
const char* pushoverApiEndpoint = "https://api.pushover.net/1/messages.json";
const char* messagePrefix = ""; // Set a prefix for all messages
// // HTTPS root certificate for api.pushover.net: DigiCert Global Root CA, expires 2031.11.10
const char pushoverCertificateRoot[] = R"=EOF=(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)=EOF=";
WiFiClient espClient;
PubSubClient mqtt_client(espClient);
WiFiClientSecure clientTCP; // for TELEGRAM
// Create a WiFiClientSecure object
WiFiClientSecure ipClient;
bool wifiConnected = true;
// MQTT broker
const char* mqtt_server = "192.168.86.225";
const unsigned mqtt_port = 1883;
const char* mqtt_user = "homeassistant";
const char* mqtt_password = "raspberrypi";
// TELEGRAM
char TelegramBOTtoken[50] = "6426740052:AAE1WAIrfylu9694iEZlbfJRcDDE7nHMG9Y"; // token given by BotFather upon creation of the bot for cpu_temperature_monitoying
char Chat_ID[15] = "739396707"; // pops telegram ID
char Country[30] = "Asia/Singapore";
char chatId[15] = "";
float temp_threshold = 75.0;
// Set your static IP address
IPAddress local_IP(192, 168, 86, 30);
// Set your Gateway IP address
IPAddress gateway(192, 168, 86, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8); // optional
IPAddress secondaryDNS(8, 8, 4, 4); // optional
boolean mute = 0;
UniversalTelegramBot bot(TelegramBOTtoken, clientTCP); // setup the Telegram bot
bool flashState = LOW; //By Default it is off
int botRequestDelay = 1000; // mean time between scan messages
long lastTimeBotRan; // last time messages' scan has been done
void handleNewMessages(int numNewMessages);
const int DHCP_PACKET_CLIENT_ADDR_LEN_OFFSET = 2;
const int DHCP_PACKET_CLIENT_ADDR_OFFSET = 28;
enum State
{
READY,
EVALUATING,
TOO_HOT
};
volatile State state = READY;
String newMAC;
String newIP;
String newName;
String device = "";
const char *hexDigits = "0123456789ABCDEF";
String DetectorMessage;
float temperature;
void sendPushover(const char* title, const char* message){
const char* hostname;
String IPAddress;
//Make HTTP POST request to send notification
if (WiFi.status() == WL_CONNECTED) {
WiFi.setHostname(MyHostName);
hostname = WiFi.getHostname();
IPAddress = WiFi.localIP().toString().c_str();
// Create a JSON object with notification details
// Check the API parameters: https://pushover.net/api
StaticJsonDocument<512> notification;
notification["token"] = pushoverAPIToken;
notification["user"] = pushoverUserKey;
notification["message"] = IPAddress;
notification["title"] = hostname;
notification["url"] = "";
notification["url_title"] = "";
notification["html"] = "";
notification["priority"] = "";
notification["sound"] = "cosmic";
notification["timestamp"] = "";
// Serialize the JSON object to a string
String jsonStringNotification;
serializeJson(notification, jsonStringNotification);
// Set the certificate
ipClient.setCACert(pushoverCertificateRoot);
// Create an HTTPClient object
HTTPClient https;
// Specify the target URL
https.begin(ipClient, pushoverApiEndpoint);
// Add headers
https.addHeader("Content-Type", "application/json");
// Send the POST request with the JSON data
int httpResponseCode = https.POST(jsonStringNotification);
// Check the response
if (httpResponseCode > 0) {
Serial.printf("HTTPS response code: %d\n", httpResponseCode);
String response = https.getString();
Serial.println("Response:");
Serial.println(response);
} else {
Serial.printf("HTTPS response code: %d\n", httpResponseCode);
}
// Close the connection
https.end();
}
}
void printLocalTime()
{
struct tm timeinfo;
// if the function getLocalTime fails
if(!getLocalTime(&timeinfo)){
// print an error message
Serial.println("No time available (yet)");
// and return
return;
}
//else print the Date and time as described below
// Format "DayOfWeek, Month Date Year Hour:Minutes:Seconds"
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
// Callback function (get's called when time adjusts via NTP)
void timeavailable(struct timeval *t)
{
Serial.println("\nGot time adjustment from NTP!");
printLocalTime();
Serial.println();
}
// function to reconnect to the MQTT broker
void reconnect() {
// Loop until we're reconnected
while (!mqtt_client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (mqtt_client.connect("ESP32client",mqtt_user,mqtt_password)) {
Serial.println("Connected to MQTT server");
// Subscribe
mqtt_client.subscribe("#");
} else {
Serial.print("failed, rc=");
Serial.print(mqtt_client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void extract_from_topic(String topic){
device = "Device Name";
// Extracting Device Name
// topic is in the form of "cpu_temp/device_name"
// so we are interested in all what is after character position 9
device = topic.substring(9,topic.length());
}
void callback(char* topic, byte* message, unsigned int length) {
unsigned int MessageLength;
String messageTemp;
temperature = 0.0;
Serial.print("\nMessage arrived on topic: ");
Serial.println(topic);
// extract the name of the device from the topic
extract_from_topic(topic);
// and print it
Serial.print("Device Name: ");
Serial.println(device);
Serial.print("Device Temperature: ");
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
MessageLength = messageTemp.length();
Serial.println("");
if (messageTemp.toFloat() > temp_threshold){
temperature = messageTemp.toFloat();
// Serial.println("Device is too hot!");
state = TOO_HOT;
}
// Feel free to add more if statements to check on the content of messages
}
//#########################//
// SET-UP //
//#########################//
void setup() {
ipClient.setCACert(pushoverCertificateRoot);
delay(1000);
Serial.begin(115200);
Serial.println();
// Connect to the WiFi Network
// Serial.print("Connecting to ");
// Serial.println(ssid);
// Serial.print("With password ");
// Serial.println(password);
// Configures static IP address
WiFi.setHostname(MyHostName);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Hostname is: ");
if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
Serial.println("STA Failed to configure");
}
else
{
Serial.println("Wifi configuration successful");
}
delay(1000);
Serial.println(WiFi.getHostname());
clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT);
delay(2000);
Serial.println("Attempting to connect to Wifi network...");
// Wait until connection is established
while(WiFi.status() != WL_CONNECTED){
// Serial.print(WiFi.status());
Serial.print(".");
delay(500);
if (WiFi.status() == WL_CONNECT_FAILED){
Serial.println("\nAttempt to connect has failed! Rebooting now...");
ESP.restart();
}
}
// Print ESP32's IP & HostName
Serial.println("\nConnected to the WiFi network");
Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP());
Serial.print("ESP32 HostName: ");
Serial.println(WiFi.getHostname());
// set notification call-back function
sntp_set_time_sync_notification_cb( timeavailable );
/**
* NTP server address could be acquired via DHCP,
*
* NOTE: This call should be made BEFORE esp32 acquires IP address via DHCP,
* otherwise SNTP option 42 would be rejected by default.
* NOTE: configTime() function call if made AFTER DHCP-client run
* will OVERRIDE acquired NTP server address
*/
sntp_servermode_dhcp(1); // (optional)
/**
* This will set configured ntp servers and constant TimeZone/daylightOffset
* should be OK if your time zone does not need to adjust daylightOffset twice a year,
* in such a case time adjustment won't be handled automatically.
*/
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1,ntpServer2);
/**
* A more convenient approach to handle TimeZones with daylightOffset
* would be to specify a environment variable with TimeZone definition including daylight adjustmnet rules.
* A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
*/
//configTzTime(time_zone, ntpServer1, ntpServer2);
Serial.println();
// Serial.println("##############################");
// Serial.println("# Device CPU Temp Monitoring #");
// Serial.println("##############################");
// Print out Ready message as well as IP address given by DHCP
Serial.print("Host Ready: ");
Serial.println(WiFi.getHostname());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Connecting to the MQTT Broker");
// sets the MQTT server
mqtt_client.setServer(mqtt_server,mqtt_port);
mqtt_client.setCallback(callback);
// attempting to connect to the MQTT server
while (!mqtt_client.connected()) {
Serial.print("Connecting to MQTT...");
if (mqtt_client.connect("mqtt_client", mqtt_user, mqtt_password )) {
Serial.println("connected");
} else {
Serial.print("failed with state ");
Serial.println(mqtt_client.state());
delay(5000);
}
}
// connected to the MQTT server, can subscribe to topics
// subscribe to cpu_temp topic for all computers
mqtt_client.subscribe("cpu_temp/#");
// Serial.println("Hello World!");
bot.sendMessage(Chat_ID, "ESP32 - CPU Temp Monitoring\nStarting now...");
// calls the sendPushover functions
sendPushover(title, message);
}
//#########################//
// MAIN LOOP //
//#########################//
void loop() {
char telegram_message [100];
// check that the MQTT connection is established
if (!mqtt_client.connected()) {
Serial.println("MQTT server disconnected...");
// if it is not, then reconnect
reconnect();
}
mqtt_client.loop();
// check if a device has too hot a temperature (state = TOO_HOT)
delay(20);
if(state == TOO_HOT)
{
if (mute==0){
// Send a message on Telegram
// Serial.print("Sending a message on Telegram: ");
sprintf(telegram_message, "%s' temperature is %.1f deg. Have a look at it!", device, temperature);
// Serial.println(buffer);
// Serial.println(telegram_message);
bot.sendMessage(Chat_ID, telegram_message);
}
state = READY;
}
}