This device will detect if any of the Raspberrys running on my Home Network do not answer to a ping call.
This script runs on a ESP32-WROOM-DA Module

/*
This device is meant to ping the devices listed below, at regular intervals.
The ping will return True if 3 subsequent pings have been successful, False otherwise
An MQTT message will be sent after each device has been pinged to report the status to Home Assistant
Each False result will be sent to me using Telegram
*/
#include <SPI.h>
#include <WiFi.h>
//#include <WiFiManager.h>
#include <WiFiClientSecure.h> // part of the esp32 framework V1.0
#include <ESP32Ping.h>
#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 - Device Presence 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;
// List of devices to ping
const byte numChars = 15;
const char devicesIPArray[][numChars] = {"192.168.86.40", "192.168.86.100", "192.168.86.102", "192.168.86.120", "192.168.86.160", "192.168.86.162", "192.168.86.165", "192.168.86.200", "192.168.86.221", "192.168.86.225"};
const char devicesNameArray[][numChars] = {"PiMinion", "PiNextCloud", "PiJellyfin", "PiPlex", "PiDatabase","PiWordpress", "PiMysterium", "PiVPN", "Beelink", "PiHA"};
int nb_devices = 10;
int nb_pings = 10;
// 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] = "5851226857:AAGtHLsHJk2dRETbjKIixRkP5HILD_XCq1o";
char Chat_ID[15] = "739396707"; // pops telegram ID
char Country[30] = "Asia/Singapore";
char chatId[15] = "";
// Set your Static IP address
IPAddress local_IP(192, 168, 86, 50);
// 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
UniversalTelegramBot bot(TelegramBOTtoken, clientTCP); // setup the Telegram bot
enum State
{
READY,
PINGING,
NOT_PINGED
};
volatile State state = READY;
String newMAC;
String newIP;
String newName;
String device = "";
String name = "";
const char *hexDigits = "0123456789ABCDEF";
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();
}
void callback(char* topic, byte* message, unsigned int length) {
unsigned int MessageLength;
String messageTemp;
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("");
// Feel free to add more if statements to check on the content of messages
}
//#########################//
// SET-UP //
//#########################//
void setup() {
// for Pushover
ipClient.setCACert(pushoverCertificateRoot);
state=READY;
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
if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
Serial.println("STA Failed to configure");
}
else
{
Serial.println("Wifi configuration successful");
}
delay(1000);
WiFi.setHostname(MyHostName);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Hostname is: ");
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();
}
}
// 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 Presence Monitoring #");
Serial.println("##############################");
// Print out Ready message as well as IP address given by DHCP
Serial.print("Host Ready: ");
Serial.println(WiFi.getHostname());
bot.sendMessage(Chat_ID, "ESP32 - Device Presence Monitoring\nStarting now...");
bool success = Ping.ping("www.google.com", 3);
if(!success){
Serial.println("Ping failed");
return;
}
Serial.println("Pinging Google is successful.");
delay(1000);
bot.sendMessage(Chat_ID, "Pinging Google is successful...");
Serial.print("Number of devices: ");
Serial.println(nb_devices);
// calls the sendPushover functions
sendPushover(title, message);
}
//#########################//
// MAIN LOOP //
//#########################//
void loop() {
bool res = 1; // will be True (1) if Ping.ping is successfull, 0 if it
char telegram_message [200];
printLocalTime();
Serial.println("Starting the pinging process on all devices");
for (int i = 0; i < nb_devices ; i++){
res = 0;
Serial.print("Pinging: ");
Serial.println(devicesNameArray[i]);
res = Ping.ping(devicesIPArray[i],nb_pings);
if (res == 0){
state = NOT_PINGED;
device = devicesNameArray[i];
}
Serial.print("");
if(state == NOT_PINGED)
{
// Send a message on Telegram
sprintf(telegram_message, "%s does not answer to several pings. Have a look at it!", device);
Serial.println(telegram_message);
bot.sendMessage(Chat_ID, telegram_message);
sprintf(telegram_message ,"");
state = READY;
delay(5000); // 5 seconds until next device
}
printLocalTime();
delay(300000); // 5 minutes before next serie of pings
state=READY;
}
}