Combinding 2 code to work as one

I'm working on a project where I want Alexa to control a light with a timer and the same light with pressing a button to start the timer say for 1 minute (for testing).

I can get them to work individually but when I add the timer code instead of running for 1 minute as expected it seems to run for 30 seconds.

On both the button press and Alexa turns the relay on/off ok.

This is the Alexa code with timer code combined.

#include <Arduino.h>
#include <RCSwitch.h>
#ifdef ESP32
#include <WiFi.h>

#else
#include <ESP8266WiFi.h>
#endif
#include "fauxmoESP.h"
#define WIFI_SSID "XXXXXXXX" // edit it according to your router configuration
#define WIFI_PASS "XXXXXXXXX" // edit it according to your router configuration
fauxmoESP fauxmo;
// -----------------------------------------------------------------------------
#define SERIAL_BAUDRATE     115200
int ledState = LOW;         // the current state of the output pin
int buttonState = LOW;            // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long LightONinterval = 1000UL * 60; // 1 minute timer, will be changed to siut
unsigned long currentMillis = 0;
unsigned long lastLight = 0;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
#define  buttonPin D2    // the pin that the pushbutton is attached to
#define Channel1_PIN          D0 //Turn light relay on/off
#define ID_Channel1           "Garden light" // Spa lights 
// Wifi
// -----------------------------------------------------------------------------

void wifiSetup() {

  // Set WIFI module to STA mode
  WiFi.mode(WIFI_STA);

  // Connect
  Serial.printf("[WIFI] Connecting to %s ", WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASS);

  // Wait
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }
  Serial.println();

  // Connected!
  Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());

}

void setup() {
  // Init serial port and clean garbage
  Serial.begin(SERIAL_BAUDRATE);
  Serial.println();
  Serial.println();
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(Channel1_PIN, OUTPUT);
  digitalWrite(buttonPin, HIGH);
  digitalWrite(Channel1_PIN, LOW);
  wifiSetup();
  // By default, fauxmoESP creates it's own webserver on the defined port
  // The TCP port must be 80 for gen3 devices (default is 1901)
  // This has to be done before the call to enable()
  fauxmo.createServer(true); // not needed, this is the default value
  fauxmo.setPort(80); // This is required for gen3 devices
  // You have to call enable(true) once you have a WiFi connection
  // You can enable or disable the library at any moment
  // Disabling it will prevent the devices from being discovered and switched
  fauxmo.enable(true);
  // Add virtual devices
  fauxmo.addDevice(ID_Channel1);
  fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state, unsigned char value) {
    // Callback when a command from Alexa is received.
    // You can use device_id or device_name to choose the element to perform an action onto (relay, LED,...)
    // State is a boolean (ON/OFF) and value a number from 0 to 255 (if you say "set kitchen light to 50 % " you will receive a 128 here).
    // Just remember not to delay too much here, this is a callback, exit as soon as possible.
    // If you have to do something more involved here set a flag and process it in your main loop.
    Serial.printf("[MAIN] Device #%d (%s) state: %s value: %d\n", device_id, device_name, state ? "ON" : "OFF", value);
    if ( (strcmp(device_name, ID_Channel1) == 0) ) {
      // Turn channel 1 on,otherwise tutn channel 2 off
      if (state) {
        Serial.println("RELAY 1 switched ON by Alexa");
        //ledState = HIGH;
        ledState = !ledState;
        digitalWrite(Channel1_PIN, ledState);
        //only placed line bekow for testing trying to stop earylswitc hoff
        // lastLight = currentMillis;//load the timer with last mills reading
      } else {
        Serial.println("RELAY 1 switched OFF by Alexa");
        // ledState = LOW;
        ledState = !ledState;
        digitalWrite(Channel1_PIN, ledState);
      }
    }

  });
}

void loop() {

  // fauxmoESP uses an async TCP server but a sync UDP server
  // Therefore, we have to manually poll for UDP packets
  fauxmo.handle();

  // This is a sample code to output free heap every 5 seconds
  // This is a cheap way to detect memory leaks
  static unsigned long last = millis();
  if (millis() - last > 5000) {
    last = millis();
    Serial.printf("[MAIN] Free heap: % d bytes\n", ESP.getFreeHeap());
    Serial.println( ledState);
  }

  // manully activate the timer by a button press
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  //  digitalWrite(Channel1_PIN,ledState);

  currentMillis = millis() ;
  if (ledState == HIGH && currentMillis - lastLight > LightONinterval )
  {
    lastLight = currentMillis;//load the timer with last mills reading
    ledState = !ledState; // Check the state of led
    digitalWrite(Channel1_PIN,  ledState);
  }
  lastButtonState = reading;
}

This is just the timer code which runs for the expected 1 minute, Once it has timed out it's self, I can press the button and it runs for the same time 1 minute.

 const int buttonPin = 2;    // the number of the pushbutton pin
const int Logging_led = 13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;         // the current state of the output pin
int buttonState = LOW;            // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long LightONinterval = 1000UL * 60; 
// constants won't change :
const long interval = 1000UL * 60;
 unsigned long currentMillis ;
unsigned long lastLight = 0;
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(Logging_led, OUTPUT);
  digitalWrite(buttonPin, HIGH);
  // set initial LED state
  digitalWrite(Logging_led, LOW);
}


void loop() {

int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        ledState = !ledState;
      }
   
  }
 
    
  }     
   digitalWrite(Logging_led, ledState);
  lastButtonState = reading;
currentMillis = millis() ;
     if (ledState == HIGH && currentMillis - lastLight > LightONinterval )
  {
 ledState = !ledState; 
    lastLight = currentMillis;
      digitalWrite(Logging_led,  ledState);
  }     
}

Not sure what's messing things up ?

Steve

A couple of questions, but first, do you intent for lastLight to be zero on the first pass?

Question- how are you getting Alexa commands through FauxMo Server?? Curious minds want to know.

SteveMann:
A couple of questions, but first, do you intent for lastLight to be zero on the first pass?

Question- how are you getting Alexa commands through FauxMo Server?? Curious minds want to know.

I just like to make sure that if you reset it, It starts back from zero, I've seen it in other peoples code.

They show up as a Philips Hue bulb, (well on my first one they do) on this version they show up as other hue devices not sure why, Which I may look into as you can only ask Alexa to turn them on/off and set the dimming value via voice as the others you can set the brightness via the app

steve

It's not entirely clear what you want the light to do. I'm guessing:

Tell Alexa to turn on the light: Light comes on and stays on.
Tell Alexa to turn off the light: Light goes off and stays off.
Push the button while the light is off: Light comes on and if nothing else is done, goes off after one minute.
Push the button while the light is on: Light goes off and stays off.

Here I set "lastLight" to millis() to start the one minute timer when the button turns the light on. At all other times "lastLight" is set to 0 to indicate that the timer is not running.

// Handling the data from Alexa:

  if ( (strcmp(device_name, ID_Channel1) == 0) )
  {
    // Turn channel 1 on, otherwise turn channel 1 off
    if (state)
    {
      Serial.println("RELAY 1 switched ON by Alexa");
      ledState = HIGH;
    }
    else
    {
      Serial.println("RELAY 1 switched OFF by Alexa");
      ledState = LOW;
    }
    lastLight = 0;  // DISABLE THE TIMER
    digitalWrite(Channel1_PIN, ledState);
  }

And here is loop() to handle button state changes, debounce, and the turn-off timer

void loop()
{
  unsigned long currentMillis = millis();


  // fauxmoESP uses an async TCP server but a sync UDP server
  // Therefore, we have to manually poll for UDP packets
  fauxmo.handle();


  // This is a sample code to output free heap every 5 seconds
  // This is a cheap way to detect memory leaks
  static unsigned long lastHeapTime;
  if (currentMillis - lastHeapTime > 5000)
  {
    lastHeapTime = currentMillis;
    Serial.printf("[MAIN] Free heap: % d bytes\n", ESP.getFreeHeap());
    Serial.println( ledState);
  }


  // Manually activate the timer by a button press
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState && currentMillis - lastDebounceTime > debounceDelay)
  {
    lastDebounceTime = currentMillis;
    lastButtonState = buttonState;


    // If the button has just gone HIGH, toggle the light
    if (buttonState == HIGH)
    {
      ledState = !ledState;
      digitalWrite(Channel1_PIN, ledState);
      // If the light was just turned on, start a timer
      if (ledState == HIGH)
        lastLight = currentMillis;  // Start the timer
      else
        lastLight = 0;    // DISABLE THE TIMER
    }
  }


  // If the light has been on for the interval, turn it off
  if (lastLight != 0 && currentMillis - lastLight > LightONinterval )
  {
    ledState = LOW; // Turn off
    lastLight = 0;    // DISABLE THE TIMER
    digitalWrite(Channel1_PIN,  ledState);
  }
}

Thanks for the reply.
I want to control some lights that I have in my summer house and The idea of the project I that I can either get alexa to turn the light on and after 2-3hrs it will turn of automatically or unless I ask alexa to turn it off.

And the same for the button press turns the lights on manually and auto turn off or again unless I press the button. I have other stuff that I want to ad to the code but those will just be on/off by alexa.

I only set it for 1 minute just for testing. When I just had the timer code working on its own it was timed for that one minute but adding to the alexa code it seems to time out early.
I will look at and go through the code you posted

Thanks for your help
Steve

If you want the light to turn off the same time after Alexa turns it on as when the button turns it on:

  if ( (strcmp(device_name, ID_Channel1) == 0) )
  {
    // Turn channel 1 on, otherwise turn channel 1 off
    if (state)
    {
      Serial.println("RELAY 1 switched ON by Alexa");
      ledState = HIGH;
      lastLight = currentMillis;  // Start the auto-off timer
    }
    else
    {
      Serial.println("RELAY 1 switched OFF by Alexa");
      ledState = LOW;
      lastLight = 0;  // DISABLE THE TIMER
    }


    digitalWrite(Channel1_PIN, ledState);
  }