c++esp8266fastled

Trigger a function on alarm time


i am trying to make an alarm clock with esp8266 and ws2812b leds. On alarm time it must call the sunrise() function. The sunrise() function works fine when i put it directly in the loop function. But it doesn't work in alarm trigger.

  if (AlarmData.AlarmOn[Current.Day])
  {
    if (!AlarmActive)//do not enter this routine if alarm already active
    {
      if (Current.Hour == AlarmData.Hour[Current.Day])
      {
        if (Current.Minute == AlarmData.Minute[Current.Day])
        {
          if (Current.Second > 0 && Current.Second < 3)
          {
            AlarmActive = true;
            sunrise();
            alarmTriggerTime = micros();
            Serial.println("Its time for your alarm!");

          }
        }
      }
    }
  }

My code is below. thanks in advance for your help

#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include "EEPROMAnything.h"
#include "get_time.h"
#include "OTA.h"
#include <stdio.h>
#include <stdint.h>
#include "web_portal.h"
#include "ESP8266TimerInterrupt.h"
#include "restore_factory_settings.h"
#include "FastLED.h"

#define NUM_LEDS 60
#define DATA_PIN 5



// Define the array of leds
CRGB leds[NUM_LEDS];
#define timeZone 3

#define TenSecs 10000000
#define OneMin 60000000
#define TenMins 600000000

#define TIMER_INTERVAL_MS   1000

ESP8266Timer ITimer;

int timer;
int alarmTriggerTime;
struct CurrentTime Current;
bool AlarmActive;
struct AlarmDataStruct AlarmData;
int WiFiTimer;
char factory_settings_stored [3];
bool OneSecoundPassed;

void ICACHE_RAM_ATTR TimerHandler(void)
{
  OneSecoundPassed = true;
}



void setup() {

  Serial.begin(115200);
  Serial.println("Booting");
  EEPROM.begin(512);
  EEPROM_readAnything(150, factory_settings_stored);
  if (memcmp(&factory_settings_stored, "YES", 3) != 0)
  {
    restore_factory_settings();
  }
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(0);
  WiFi.mode(WIFI_STA);
  WiFiManager wm;


  bool response;
  response = wm.autoConnect("AutoConnectAP"); // anonymous ap
  if (!response) {
    Serial.println("Failed to connect");
    // ESP.restart();
  }
  else {
    //if you get here you have connected to the WiFi
    Serial.println("Lets Go");
  }


  start_server();
  SetupOTA();
  setup_time(timeZone);
  Current = Current_Time();

  EEPROM_readAnything(100, AlarmData);
  Serial.print("Alarm set for ");
  Serial.print(AlarmData.Hour[Current.Day]);
  Serial.print(":");
  Serial.println(AlarmData.Minute[Current.Day]);
  timer = micros();
  WiFiTimer = timer;

  // Interval in microsecs
  if (ITimer.attachInterruptInterval(TIMER_INTERVAL_MS * 1000, TimerHandler))
  {
    Serial.println("Starting  ITimer OK, millis() = " + String(millis()));
  }
  else
  {
    Serial.println("Can't set ITimer correctly. Select another freq. or interval");
  }
}


void loop() {
  if (!AlarmActive)
  {
    ArduinoOTA.handle();
    handle_client();

    if ((micros() - WiFiTimer) > TenMins) // check if wifi connection lost and if so try to reconnect
    {
      if (WiFi.status() != WL_CONNECTED)
      {
        ESP.restart(); //try to reconnect rather than resetting
      }
      WiFiTimer = micros();
    }

    if (OneSecoundPassed)
    {
      updateLocalTime();
      OneSecoundPassed = false;
    }

    //update current hour from NTP server
    if ((micros() - timer) > TenMins)
    {
      Current = Current_Time();
      timer = micros();
    }

  }
  if (AlarmActive)
  {
    if ((micros() - alarmTriggerTime) > TenMins)
    {
      AlarmActive = false; //if alarm active for 10mins and no one switches it off then do it auto
    }
  }


  if (AlarmData.AlarmOn[Current.Day])
  {
    if (!AlarmActive)//do not enter this routine if alarm already active
    {
      if (Current.Hour == AlarmData.Hour[Current.Day])
      {
        if (Current.Minute == AlarmData.Minute[Current.Day])
        {
          if (Current.Second > 0 && Current.Second < 3)
          {
            AlarmActive = true;
            sunrise();
            alarmTriggerTime = micros();
            Serial.println("Its time for your alarm!");

          }
        }
      }
    }
  }



  else
  {
    if (!AlarmActive)
    {

    }
  }
}




void updateLocalTime () {
  Current.Second++;
  if (Current.Second >= 60)
  {
    Current.Second = 0;
    Current.Minute++;
    if (Current.Minute >= 60)
    {
      Current.Minute = 0;
      Current.Hour++;
      if (Current.Hour >= 24)
      {
        Current.Hour = 0;
        Current.Day++;
        if (Current.Day >= 7)
        {
          Current.Day = 0;
        }
      }
    }
  }
  char tempTime[6];
  if (Current.Minute < 10 && Current.Second < 10)
  {
    sprintf(tempTime, "0%d:0%d", Current.Minute, Current.Second);
  }
  else if (Current.Minute < 10)
  {
    sprintf(tempTime, "0%d:%d", Current.Minute, Current.Second);
  }
  else if (Current.Second < 10)
  {
    sprintf(tempTime, "%d:0%d", Current.Minute, Current.Second);
  }
  else
  {
    sprintf(tempTime, "%d:%d", Current.Minute, Current.Second);
  }

}

void sunrise() {
  static const uint8_t sunriseLength = 30; //(min)
  static const uint8_t interval = (sunriseLength * 60) / 256;
  static const uint8_t binterval = (sunriseLength * 60) / 256;


  // current gradient palette color index
  static uint8_t heatIndex = 0; // start out at 0
  static uint8_t brIndex = 0;


  // HeatColors_p is a gradient palette built in to FastLED
  // that fades from black to red, orange, yellow, white
  // feel free to use another palette or define your own custom one
  CRGB color = ColorFromPalette(HeatColors_p, heatIndex);
  fill_solid(leds, NUM_LEDS, color); // fill the entire strip with the current color
  EVERY_N_SECONDS(binterval) {
    if (brIndex < 255) {
      FastLED.setBrightness(brIndex);
      brIndex++;
    }
  }
  EVERY_N_SECONDS(interval) {
    if (heatIndex < 255) {
      heatIndex++;
    }
  }
  FastLED.show();
}

Solution

  • Your sunrise function should be called over and over, every call changes the LED color a slight bit. This is why it works then you put it into the loop function.

    However, you have guarded it so that it is specifically only called once - so now it is called, sets the LEDs to the dimmest setting possible, and is not called again.

    What you need to do is separate this out into two parts: One that detects when to activate sunrise, and one that is continuously called when it is time. F.ex:

    void loop()
    {
        /* stuff */
    
        if (AlarmData.AlarmOn[Current.Day])
        {
            if (!AlarmActive) // do not enter this routine if alarm already active
            {
                if (Current.Hour == AlarmData.Hour[Current.Day])
                {
                    if (Current.Minute == AlarmData.Minute[Current.Day])
                    {
                        if (Current.Second > 0 && Current.Second < 3)
                        {
                            AlarmActive = true;
                            alarmTriggerTime = micros();
                            Serial.println("Its time for your alarm!");
                        }
                    }
                }
            }
        }
    
        if (AlarmActive)
            sunrise();
    }