Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/***************************************************
mqtt_airlift_subscribe_time_keepalive

Example demonstrating MQTT subscription and manual
KeepAlive handling for AirLift (ESP32 / NINA-FW)
devices using the Adafruit_MQTT_Library.

This example:
* Connects an AirLift device to WiFi
* Subscribes to io.adafruit.com/time/ISO-8601
* Manually manages MQTT KeepAlive intervals
* Sends periodic MQTT PINGs to maintain the
MQTT session (workaround for NINA-FW behavior)

Written by Bruce Conrad.
MIT license, all text above must be included in
any redistribution.
****************************************************/

#include <SPI.h>
#include <WiFiNINA.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

/************************* WiFi Setup *********************************/
// Update for your WiFi network.
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASS "YOUR_WIFI_PASSWORD"

/************************* Adafruit IO Setup ***************************/
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883 // use 8883 for MQTTS
#define AIO_USERNAME "YOUR_ADAFRUIT_IO_USERNAME"
#define AIO_KEY "YOUR_ADAFRUIT_IO_KEY"

/************************* AirLift Pin Setup ***************************/
// These are the pins you provided and known-good.
#define SPIWIFI SPI
#define SPIWIFI_SS 13
#define SPIWIFI_IRQ 11
#define SPIWIFI_RESET 12
#define ESP32_GPIO0 -1

/*************************** Timing / Params ***************************/
// MQTT KeepAlive interval (seconds). The client must send at least one
// packet (e.g., PINGREQ) within this interval or the MQTT server will
// disconnect the session.
#define AIRLIFT_KEEPALIVE 30

// Safety margin (seconds) to subtract before sending a manual PING.
// AirLift/NINA-FW firmware does not reliably handle automatic MQTT
// KeepAlive packets, and real-world testing shows a 10 second margin
// prevents premature disconnects (“No socket available”).
#define KEEPALIVE_SAFETY_MARGIN 10

#define MAX_MQTT_RETRIES 5
#define SUBSCRIBE_WAIT_MS 1500

// Time (milliseconds) between manual MQTT PING operations.
#define PING_PERIOD_MS \
((AIRLIFT_KEEPALIVE - KEEPALIVE_SAFETY_MARGIN) * 1000)

/*************************** MQTT Objects ******************************/
WiFiClient client;

Adafruit_MQTT_Client mqtt(
&client,
AIO_SERVER,
AIO_SERVERPORT,
AIO_USERNAME,
AIO_KEY
);

Adafruit_MQTT_Subscribe time_subscription =
Adafruit_MQTT_Subscribe(&mqtt, "time/ISO-8601");

/*************************** State Vars *******************************/
unsigned long ping_clk = 0;
long ping_cnt = 0;

/*************************** MQTT Connect ******************************/
void MQTT_connect() {

unsigned long start = millis();
long attempts = 0;

while (attempts < MAX_MQTT_RETRIES) {
attempts++;

Serial.print("MQTT Connect Attempt #");
Serial.print(attempts);
Serial.print(" ... ");

int8_t ret = mqtt.connect();

if (ret == 0) {
Serial.print("Connected in ");
Serial.print(millis() - start);
Serial.println(" ms");
ping_clk = millis();
return;
}

Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying in 5 seconds...");
mqtt.disconnect();
delay(5000);
}

Serial.println("ERROR: Maximum MQTT connect attempts exceeded.");
while (1) delay(10);
}

/*************************** MQTT PING Logic ***************************/
void MQTT_ping() {
if ((millis() - ping_clk) < PING_PERIOD_MS) return;

ping_cnt++;
unsigned long start = millis();

Serial.print("PING #");
Serial.print(ping_cnt);
Serial.print(" ... ");

for (int i = 0; i < MAX_MQTT_RETRIES; i++) {

if (mqtt.ping()) {
Serial.print("OK (");
Serial.print(millis() - start);
Serial.println(" ms)");
ping_clk = millis();
return;
}

Serial.print("fail ");
delay(1000);
}

Serial.println("\nERROR: No MQTT PING response. Halting.");
while (1) delay(10);
}

/*************************** WiFi Init *********************************/
void initWiFi() {

// IMPORTANT: passes the *SPI object* (SPIWIFI), not a pin
WiFi.setPins(SPIWIFI_SS, SPIWIFI_IRQ, SPIWIFI_RESET, ESP32_GPIO0, &SPIWIFI);

Serial.println("Starting AirLift WiFi...");

if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("ERROR: Communication with AirLift failed.");
while (1) delay(10);
}

Serial.print("NINA-FW Version: ");
Serial.println(WiFi.firmwareVersion());

int status = WL_IDLE_STATUS;

while (status != WL_CONNECTED) {
Serial.print("Connecting to SSID: ");
Serial.println(WIFI_SSID);

status = WiFi.begin(WIFI_SSID, WIFI_PASS);

while (WiFi.localIP()[0] == 0) {
delay(50);
}
}

Serial.println("WiFi connected.");
printCurrentNet();
printWiFiData();
}

/*************************** Helpers ***********************************/
void printCurrentNet() {
Serial.print("SSID: ");
Serial.print(WiFi.SSID());

byte bssid[6];
WiFi.BSSID(bssid);

Serial.print(" BSSID: ");
printMacAddress(bssid);

Serial.print(" RSSI: ");
Serial.print(WiFi.RSSI());

Serial.print(" Encryption: ");
Serial.println(WiFi.encryptionType(), HEX);
}

void printWiFiData() {
Serial.print("IP: ");
Serial.print(WiFi.localIP());

Serial.print(" Gateway: ");
Serial.print(WiFi.gatewayIP());

Serial.print(" Subnet: ");
Serial.print(WiFi.subnetMask());

byte mac[6];
WiFi.macAddress(mac);

Serial.print(" MAC: ");
printMacAddress(mac);
}

void printMacAddress(byte mac[]) {
for (int i = 5; i >= 0; i--) {
if (mac[i] < 16) Serial.print("0");
Serial.print(mac[i], HEX);
if (i > 0) Serial.print(":");
}
Serial.print(" ");
}

/*************************** Setup *************************************/
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);

Serial.println("MQTT AirLift Subscribe + KeepAlive Example");

initWiFi();

mqtt.setKeepAliveInterval(AIRLIFT_KEEPALIVE);
mqtt.subscribe(&time_subscription);

MQTT_connect();
}

/*************************** Main Loop *********************************/
void loop() {

MQTT_ping();

Adafruit_MQTT_Subscribe *subscription =
mqtt.readSubscription(SUBSCRIBE_WAIT_MS);

if (subscription == &time_subscription) {
Serial.print("TIME FEED: ");
Serial.println((char *)time_subscription.lastread);
}
}
4 changes: 2 additions & 2 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name=Adafruit MQTT Library
version=2.6.1
version=2.6.2
author=Adafruit
maintainer=Adafruit <[email protected]>
sentence=MQTT library that supports the FONA, ESP8266, ESP32, Yun, and generic Arduino Client hardware.
paragraph=Simple MQTT library that supports the bare minimum to publish and subscribe to topics.
category=Communication
url=https://github.com/adafruit/Adafruit_MQTT_Library
architectures=*
depends=Adafruit SleepyDog Library, Adafruit FONA Library, WiFi101
depends=Adafruit SleepyDog Library, Adafruit FONA Library, WiFi101, WiFiNINA_-_Adafruit_Fork