Musab Gulfam
Musab Gulfam

Reputation: 172

Last will testimony (LWT) not working on AWS IoT Core

WiFiClientSecure net;
PubSubClient client(net);

char lwtMessage[256];

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  
  connectWiFi();

  // Prepare JSON for Last Will Testament (LWT)
  StaticJsonDocument<512> doc;
  doc["state"]["reported"]["deviceStatus"] = "OFFLINE";
  serializeJson(doc, lwtMessage, sizeof(lwtMessage));

  connectAWSIoT();
}

void connectAWSIoT() {
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);

  client.setServer(AWS_IOT_ENDPOINT, AWS_IOT_PORT);
  client.setCallback(messageHandler);

  Serial.print("Connecting to AWS IoT...");

  while (!client.connect(CLIENT_ID, "", "", SHADOW_UPDATE_TOPIC, 1, true, lwtMessage)) {
    Serial.print(client.state());
    delay(1000);
  }
  Serial.println("Connected to AWS!");

  client.subscribe(AWS_IOT_TOPIC_SUB);
  publishDeviceStatus("ONLINE");
}

I am not able to connect to AWS when setting the client function with Last Will Testimony. Basically whenever the ESP-32 goes offline, the shadow must be updated to reflect that the device is offline. But its not able to connect to AWS in the first place, and client.state() outputs -4, which is connection timeout I guess.

Complete code

#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include "secrets.h"  // Include credentials
#include "DHT.h"

// Relay Pin
#define RELAY_PIN 5  // GPIO5
#define DHTPIN 4 //GPIO4
#define DHTTYPE DHT11  // DHT 11 

DHT dht = DHT(DHTPIN, DHTTYPE);

float h;
float t;

unsigned long turnOffTime = 0; // Store turn-off time

unsigned long lastOnlineUpdate = 0;

// Create JSON buffer for Last Will Testament
char lwtMessage[256];

WiFiClientSecure net;
PubSubClient client(net);

// Connect to WiFi
void connectWiFi() {
  Serial.print("Connecting to WiFi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("Connected!");
}

// Connect to AWS IoT
void connectAWSIoT() {
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);

  client.setServer(AWS_IOT_ENDPOINT, AWS_IOT_PORT);
  client.setCallback(messageHandler);

  Serial.print("Connecting to AWS IoT...");

  while (!client.connect(CLIENT_ID, "", "", SHADOW_UPDATE_TOPIC, 1, true, lwtMessage)) {
    Serial.print(client.state());
    delay(1000);
  }
  Serial.println("Connected to AWS!");

  client.subscribe(AWS_IOT_TOPIC_SUB);
  publishDeviceStatus("ONLINE");
}


void publishDeviceStatus(String status) {
  StaticJsonDocument<256> doc;
  doc["state"]["reported"]["status"] = status;

  char jsonBuffer[256];
  serializeJson(doc, jsonBuffer);

  client.publish(SHADOW_UPDATE_TOPIC, jsonBuffer);
}

// Message handler to turn relay ON/OFF
void messageHandler(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message received");
  String msg = "";
  for (int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }

  Serial.print("Received: ");
  Serial.println(msg);

  int duration = msg.toInt();  // Convert MQTT message to integer

  if (duration > 0) {
    Serial.println("Turning ON the motor for " + String(duration) + " minutes.");
    digitalWrite(RELAY_PIN, HIGH); // Turn ON motor
    turnOffTime = millis() + (duration * 60000); // Set turn-off time
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  
  connectWiFi();

  // Prepare JSON for Last Will Testament (LWT)
  StaticJsonDocument<512> doc;
  doc["state"]["reported"]["deviceStatus"] = "OFFLINE";
  serializeJson(doc, lwtMessage, sizeof(lwtMessage));

  connectAWSIoT();
}

void sendOnlineStatus() {
    StaticJsonDocument<200> doc;
    doc["state"]["reported"]["deviceStatus"] = "ONLINE";

    char buffer[256];
    serializeJson(doc, buffer);
    client.publish(SHADOW_UPDATE_TOPIC, buffer);
}

void loop() {
  if (!client.connected()) {
    connectAWSIoT();
  }

  h = dht.readHumidity();
  t = dht.readTemperature();
  
  client.loop();  // Keep MQTT connection alive

  // ✅ Send "ONLINE" status every 30 seconds, NOT on every loop iteration
  if (millis() - lastOnlineUpdate > 30000) {
    sendOnlineStatus();
    lastOnlineUpdate = millis();
  }
    
  // Check if it's time to turn OFF the motor
  if (turnOffTime > 0 && millis() >= turnOffTime) {
    Serial.println("Turning OFF the motor.");
    digitalWrite(RELAY_PIN, LOW); // Turn OFF motor
    turnOffTime = 0;  // Reset timer
  }
}

Upvotes: 0

Views: 24

Answers (0)

Related Questions