I use the RPi servers name instead of an IP address.
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include "time.h"
#include <ESP32Time.h>
//
ESP32Time rtc;
//
hw_timer_t * timer = NULL;
EventGroupHandle_t eg;
#define evtDoDisplay ( 1 << 1 )
#define evtDoTheMQTT_Watch ( 1 << 2 )
#define evtParseMQTT ( 1 << 5 )
#define evtDoTheSunLampThing ( 1 << 10 )
//
int SunLampManual = 0; // manual on or off
int SunLampAuto = 1;// auto mode
int mqttOK = 0;
////
WiFiClient wifiClient;
PubSubClient MQTTclient( mqtt_server, mqtt_port, wifiClient );
////
String str_eTopic;
char strPayload [300] = { '\0' };
////
SemaphoreHandle_t sema_MQTT_Parser; //if parsing is in progress hold up callback a moment to let parsing finish before sending a new things to parse
SemaphoreHandle_t sema_MQTT_KeepAlive;
SemaphoreHandle_t sema_mqttOK;
////
volatile bool TimeSet = false;
volatile int iDoTheThing = 0;
////
void IRAM_ATTR onTimer()
{
BaseType_t xHigherPriorityTaskWoken;
iDoTheThing++;
if ( iDoTheThing == 60000 )
{
xEventGroupSetBitsFromISR( eg, evtDoTheSunLampThing, &xHigherPriorityTaskWoken );
iDoTheThing = 0;
}
}
////
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
xSemaphoreTake( sema_MQTT_Parser, portMAX_DELAY); //if parsing is in progress hold up a moment to let parsing finish before sending a new things to parse
str_eTopic = topic + '\0';
int i = 0;
for ( i; i < length; i++) {
strPayload[i] = ((char)payload[i]);
}
strPayload[i] = '\0';
xSemaphoreGive ( sema_MQTT_Parser );
xEventGroupSetBits( eg, evtParseMQTT ); // trigger tasks
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
void setup()
{
//
gpio_config_t io_cfg = {};
io_cfg.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins to set
io_cfg.pin_bit_mask = ( (1ULL << GPIO_NUM_15) );
// //configure GPIO with the given settings
gpio_config(&io_cfg);
REG_WRITE(GPIO_OUT_W1TC_REG, BIT15); // sunlamp
//
/* Use 4th timer of 4.
1 tick 1/(80MHZ/80) = 1us set divider 80 and count up.
Attach onTimer function to timer
Set alarm to call timer ISR, every 1000uS and repeat / reset ISR (true) after each alarm
Start an timer alarm
*/
timer = timerBegin( 3, 80, true );
timerAttachInterrupt( timer, &onTimer, true );
timerAlarmWrite(timer, 1000, true);
timerAlarmEnable(timer);
//
str_eTopic.reserve(300);
//
eg = xEventGroupCreate();
//
sema_MQTT_Parser = xSemaphoreCreateBinary();
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
sema_mqttOK = xSemaphoreCreateBinary();
xSemaphoreGive( sema_mqttOK );
xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
////
xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 7000, NULL, 5, NULL, 1 ); // assign all to core 1, WiFi in use.
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 7000, NULL, 2, NULL, 1 ); //this task makes a WiFi and MQTT connection.
xTaskCreatePinnedToCore( fDoTheSunLampThing, "fDoTheSunLampThing", 2000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 2000, NULL, 3, NULL, 1 );
////
} //setup() END
////
///
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 86300; // 1st time update in 100 counts
int maxNonMQTTresponse = 60;
for (;;)
{
vTaskDelay( 1000 );
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
if ( mqttOK >= maxNonMQTTresponse )
{
ESP.restart();
}
mqttOK++;
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
//log_i( "mqttOK %d", mqttOK );
xSemaphoreGive( sema_mqttOK );
}
vTaskDelete( NULL );
}
////
void fDoTheSunLampThing( void * parameter )
{
int _hour = rtc.getHour(true);
// SunLampManual = sunlamp on manual mode, automatic mode off for manual mode to work
// SunLampAuto = sun lamp enable automatic mode
for (;;)
{
xEventGroupWaitBits (eg, evtDoTheSunLampThing, pdTRUE, pdTRUE, portMAX_DELAY );
// sun lamp auto mode of operation
//log_i( "SunLampManualOnOff %d SunLampAuto %d", SunLampManual, SunLampAuto );
if ( SunLampAuto )
{
// run in automated mode
_hour = rtc.getHour(true); // get hour in 24 hours format
log_i( "get hour %d", _hour );
if ( (_hour >= 7) && (_hour <= 19) )
{
REG_WRITE(GPIO_OUT_W1TS_REG, BIT15);
}
if ( (_hour < 7) || (_hour > 19) )
{
REG_WRITE(GPIO_OUT_W1TC_REG, BIT15);
}
} else {
// manual mode off/on
if ( (SunLampManual == 1) )
{
REG_WRITE(GPIO_OUT_W1TS_REG, BIT15);
} else {
REG_WRITE(GPIO_OUT_W1TC_REG, BIT15);
}
}
//log_i( " AlreadyOn = %d", AlreadyOn );
xSemaphoreGive( sema_MQTT_KeepAlive );
//log_i( "fDoTheSunLampThing high watermark %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete( NULL );
} // void fDoTheSunLampThing( void * parameter )
////
/*
Important to not set vtaskDelay to less then 10. Errors begin to develop with the MQTT and network connection.
makes the initial wifi/mqtt connection and works to keeps those connections open.
*/
void MQTTkeepalive( void *pvParameters )
{
// setting must be set before a mqtt connection is made
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
for (;;)
{
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
if ( !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
vTaskDelay( 250 ); //task runs approx every 250 mS
}
vTaskDelete ( NULL );
}
////
void connectToMQTT()
{
// create client ID from mac address
byte mac[5];
WiFi.macAddress(mac);
log_i( "mac address %d.%d.%d.%d.%d", mac[0], mac[1], mac[2], mac[3], mac[4] );
String clientID = String(mac[0]) + String(mac[4]) ;
log_i( "connect to mqtt as client %s", clientID );
while ( !MQTTclient.connected() )
{
MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password );
log_i( "connecting to MQTT" );
vTaskDelay( 250 );
}
log_i("MQTT Connected");
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( topic_SunLampOn );
MQTTclient.subscribe( topic_SunLampEnable );
MQTTclient.subscribe( topicOK );
}
//
void connectToWiFi()
{
while ( WiFi.status() != WL_CONNECTED )
{
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
vTaskDelay( 4000 );
}
WiFi.onEvent( WiFiEvent );
}
////
void fparseMQTT( void *pvParameters )
{
xSemaphoreGive ( sema_MQTT_Parser );
for (;;)
{
xEventGroupWaitBits ( eg, evtParseMQTT, pdTRUE, pdTRUE, portMAX_DELAY ); //
xSemaphoreTake( sema_MQTT_Parser, portMAX_DELAY );
if ( String(str_eTopic) == topic_SunLampOn )
{
SunLampManual = String(strPayload).toInt();
log_i( "SunLampManual on/off, %d", SunLampManual );
}
if ( String(str_eTopic) == topic_SunLampEnable )
{
SunLampAuto = String(strPayload).toInt();
log_i( "sunlampAuto %d", SunLampAuto);
}
// parse the time from the OK message and update MCU time
if ( String(str_eTopic) == topicOK )
{
if ( !TimeSet)
{
String temp = "";
temp = strPayload[0];
temp += strPayload[1];
temp += strPayload[2];
temp += strPayload[3];
int year = temp.toInt();
temp = "";
temp = strPayload[5];
temp += strPayload[6];
int month = temp.toInt();
temp = "";
temp = strPayload[8];
temp += strPayload[9];
int day = temp.toInt();
temp = "";
temp = strPayload[11];
temp += strPayload[12];
int hour = temp.toInt();
temp = "";
temp = strPayload[14];
temp += strPayload[15];
int min = temp.toInt();
rtc.setTime( 0, min, hour, day, month, year );
log_i( "%s rtc %s ", strPayload, rtc.getTime() );
TimeSet = true;
}
}
// clear pointer locations
memset( strPayload, '\0', 300 );
str_eTopic = ""; //clear string buffer
xSemaphoreGive( sema_MQTT_Parser );
xEventGroupSetBits( eg, evtDoTheSunLampThing );
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK = 0;
xSemaphoreGive( sema_mqttOK );
}
} // void fparseMQTT( void *pvParameters )
////
// great trouble shooting tool when uncommented
////
void WiFiEvent(WiFiEvent_t event)
{
// log_i( "[WiFi-event] event: %d\n", event );
switch (event) {
// case SYSTEM_EVENT_WIFI_READY:
// log_i("WiFi interface ready");
// break;
// case SYSTEM_EVENT_SCAN_DONE:
// log_i("Completed scan for access points");
// break;
// case SYSTEM_EVENT_STA_START:
// log_i("WiFi client started");
// break;
// case SYSTEM_EVENT_STA_STOP:
// log_i("WiFi clients stopped");
// break;
case SYSTEM_EVENT_STA_CONNECTED:
log_i("Connected to access point");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
// case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
// log_i("Authentication mode of access point has changed");
// break;
// case SYSTEM_EVENT_STA_GOT_IP:
// log_i ("Obtained IP address: %s", WiFi.localIP() );
// break;
// case SYSTEM_EVENT_STA_LOST_IP:
// log_i("Lost IP address and IP address is reset to 0");
// // vTaskDelay( 5000 );
// // ESP.restart();
// break;
// case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
// log_i("WiFi Protected Setup (WPS): succeeded in enrollee mode");
// break;
// case SYSTEM_EVENT_STA_WPS_ER_FAILED:
// log_i("WiFi Protected Setup (WPS): failed in enrollee mode");
// // ESP.restart();
// break;
// case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
// log_i("WiFi Protected Setup (WPS): timeout in enrollee mode");
// break;
// case SYSTEM_EVENT_STA_WPS_ER_PIN:
// log_i("WiFi Protected Setup (WPS): pin code in enrollee mode");
// break;
// case SYSTEM_EVENT_AP_START:
// log_i("WiFi access point started");
// break;
// case SYSTEM_EVENT_AP_STOP:
// log_i("WiFi access point stopped");
// // WiFi.mode( WIFI_OFF);
// // esp_sleep_enable_timer_wakeup( 1000000 * 2 ); // 1 second times how many seconds wanted
// // esp_deep_sleep_start();
// break;
// case SYSTEM_EVENT_AP_STACONNECTED:
// log_i("Client connected");
// break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
break;
// case SYSTEM_EVENT_AP_STAIPASSIGNED:
// log_i("Assigned IP address to client");
// break;
// case SYSTEM_EVENT_AP_PROBEREQRECVED:
// log_i("Received probe request");
// break;
// case SYSTEM_EVENT_GOT_IP6:
// log_i("IPv6 is preferred");
// break;
// case SYSTEM_EVENT_ETH_GOT_IP:
// log_i("Obtained IP address");
// break;
default: break;
}
}
////
void loop() { }
some mqtt code I use on an ESP32.