ESP32 with and LED's based on time

Heya,

I am trying to make a little device with some LED's. What I am looking for is code to tell the LED's to turn on according to a certain schedule.

LED1: Turn on on weekdays at 09:00, stay on for 10 minutes and then turn off.
LED2: Turn on once a day at 06:00 and then switch on and off every 6 minutes. stop doing this at midnight.

I am using an ESP32, so I can fetch time from an NTC server.
I love soldering and made my own board, but I suck big time at coding.
If people have ideas, links or any pointers: I'd be very grateful!

Not being a programmer and on a project that will require picking apart the time, there is an excellent time library for the ESP32 that makes picking apart the time easier.

1 Like

Hey @Idahowalker, thank you for your reply. I am looking into it now, but am still a bit lost...

The example in the ESP32time library sets the time at a hard coded time and then starts counting. Of course I'd prefer to get the current actual time...

Using the SimpleTime example I was able to query an NTP server to get current time.

But now I am looking for examples to learn from on how to use these time settings to turn my LED's on.

Do you, or anyone else, know of examples I could look at and learn from?

#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;
    }
    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
    if ( SunLampAuto )
    {
      // run in automated mode
      _hour = rtc.getHour(true); // get hour in 24 hours format
      if ( (_hour >= 7) && (_hour <= 17) )
      {
        REG_WRITE(GPIO_OUT_W1TS_REG, BIT15);
      }
      if ( (_hour < 7) || (_hour > 16) )
      {
        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);
      }
    }
    xSemaphoreGive( sema_MQTT_KeepAlive );
  }
  vTaskDelete( NULL );
} // void fDoTheSunLampThing( void * parameter )
////
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();
    }
    if ( String(str_eTopic) == topic_SunLampEnable )
    {
      SunLampAuto = String(strPayload).toInt();
    }
    // 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() { }

Using the time library to turn things on and off.

1 Like

oh wow, that is a whole bunch of code :astonished:
will take it apart to my best abilities. But to be sure: I am using the pins of the ESP32: so all references to MQTT can probably already be ignored, no?

I don't see why not.