#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// --- GSM Configuration ---
#define TINY_GSM_MODEM_SIM800
#include <TinyGsmClient.h>
#define SerialAT Serial2
// Include the secrets file
#include "secrets.h"
// --- Global State Variables ---
bool wifiConnected = false;
bool gsmConnected = false;
// --- LED Pin ---
const int ledPin = 26;
// Create instances for the clients
WiFiClientSecure wifiSecureClient;
TinyGsm modem(SerialAT);
TinyGsmClient gsmClient(modem);
PubSubClient client;
// --- Function Prototypes ---
void reconnect();
void connectWiFi();
void connectGSM();
void publishData();
void callback(char* topic, byte* payload, unsigned int length);
// Global variables for our fake inverter data
float voltage = 230.5;
float current = 5.1;
float power = 1175.5;
void setup() {
Serial.begin(115200);
delay(10);
Serial.println("\nStarting up the ESP32 inverter data sender...");
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
SerialAT.begin(115200, SERIAL_8N1, 16, 17);
delay(100);
connectWiFi();
if (!wifiConnected) {
connectGSM();
}
if (wifiConnected) {
wifiSecureClient.setCACert(root_ca_cert);
wifiSecureClient.setCertificate(client_cert);
wifiSecureClient.setPrivateKey(client_private_key);
client.setClient(wifiSecureClient);
client.setServer(aws_iot_endpoint, aws_iot_port);
} else if (gsmConnected) {
client.setClient(gsmClient);
client.setServer("test.mosquitto.org", 1883);
} else {
Serial.println("FATAL ERROR: Could not connect to any network.");
while(true);
}
client.setCallback(callback);
}
void loop() {
if (!wifiConnected && !gsmConnected) {
Serial.println("Attempting to re-establish network connection...");
connectWiFi();
if (!wifiConnected) {
connectGSM();
}
if (wifiConnected) {
wifiSecureClient.setCACert(root_ca_cert);
wifiSecureClient.setCertificate(client_cert);
wifiSecureClient.setPrivateKey(client_private_key);
client.setClient(wifiSecureClient);
client.setServer(aws_iot_endpoint, aws_iot_port);
} else if (gsmConnected) {
client.setClient(gsmClient);
client.setServer("test.mosquitto.org", 1883);
}
}
if (client.connected()) {
client.loop();
publishData();
} else {
reconnect();
}
}
void connectWiFi() {
int attempts = 0;
Serial.print("Attempting to connect to Wi-Fi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED && attempts < wifi_retry_attempts) {
delay(1000);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nConnected to Wi-Fi!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
wifiConnected = true;
gsmConnected = false;
} else {
Serial.println("\nWi-Fi connection failed.");
wifiConnected = false;
}
}
void connectGSM() {
Serial.println("Wi-Fi failed. Attempting to connect via GSM...");
Serial.print("Waiting for modem...");
modem.waitForNetwork();
Serial.println(" done.");
Serial.print("Connecting to GPRS...");
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
Serial.println(" failed!");
gsmConnected = false;
return;
}
Serial.println(" success.");
Serial.print("GPRS connected. IP Address: ");
Serial.println(modem.localIP());
gsmConnected = true;
wifiConnected = false;
}
void reconnect() {
String clientId = wifiConnected ? client_id : "ESP32-Inverter-GSM";
while (!client.connected()) {
Serial.print("Attempting MQTT connection on active network...");
if (client.connect(clientId.c_str())) {
Serial.println("connected!");
client.subscribe(inverter_control_topic);
Serial.print("Subscribed to topic: ");
Serial.println(inverter_control_topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" trying again in 5 seconds");
delay(5000);
}
}
}
void publishData() {
static unsigned long lastMsg = 0;
unsigned long now = millis();
if (now - lastMsg > 1000) {
lastMsg = now;
voltage += (random(0, 10) - 5) / 100.0;
current += (random(0, 10) - 5) / 100.0;
power = voltage * current;
char msgBuffer[100];
sprintf(msgBuffer, "{\"voltage\": %.2f, \"current\": %.2f, \"power\": %.2f}", voltage, current, power);
client.publish(inverter_data_topic, msgBuffer);
Serial.print("Published message on ");
Serial.print(wifiConnected ? "Wi-Fi" : "GSM");
Serial.print(": ");
Serial.println(msgBuffer);
}
}
// This is the callback function that handles JSON
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.println(topic);
// Deserialize the JSON message
StaticJsonDocument<200> doc;
deserializeJson(doc, payload, length);
// Check if the "command" field exists
if (doc.containsKey("command")) {
String command = doc["command"].as<String>();
Serial.print("Command received: ");
Serial.println(command);
if (command == "ON") {
digitalWrite(ledPin, HIGH);
Serial.println("Turned LED ON");
} else if (command == "OFF") {
digitalWrite(ledPin, LOW);
Serial.println("Turned LED OFF");
}
} else {
Serial.println("JSON message does not contain a 'command' key.");
}
}