Driver to illuminate the stairs, driveway, etc...

Post Reply
elmaya
Posts: 1482
Joined: Wed Jun 27, 2018 5:48 pm
Location: El Saucejo - Sevilla

Based on PCA9685 and ESP8266 it is configurable for 2 to 64 PWM output channels.
16 outputs per PCA9685, for 64 outputs you need 4 X PCA9685.

It consists of 2 dimmer channels, 3 staircase timer channels and one light switch:

the first dimmer set the level of the outputs for when they are on between 50% and 100%.
the second dimmer set the level of the outputs for when they are off between 0% and 50%.

three staircase timer channels:
the first to turn on in sequence from the first output to the last and turns off in sequence from the first to the last."also with button 1"
the second to turn on in sequence from the last output to the first and turn off in sequence from the last to the first."also with button 2"
the third to turn on in sequence from the output set as center to the first / last and turn off in sequence from the output set as center to the first / last."also with button 3"

One light switch channel to turn all the channels On / Off at the same time.
allows to leave On."also with double click on any button"

PCA9685_x_64_bb.png
PCA9685_x_64_bb.png (184.49 KiB) Viewed 4076 times
For testing you can connect Led diodes directly to the outputs and GND.
Gpio4 "D2" = SDA -- PCA9685
Gpio5 "D1" = SCL -- PCA9685
Gpio2 "D4" = LED_PIN
Gpio0 "D3" = button_0
Gpio14 "D5" = button_1
Gpio12 "D6" = button_3

ESP Buildin Led:
winking 0.5 seconds = not connected / connecting.
on = WiFiConfig.
off = connected / Ok.

button 1:
click = toggle On / Off from 0 to XX "climb stairs".
double click = togle all On / OFF.
hold 10 seconds = WiFiConfig.

button 2:
click = toggle On / Off from XX to 0 "go down stairs".
double click = togle all On / OFF.

button 3:
click = toggle On / Off from center to 0/XX.
double click = togle all On / OFF.


in WiFiConfig are some additional parameters:

"Fade Time for each Step".
this is the time it takes to turn on each output in milliseconds, 500 is a good value to start with.
500 * 16 = 8 seconds.

"Number of Step".
number of outputs up to a maximum of 64 (4 x PCA9685).

"Center Step".
central channel "button 3".

Code: Select all

#define supla_lib_config_h_  // silences debug messages
#include "LittleFS.h"
#include <Wire.h>
#include <WiFiManager.h>
#include <EEPROM.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266TrueRandom.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <Button3.h>
#include <Ticker.h>
#include <Adafruit_PWMServoDriver.h>
#include <SuplaDevice.h>
#include <supla/control/dimmer_base.h>
#include <supla/control/relay.h>
#include <supla/network/esp_wifi.h>
Supla::ESPWifi wifi("SSID", "PASS");  //------ Do not change----wifimanager takes care------
#define STORAGE_OFFSET 512
#include <supla/storage/eeprom.h>
Supla::Eeprom eeprom(STORAGE_OFFSET);

//#define D0 16  //no internal pullup resistor
//#define D1  5
//#define D2  4
//#define D3  0  //must not be pulled low during power on/reset, toggles value during boot
//#define D4  2  //must not be pulled low during power on/reset, toggles value during boot
//#define D5 14
//#define D6 12
//#define D7 13
//#define D8 15  //must not be pulled high during power on/reset
//#define RX  3  //High at boot
//#define TX  1  //must not be pulled low during power on/reset

#define SCL_PIN 5        //D1
#define SDA_PIN 4        //D2
#define LED_PIN  2       //D4
#define button_0_pin  0  //D3
#define button_1_pin  14 //D5
#define button_2_pin  12 //D6

bool statusLedOn = LOW;

const int PWM_SEQUENCE_STOP       = -1;
const int PWM_SEQUENCE_ON_0_TO_XX  = 1;
const int PWM_SEQUENCE_OFF_XX_TO_0 = 2;
const int PWM_SEQUENCE_ON_ALL      = 3;
const int PWM_SEQUENCE_OFF_ALL     = 4;
const int PWM_SEQUENCE_ON_XX_TO_0  = 5;
const int PWM_SEQUENCE_OFF_0_TO_XX = 6;
const int PWM_SEQUENCE_ON_X_TO_MAX_MIN = 7;
const int PWM_SEQUENCE_OFF_X_TO_MAX_MIN = 8;
int pwmSequence = PWM_SEQUENCE_STOP;
int pwmOutLevel[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int pwmMaxLevel = 4095;
int pwmMinLevel = 0;
int numPwmOut = 16;
int numCenter = 8;
int fadeEffect = 500;
int currentPwmChannel = 0;
int upPwmChannel = numCenter;
int downPwmChannel = numCenter;
bool upSequense = false;
bool downSequence = false;
bool setupEnd = false;
const int  relay_0_pin = 200;
const int  relay_1_pin = 201;
const int  relay_2_pin = 202;
const int  relay_3_pin = 203;
bool relay_0_state = false;
bool relay_1_state = false;
bool relay_2_state = false;
bool relay_3_state = false;
bool setOff = false;
int offTriger = -1;
unsigned long ultimaPasada;
int C_W_state = HIGH;
int last_C_W_state = HIGH;
unsigned long time_last_C_W_change = 0;
long C_W_delay = 10000;               // ---------------------- config delay 10 seconds ---------------------------
char Supla_server[81] = ("Set server address");
char Email[81] = ("set email address");
char Supla_name[81] = ("SuplaPCA9685");
char FadeTime[8] = ("500");
char NumPwmOut[3] = ("16");
char NumCenter[3] = ("8");
char Router_SSID[32];
char Router_Pass[64];
char Supla_status[51];
bool shouldSaveConfig = false;
bool initialConfig = false;
bool starting = true;
bool tikOn = true;
int s;
char GUID[SUPLA_GUID_SIZE];
char AUTHKEY[SUPLA_AUTHKEY_SIZE];
byte uuidNumber[16];
static const char logo[] PROGMEM = "<style>html{ background-color: #01DF3A;}</style><div class='s'><svg version='1.1' id='l' x='0' y='0' viewBox='0 0 200 200' xml:space='preserve'><path d='M59.3,2.5c18.1,0.6,31.8,8,40.2,23.5c3.1,5.7,4.3,11.9,4.1,18.3c-0.1,3.6-0.7,7.1-1.9,10.6c-0.2,0.7-0.1,1.1,0.6,1.5c12.8,7.7,25.5,15.4,38.3,23c2.9,1.7,5.8,3.4,8.7,5.3c1,0.6,1.6,0.6,2.5-0.1c4.5-3.6,9.8-5.3,15.7-5.4c12.5-0.1,22.9,7.9,25.2,19c1.9,9.2-2.9,19.2-11.8,23.9c-8.4,4.5-16.9,4.5-25.5,0.2c-0.7-0.3-1-0.2-1.5,0.3c-4.8,4.9-9.7,9.8-14.5,14.6c-5.3,5.3-10.6,10.7-15.9,16c-1.8,1.8-3.6,3.7-5.4,5.4c-0.7,0.6-0.6,1,0,1.6c3.6,3.4,5.8,7.5,6.2,12.2c0.7,7.7-2.2,14-8.8,18.5c-12.3,8.6-30.3,3.5-35-10.4c-2.8-8.4,0.6-17.7,8.6-22.8c0.9-0.6,1.1-1,0.8-2c-2-6.2-4.4-12.4-6.6-18.6c-6.3-17.6-12.7-35.1-19-52.7c-0.2-0.7-0.5-1-1.4-0.9c-12.5,0.7-23.6-2.6-33-10.4c-8-6.6-12.9-15-14.2-25c-1.5-11.5,1.7-21.9,9.6-30.7C32.5,8.9,42.2,4.2,53.7,2.7c0.7-0.1,1.5-0.2,2.2-0.2C57,2.4,58.2,2.5,59.3,2.5z M76.5,81c0,0.1,0.1,0.3,0.1,0.6c1.6,6.3,3.2,12.6,4.7,18.9c4.5,17.7,8.9,35.5,13.3,53.2c0.2,0.9,0.6,1.1,1.6,0.9c5.4-1.2,10.7-0.8,15.7,1.6c0.8,0.4,1.2,0.3,1.7-0.4c11.2-12.9,22.5-25.7,33.4-38.7c0.5-0.6,0.4-1,0-1.6c-5.6-7.9-6.1-16.1-1.3-24.5c0.5-0.8,0.3-1.1-0.5-1.6c-9.1-4.7-18.1-9.3-27.2-14c-6.8-3.5-13.5-7-20.3-10.5c-0.7-0.4-1.1-0.3-1.6,0.4c-1.3,1.8-2.7,3.5-4.3,5.1c-4.2,4.2-9.1,7.4-14.7,9.7C76.9,80.3,76.4,80.3,76.5,81z M89,42.6c0.1-2.5-0.4-5.4-1.5-8.1C83,23.1,74.2,16.9,61.7,15.8c-10-0.9-18.6,2.4-25.3,9.7c-8.4,9-9.3,22.4-2.2,32.4c6.8,9.6,19.1,14.2,31.4,11.9C79.2,67.1,89,55.9,89,42.6z M102.1,188.6c0.6,0.1,1.5-0.1,2.4-0.2c9.5-1.4,15.3-10.9,11.6-19.2c-2.6-5.9-9.4-9.6-16.8-8.6c-8.3,1.2-14.1,8.9-12.4,16.6C88.2,183.9,94.4,188.6,102.1,188.6z M167.7,88.5c-1,0-2.1,0.1-3.1,0.3c-9,1.7-14.2,10.6-10.8,18.6c2.9,6.8,11.4,10.3,19,7.8c7.1-2.3,11.1-9.1,9.6-15.9C180.9,93,174.8,88.5,167.7,88.5z'/></svg>";

ESP8266WebServer httpServer(81);
ESP8266HTTPUpdateServer httpUpdater;
WiFiManager wifiManager;
Ticker ticker;
Ticker tickerB;
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x42);
Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x43);
Button3 buttonA = Button3(button_0_pin);
Button3 buttonB = Button3(button_1_pin);
Button3 buttonC = Button3(button_2_pin);

Supla::Control::Relay *relay_0 = nullptr;
Supla::Control::Relay *relay_1 = nullptr;
Supla::Control::Relay *relay_2 = nullptr;
Supla::Control::Relay *relay_3 = nullptr;

void setPCA9685(uint8_t num, uint16_t on, uint16_t off) {

  if ( num < 16) {
    pwm0.setPWM(num, on, off);      // PCA-0 from 0 to 15
  } else if (( num > 15 ) && (num < 32)) {
    pwm1.setPWM(num - 16, on, off); // PCA-1 from 16 to 31
  } else if (( num > 31 ) && (num < 48)) {
    pwm2.setPWM(num - 32, on, off); // PCA-2 from 32 to 47
  } else if (( num > 47 ) && (num < 64)) {
    pwm3.setPWM(num - 48, on, off); // PCA-3 from 48 to 63
  }
}

class PwmDimm : public Supla::Control::DimmerBase {
  public:
    PwmDimm(int pwmChannel)
      : pwmChannel(pwmChannel) {
    }
    void setRGBWValueOnDevice(uint32_t red,
                              uint32_t green,
                              uint32_t blue,
                              uint32_t colorBrightness,
                              uint32_t brightness) {

      uint32_t brightnessAdj = brightness;

      if ( pwmChannel == 0) {
        brightnessAdj = map(brightnessAdj, 0, 1023, 2047, 4095);
        for (uint8_t i = 0; i < numPwmOut; i++) {
          if (pwmOutLevel[i] >= pwmMaxLevel) {
            setPCA9685(i, 0, brightnessAdj);
            pwmOutLevel[i] = brightnessAdj;
          }
        }
        pwmMaxLevel = brightnessAdj;
      }
      else if ( pwmChannel == 1) {
        brightnessAdj = map(brightnessAdj, 0, 1023, 0, 2047);
        for (uint8_t i = 0; i < numPwmOut; i++) {
          if (pwmOutLevel[i] <= pwmMinLevel) {
            setPCA9685(i, 0, brightnessAdj);
            pwmOutLevel[i] = brightnessAdj;
          }
        }
        pwmMinLevel = brightnessAdj;
      }
    }
  protected:
    int pwmChannel;
};
class CustomControl : public Supla::Io {
  public:
    void customDigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {

      if ((pin == relay_0_pin) && (setupEnd)) {
        if (val == 1) {
          relay_0_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 0;
          }
          currentPwmChannel = 0;
          pwmSequence = PWM_SEQUENCE_ON_0_TO_XX;
          Serial.println("ON Min to Max");
        }
        else if ((val == 0) && (setupEnd)) {
          relay_0_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 1;
            currentPwmChannel = 0;
            pwmSequence = PWM_SEQUENCE_OFF_0_TO_XX;
            Serial.println("OFF Min to Max");
          }
        }
      }
      else if ((pin == relay_1_pin) && (setupEnd)) {
        if (val == 1) {
          relay_1_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 2;
          }
          pwmSequence = PWM_SEQUENCE_ON_ALL;
          Serial.println("On All");
        }
        if (val == 0) {
          relay_1_state = false;
          if (setOff == false) {
            setOff = true;
            offTriger = 2;
            pwmSequence = PWM_SEQUENCE_OFF_ALL;
            Serial.println("Off All");
          }
        }
      }
      else if ((pin == relay_2_pin) && (setupEnd)) {
        if (val == 1) {
          relay_2_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 3;
          }
          currentPwmChannel = numPwmOut - 1;
          pwmSequence = PWM_SEQUENCE_ON_XX_TO_0;
          Serial.println("ON Max to Min");
        }
        if (val == 0) {
          relay_2_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 4;
            currentPwmChannel = numPwmOut - 1;
            pwmSequence = PWM_SEQUENCE_OFF_XX_TO_0;
            Serial.println("OFF Max to Min");
          }
        }
      }
      else if ((pin == relay_3_pin) && (setupEnd)) {
        if (val == 1) {
          relay_3_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 5;
          }
          upSequense = true;
          downSequence = true;
          upPwmChannel = numCenter;
          downPwmChannel = (numCenter - 1);
          pwmSequence = PWM_SEQUENCE_ON_X_TO_MAX_MIN;
          Serial.println("ON Center to MaxMin");
        }
        if (val == 0) {
          relay_3_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 6;
            upSequense = true;
            downSequence = true;
            upPwmChannel = numCenter;
            downPwmChannel = (numCenter - 1);
            pwmSequence = PWM_SEQUENCE_OFF_X_TO_MAX_MIN;
            Serial.println("OFF Center to MaxMin");
          }
        }
      }
      else {
        return ::digitalWrite(pin, val);
      }
    }

    int customDigitalRead(int channelNumber, uint8_t pin) {
      if (pin == relay_0_pin) {
        return relay_0_state;
      } else if (pin == relay_1_pin) {
        return relay_1_state;
      } else if (pin == relay_2_pin) {
        return relay_2_state;
      } else if (pin == relay_3_pin) {
        return relay_3_state;
      } else {
        return ::digitalRead(pin);
      }
    }
} CustomControl;

void rampa() {
  unsigned long timePast = millis() - ultimaPasada;
  ultimaPasada = millis();
  if (timePast > 0) {
    double divisor = 1.0 * fadeEffect / timePast;
    if (divisor <= 0) {
      divisor = 1;
    }
    int psos = pwmMaxLevel / divisor;
    if (psos < 1) {
      psos = 1;
    }

    switch (pwmSequence) {

      case PWM_SEQUENCE_STOP: break;

      case PWM_SEQUENCE_ON_0_TO_XX: {
          pwmOutLevel[currentPwmChannel] += psos;
          if (pwmOutLevel[currentPwmChannel] >= pwmMaxLevel) {
            int sobras = (pwmOutLevel[currentPwmChannel] - pwmMaxLevel) + pwmOutLevel[currentPwmChannel + 1];
            pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
            if (currentPwmChannel < (numPwmOut - 1)) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel ++;
              if (sobras <= pwmMaxLevel) {
                pwmOutLevel[currentPwmChannel] = sobras;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMaxLevel);
              pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);;
          }
        } break;

      case PWM_SEQUENCE_OFF_XX_TO_0: {
          pwmOutLevel[currentPwmChannel] -= psos;
          if (pwmOutLevel[currentPwmChannel] <= pwmMinLevel) {
            int faltas = (pwmOutLevel[currentPwmChannel] - pwmMinLevel) + pwmOutLevel[currentPwmChannel - 1];
            pwmOutLevel[currentPwmChannel] = pwmMinLevel;
            if (currentPwmChannel > 0) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel --;
              if (faltas >= pwmMinLevel) {
                pwmOutLevel[currentPwmChannel] = faltas;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMinLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMinLevel);
              pwmOutLevel[currentPwmChannel] = pwmMinLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_ON_ALL: {
          for (uint8_t i = 0; i < numPwmOut; i++) {
            pwmOutLevel[i] += psos;
            if (pwmOutLevel[i] >= pwmMaxLevel) {
              pwmOutLevel[i] = pwmMaxLevel;
              setPCA9685(i, 0, pwmOutLevel[i]);
              if (i >= (numPwmOut - 1)) {
                pwmSequence = PWM_SEQUENCE_STOP;
                Serial.println("PWM_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(i, 0, pwmOutLevel[i]);
            }
          }
        } break;

      case PWM_SEQUENCE_OFF_ALL: {
          for (uint8_t i = 0; i < numPwmOut; i++) {
            pwmOutLevel[i] -= psos;
            if (pwmOutLevel[i] <= pwmMinLevel) {
              pwmOutLevel[i] = pwmMinLevel;
              setPCA9685(i, 0, pwmOutLevel[i]);
              if (i >= (numPwmOut - 1)) {
                pwmSequence = PWM_SEQUENCE_STOP;
                Serial.println("PWM_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(i, 0, pwmOutLevel[i]);
            }
          }
        } break;

      case PWM_SEQUENCE_ON_XX_TO_0: {
          pwmOutLevel[currentPwmChannel] += psos;
          if (pwmOutLevel[currentPwmChannel] >= pwmMaxLevel) {
            int sobras = (pwmOutLevel[currentPwmChannel] - pwmMaxLevel) + pwmOutLevel[currentPwmChannel - 1];
            pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
            if (currentPwmChannel > 0) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel --;
              if (sobras <= pwmMaxLevel) {
                pwmOutLevel[currentPwmChannel] = sobras;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMaxLevel);
              pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_OFF_0_TO_XX: {
          pwmOutLevel[currentPwmChannel] -= psos;
          if (pwmOutLevel[currentPwmChannel] <= pwmMinLevel) {
            int faltas = (pwmOutLevel[currentPwmChannel] - pwmMinLevel) + pwmOutLevel[currentPwmChannel + 1];
            pwmOutLevel[currentPwmChannel] = pwmMinLevel;
            if (currentPwmChannel < (numPwmOut - 1)) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel ++;
              if (faltas >= pwmMinLevel) {
                pwmOutLevel[currentPwmChannel] = faltas;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMinLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMinLevel);
              pwmOutLevel[currentPwmChannel] = pwmMinLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_ON_X_TO_MAX_MIN: {
          if ((upSequense) && (upPwmChannel < numPwmOut)) {
            pwmOutLevel[upPwmChannel] += psos;
            if (pwmOutLevel[upPwmChannel] >= pwmMaxLevel) {
              int upSobras = (pwmOutLevel[upPwmChannel] - pwmMaxLevel) + pwmOutLevel[upPwmChannel + 1];
              pwmOutLevel[upPwmChannel] = pwmMaxLevel;
              if (upPwmChannel < (numPwmOut - 1)) {
                setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                upPwmChannel ++;
                if (upSobras <= pwmMaxLevel) {
                  pwmOutLevel[upPwmChannel] = upSobras;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                } else {
                  pwmOutLevel[upPwmChannel] = pwmMaxLevel;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                }
              } else {
                setPCA9685(upPwmChannel, 0, pwmMaxLevel);
                pwmOutLevel[upPwmChannel] = pwmMaxLevel;
                upSequense = false;
                Serial.println("PWM_UP_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);;
            }
          }
          if ((downSequence) && (downPwmChannel >= 0)) {
            pwmOutLevel[downPwmChannel] += psos;
            if (pwmOutLevel[downPwmChannel] >= pwmMaxLevel) {
              int downSobras = (pwmOutLevel[downPwmChannel] - pwmMaxLevel) + pwmOutLevel[downPwmChannel - 1];
              pwmOutLevel[downPwmChannel] = pwmMaxLevel;
              if (downPwmChannel > 0) {
                setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                downPwmChannel --;
                if (downSobras <= pwmMaxLevel) {
                  pwmOutLevel[downPwmChannel] = downSobras;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                } else {
                  pwmOutLevel[downPwmChannel] = pwmMaxLevel;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                }
              } else {
                setPCA9685(downPwmChannel, 0, pwmMaxLevel);
                pwmOutLevel[downPwmChannel] = pwmMaxLevel;
                downSequence = false;
                Serial.println("PWM_DOWN_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);;
            }
          }
          if ((!upSequense) && (!downSequence)) {
            pwmSequence = PWM_SEQUENCE_STOP;
            Serial.println("PWM_SEQUENCE_STOP");
          }
        } break;

      case PWM_SEQUENCE_OFF_X_TO_MAX_MIN: {
          if ((upSequense) && (upPwmChannel < numPwmOut)) {
            pwmOutLevel[upPwmChannel] -= psos;
            if (pwmOutLevel[upPwmChannel] <= pwmMinLevel) {
              int upFaltas = (pwmOutLevel[upPwmChannel] - pwmMinLevel) + pwmOutLevel[upPwmChannel + 1];
              pwmOutLevel[upPwmChannel] = pwmMinLevel;
              if (upPwmChannel < (numPwmOut - 1)) {
                setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                upPwmChannel ++;
                if (upFaltas >= pwmMinLevel) {
                  pwmOutLevel[upPwmChannel] = upFaltas;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                } else {
                  pwmOutLevel[upPwmChannel] = pwmMinLevel;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                }
              } else {
                setPCA9685(upPwmChannel, 0, pwmMinLevel);
                pwmOutLevel[upPwmChannel] = pwmMinLevel;
                upSequense = false;
                Serial.println("PWM_UP_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
            }
          }
          if ((downSequence) && (downPwmChannel >= 0)) {
            pwmOutLevel[downPwmChannel] -= psos;
            if (pwmOutLevel[downPwmChannel] <= pwmMinLevel) {
              int downFaltas = (pwmOutLevel[downPwmChannel] - pwmMinLevel) + pwmOutLevel[downPwmChannel - 1];
              pwmOutLevel[downPwmChannel] = pwmMinLevel;
              if (downPwmChannel > 0) {
                setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                downPwmChannel --;
                if (downFaltas >= pwmMinLevel) {
                  pwmOutLevel[downPwmChannel] = downFaltas;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                } else {
                  pwmOutLevel[downPwmChannel] = pwmMinLevel;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                }
              } else {
                setPCA9685(downPwmChannel, 0, pwmMinLevel);
                pwmOutLevel[downPwmChannel] = pwmMinLevel;
                downSequence = false;
                Serial.println("PWM_DOWN_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
            }
          }
          if ((!upSequense) && (!downSequence)) {
            pwmSequence = PWM_SEQUENCE_STOP;
            Serial.println("PWM_SEQUENCE_STOP");
          }
        } break;
    }
  }
}

void tick() {
  int state = digitalRead(LED_PIN);
  digitalWrite(LED_PIN, !state);
}

void botones() {
  buttonA.loop();
  buttonB.loop();
  buttonC.loop();
}

void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

void ondemandwifiCallback () {
  ticker.detach();
  digitalWrite(LED_PIN, statusLedOn);
  tikOn = false;

  WiFiManagerParameter custom_Supla_server("server", "supla server", Supla_server, 81, "required");
  WiFiManagerParameter custom_Email("email", "Email", Email, 81, "required");
  WiFiManagerParameter custom_Supla_name("name", "Supla Device Name", Supla_name, 81, "required");
  WiFiManagerParameter custom_FadeTime("FadeTime", "Fade Time for each Step", FadeTime, 5, "required");
  WiFiManagerParameter custom_NumPwmOut("NumPwmOut", "Number of Step", NumPwmOut, 2, "required");
  WiFiManagerParameter custom_NumCenter("NumCenter", "Center Step", NumCenter, 2, "required");
  WiFiManagerParameter custom_html_id21("<div><h4> - Supla State -   ");
  WiFiManagerParameter custom_html_id22( Supla_status);
  WiFiManagerParameter custom_html_id23( "</h4></div>");

  wifiManager.setBreakAfterConfig(true);
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  wifiManager.addParameter(&custom_Supla_server);
  wifiManager.addParameter(&custom_Email);
  wifiManager.addParameter(&custom_Supla_name);
  wifiManager.addParameter(&custom_FadeTime);
  wifiManager.addParameter(&custom_NumPwmOut);
  wifiManager.addParameter(&custom_NumCenter);
  wifiManager.addParameter(&custom_html_id21);
  wifiManager.addParameter(&custom_html_id22);
  wifiManager.addParameter(&custom_html_id23);

  wifiManager.setCustomHeadElement(logo);
  wifiManager.setMinimumSignalQuality(8);
  wifiManager.setConfigPortalTimeout(300);

  if (!wifiManager.startConfigPortal("SuplaPCA9685")) {
    Serial.println("Not connected to WiFi but continuing anyway.");
  } else {
    Serial.println("connected...yeey :)");
  }
  strcpy(Supla_server, custom_Supla_server.getValue());
  strcpy(Email, custom_Email.getValue());
  strcpy(Supla_name, custom_Supla_name.getValue());
  strcpy(FadeTime, custom_FadeTime.getValue());
  strcpy(NumPwmOut, custom_NumPwmOut.getValue());
  strcpy(NumCenter, custom_NumCenter.getValue());
  wifiManager.getWiFiSSID().toCharArray(Router_SSID, 33);
  wifiManager.getWiFiPass().toCharArray(Router_Pass, 65);
  if (strcmp(Supla_server, "get_new_guid_and_authkey") == 0) {
    Serial.println("new guid & authkey.");
    EEPROM.write(300, 0);
    EEPROM.commit();
    delay(100);
    ESP.reset();
  }
  if (shouldSaveConfig == true) { // ------------------------ wificonfig save --------------
    Serial.println(" config...");
    DynamicJsonDocument json(1024);
    json["Supla_server"] = Supla_server;
    json["Email"] = Email;
    json["Supla_name"] = Supla_name;
    json["FadeTime"] = FadeTime;
    json["NumPwmOut"] = NumPwmOut;
    json["NumCenter"] = NumCenter;
    json["Router_SSID"] = Router_SSID;
    json["Router_Pass"] = Router_Pass;
    File configFile = LittleFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }
    serializeJsonPretty(json, Serial);
    serializeJson(json, configFile);
    configFile.close();
    Serial.println("Config written successfully");
    shouldSaveConfig = false;
    initialConfig = false;
    WiFi.mode(WIFI_STA);
    delay(5000);
    ESP.restart();
  }
  WiFi.softAPdisconnect(true);
  initialConfig = false;
}

void status_func(int status, const char *msg) {
  if (s != status) {
    s = status;
    if (s != 10) {
      strcpy(Supla_status, msg);
    }
  }
}

void guid_authkey(void) {
  if (EEPROM.read(300) != 60) {
    int eep_gui = 301;
    ESP8266TrueRandom.uuid(uuidNumber);
    String uuidString = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString += "0123456789abcdef"[topDigit];
      uuidString += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid = uuidString.length();
    for (int i = 0; i < length_uuid; ++i) {
      EEPROM.put(eep_gui + i, uuidString[i]);
    }
    int eep_aut = 341;
    ESP8266TrueRandom.uuid(uuidNumber);
    String uuidString2 = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString2 += "0123456789abcdef"[topDigit];
      uuidString2 += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid2 = uuidString2.length();
    for (int i = 0; i < length_uuid2; ++i) {
      EEPROM.put(eep_aut + i, uuidString2[i]);
    }
    EEPROM.write(300, 60);
    EEPROM.commit();
    delay(0);
  }
  read_guid();
  read_authkey();
  Serial.print("GUID : "); Serial.println(read_guid());
  Serial.print("AUTHKEY : "); Serial.println(read_authkey());
}

String read_guid(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 301;
  int end_guid = eep_star + SUPLA_GUID_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_guid + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_guid = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      GUID[ii] = strtoul( _guid, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}

String read_authkey(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 341;
  int end_authkey = eep_star + SUPLA_AUTHKEY_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_authkey + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_authkey = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      AUTHKEY[ii] = strtoul( _authkey, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}

void setup() {

  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY, 1);
  delay(10);
  Serial.println(" ");
  Serial.println(" ");
  pinMode(button_0_pin, INPUT_PULLUP);
  pinMode(button_1_pin, INPUT_PULLUP);
  pinMode(button_2_pin, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  ticker.attach(0.5, tick);
  EEPROM.begin(1024);

  if (EEPROM.read(300) != 60) {
    initialConfig = true;
  }

  guid_authkey();

  if (WiFi.SSID() == "") {
    initialConfig = true;
  }
  if (LittleFS.begin()) {  // ------------------------- wificonfig read -----------------
    Serial.println("mounted file system");
    if (LittleFS.exists("/config.json")) {
      Serial.println("reading config file");
      File configFile = LittleFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        std::unique_ptr<char[]> buf(new char[size]);
        configFile.readBytes(buf.get(), size);
        DynamicJsonDocument json(1024);
        DeserializationError deserializeError = deserializeJson(json, buf.get());
        serializeJsonPretty(json, Serial);
        if (!deserializeError) {
          Serial.println("\nparsed json");
          if (json.containsKey("Supla_server")) strcpy(Supla_server, json["Supla_server"]);
          if (json.containsKey("Email")) strcpy(Email, json["Email"]);
          if (json.containsKey("Supla_name")) strcpy(Supla_name, json["Supla_name"]);
          if (json.containsKey("FadeTime")) strcpy(FadeTime, json["FadeTime"]);
          if (json.containsKey("NumPwmOut")) strcpy(NumPwmOut, json["NumPwmOut"]);
          if (json.containsKey("NumCenter")) strcpy(NumCenter, json["NumCenter"]);
          if (json.containsKey("Router_SSID")) strcpy(Router_SSID, json["Router_SSID"]);
          if (json.containsKey("Router_Pass")) strcpy(Router_Pass, json["Router_Pass"]);
          fadeEffect = atoi(FadeTime);
          numPwmOut = atoi(NumPwmOut);
          numCenter = atoi(NumCenter);
          if (numPwmOut < 2) numPwmOut = 2;
          if (numPwmOut > 64) numPwmOut = 64;
          if (numCenter < 1) numCenter = 1;
          if (numCenter > (numPwmOut - 1)) numCenter = (numPwmOut - 1);
        } else {
          Serial.println("failed to load json config");
          initialConfig = true;
        }
        configFile.close();
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  wifi_station_set_hostname(Supla_name);
  WiFi.mode(WIFI_STA);

  Wire.begin(SDA_PIN, SCL_PIN);
  pwm0.begin();
  pwm0.reset();
  pwm0.setOscillatorFrequency(27000000);
  pwm0.setPWMFreq(400);  // This is the PWM frequency
  pwm1.begin();
  pwm1.reset();
  pwm1.setOscillatorFrequency(27000000);
  pwm1.setPWMFreq(400);  // This is the PWM frequency
  pwm2.begin();
  pwm2.reset();
  pwm2.setOscillatorFrequency(27000000);
  pwm2.setPWMFreq(400);  // This is the PWM frequency
  pwm3.begin();
  pwm3.reset();
  pwm3.setOscillatorFrequency(27000000);
  pwm3.setPWMFreq(400);  // This is the PWM frequency
  Wire.setClock(400000);

  auto miDimA = new PwmDimm(0);
  auto miDimB = new PwmDimm(1);
  relay_0 = new Supla::Control::Relay(relay_0_pin, true, 192);
  relay_0->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_0->keepTurnOnDuration();
  relay_0->disableChannelState();
  relay_2 = new Supla::Control::Relay(relay_2_pin, true, 192);
  relay_2->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_2->keepTurnOnDuration();
  relay_2->disableChannelState();
  relay_3 = new Supla::Control::Relay(relay_3_pin, true, 192);
  relay_3->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_3->keepTurnOnDuration();
  relay_3->disableChannelState();
  relay_1 = new Supla::Control::Relay(relay_1_pin, true, 64);
  relay_1->getChannel()->setDefault(SUPLA_CHANNELFNC_LIGHTSWITCH);
  relay_1->setDefaultStateOff();
  relay_1->disableChannelState();

  buttonA.setClickHandler(clickA);
  buttonA.setLongClickHandler(clickA);
  buttonA.setDoubleClickHandler(doubleClickA);
  buttonB.setClickHandler(clickB);
  buttonB.setLongClickHandler(clickB);
  buttonB.setDoubleClickHandler(doubleClickA);
  buttonC.setClickHandler(clickC);
  buttonC.setLongClickHandler(clickC);
  buttonC.setDoubleClickHandler(doubleClickA);

  SuplaDevice.setName(Supla_name);
  SuplaDevice.setStatusFuncImpl(&status_func);
  wifi.enableSSL(false);
  wifi.setSsid(Router_SSID);
  wifi.setPassword(Router_Pass);
  SuplaDevice.begin(GUID, Supla_server, Email, AUTHKEY);

  if (initialConfig == true) {
    ondemandwifiCallback();
  }

  for (uint8_t i = 0; i < numPwmOut; i++) {
    setPCA9685(i, 0, pwmMinLevel);
    pwmOutLevel[currentPwmChannel] = pwmMinLevel;
  }

  tickerB.attach_ms(50, botones);

  setupEnd = true;
}

void loop() {

  int C_W_read = digitalRead(button_0_pin); {
    if (C_W_read != last_C_W_state) {
      time_last_C_W_change = millis();
    }
    if ((millis() - time_last_C_W_change) > C_W_delay) {
      if (C_W_read != C_W_state) {
        C_W_state = C_W_read;
        if (C_W_state == LOW) {
          ondemandwifiCallback () ;
        }
      }
    }
    last_C_W_state = C_W_read;
  }

  SuplaDevice.iterate();

  delay(25);

  if (WiFi.status() == WL_CONNECTED) {
    if (starting) {
      httpUpdater.setup(&httpServer, "/update", "admin", "pass");
      httpServer.begin();
      starting = false;
    }
    httpServer.handleClient();
  }
  if (s == STATUS_REGISTERED_AND_READY) {
    if (tikOn) {
      ticker.detach();
      digitalWrite(LED_PIN, !statusLedOn);
      tikOn = false;
    }
  } else if (!tikOn) {
    ticker.attach(0.5, tick);
    tikOn = true;
  }

  if (setOff) {
    if ((offTriger == 0) || (offTriger == 1)) {
      if ((offTriger == 0) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if (offTriger == 2) {
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if ((offTriger == 3) || (offTriger == 4)) {
      if ((offTriger == 3) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if ((offTriger == 5) || (offTriger == 6)) {
      if ((offTriger == 5) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
    }
    offTriger = -1;
    setOff = false;
  }
  rampa();
}
void clickA(Button3 & btn) {
  Serial.println("Click A");
  relay_0->toggle();
}

void doubleClickA(Button3& btn) {
  Serial.println("longClick A");
  relay_1->toggle();
}

void clickB(Button3 & btn) {
  Serial.println("Click B");
  relay_2->toggle();
}

void clickC(Button3 & btn) {
  Serial.println("Click B");
  relay_3->toggle();
}
Rampa_64_DOUT_16Mbit.rar
compiled firmware
(580.09 KiB) Downloaded 129 times
radzik_r
Posts: 390
Joined: Sun Aug 11, 2019 5:32 pm

Very good job.
I test and recommend the tests to others.
dobo
Posts: 1042
Joined: Sun Apr 07, 2019 8:14 pm
Location: Nadarzyn

Great
I meant something like that.
mirizag
Posts: 121
Joined: Mon Jan 02, 2017 6:36 pm

To connect the led strip, I have to use something else, can it be directly connected to the PCA9685
elmaya
Posts: 1482
Joined: Wed Jun 27, 2018 5:48 pm
Location: El Saucejo - Sevilla

mirizag wrote: Sun Aug 01, 2021 3:16 pm To connect the led strip, I have to use something else, can it be directly connected to the PCA9685
you can't connect directly to the PCA9685.
you have to use a mosfet and a resistor as seen in the image connected to channel 0.
1 mosfet and 1 resistor for each output.
mirizag
Posts: 121
Joined: Mon Jan 02, 2017 6:36 pm

elmaya wrote: Sun Aug 01, 2021 3:20 pm
mirizag wrote: Sun Aug 01, 2021 3:16 pm To connect the led strip, I have to use something else, can it be directly connected to the PCA9685
you can't connect directly to the PCA9685.
you have to use a mosfet and a resistor as seen in the image connected to channel 0.
1 mosfet and 1 resistor for each output.
And what kind of mosfet must it be?
elmaya
Posts: 1482
Joined: Wed Jun 27, 2018 5:48 pm
Location: El Saucejo - Sevilla

mirizag wrote: Sun Aug 01, 2021 3:57 pm
elmaya wrote: Sun Aug 01, 2021 3:20 pm
mirizag wrote: Sun Aug 01, 2021 3:16 pm To connect the led strip, I have to use something else, can it be directly connected to the PCA9685
you can't connect directly to the PCA9685.
you have to use a mosfet and a resistor as seen in the image connected to channel 0.
1 mosfet and 1 resistor for each output.
And what kind of mosfet must it be?
NPN type mosfet for example AOD4184A
elmaya
Posts: 1482
Joined: Wed Jun 27, 2018 5:48 pm
Location: El Saucejo - Sevilla

with half speed when turning off the outputs.

I remind you that it has OTA:

Code: Select all

IP:81/update
user = admin
password = pass
example: 192.168.1.15:81/update

Code: Select all

#define supla_lib_config_h_  // silences debug messages
#include "LittleFS.h"
#include <Wire.h>
#include <WiFiManager.h>
#include <EEPROM.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266TrueRandom.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include <Button3.h>
#include <Ticker.h>
#include <Adafruit_PWMServoDriver.h>
#include <SuplaDevice.h>
#include <supla/control/dimmer_base.h>
#include <supla/control/relay.h>
#include <supla/network/esp_wifi.h>
Supla::ESPWifi wifi("SSID", "PASS");  //------ Do not change----wifimanager takes care------
#define STORAGE_OFFSET 512
#include <supla/storage/eeprom.h>
Supla::Eeprom eeprom(STORAGE_OFFSET);

//#define D0 16  //no internal pullup resistor
//#define D1  5
//#define D2  4
//#define D3  0  //must not be pulled low during power on/reset, toggles value during boot
//#define D4  2  //must not be pulled low during power on/reset, toggles value during boot
//#define D5 14
//#define D6 12
//#define D7 13
//#define D8 15  //must not be pulled high during power on/reset
//#define RX  3  //High at boot
//#define TX  1  //must not be pulled low during power on/reset

#define SCL_PIN 5        //D1
#define SDA_PIN 4        //D2
#define LED_PIN  2       //D4
#define button_0_pin  0  //D3
#define button_1_pin  14 //D5
#define button_2_pin  12 //D6

bool statusLedOn = LOW;

const int PWM_SEQUENCE_STOP       = -1;
const int PWM_SEQUENCE_ON_0_TO_XX  = 1;
const int PWM_SEQUENCE_OFF_XX_TO_0 = 2;
const int PWM_SEQUENCE_ON_ALL      = 3;
const int PWM_SEQUENCE_OFF_ALL     = 4;
const int PWM_SEQUENCE_ON_XX_TO_0  = 5;
const int PWM_SEQUENCE_OFF_0_TO_XX = 6;
const int PWM_SEQUENCE_ON_X_TO_MAX_MIN = 7;
const int PWM_SEQUENCE_OFF_X_TO_MAX_MIN = 8;
int pwmSequence = PWM_SEQUENCE_STOP;
int pwmOutLevel[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int pwmMaxLevel = 4095;
int pwmMinLevel = 0;
int numPwmOut = 16;
int numCenter = 8;
int fadeEffect = 500;
int runFadeEffect = fadeEffect;
int currentPwmChannel = 0;
int upPwmChannel = numCenter;
int downPwmChannel = numCenter;
bool upSequense = false;
bool downSequence = false;
bool setupEnd = false;
const int  relay_0_pin = 200;
const int  relay_1_pin = 201;
const int  relay_2_pin = 202;
const int  relay_3_pin = 203;
bool relay_0_state = false;
bool relay_1_state = false;
bool relay_2_state = false;
bool relay_3_state = false;
bool setOff = false;
int offTriger = -1;
unsigned long ultimaPasada;
int C_W_state = HIGH;
int last_C_W_state = HIGH;
unsigned long time_last_C_W_change = 0;
long C_W_delay = 10000;               // ---------------------- config delay 10 seconds ---------------------------
char Supla_server[81] = ("Set server address");
char Email[81] = ("set email address");
char Supla_name[81] = ("SuplaPCA9685");
char FadeTime[8] = ("500");
char NumPwmOut[3] = ("16");
char NumCenter[3] = ("8");
char Router_SSID[32];
char Router_Pass[64];
char Supla_status[51];
bool shouldSaveConfig = false;
bool initialConfig = false;
bool starting = true;
bool tikOn = true;
int s;
char GUID[SUPLA_GUID_SIZE];
char AUTHKEY[SUPLA_AUTHKEY_SIZE];
byte uuidNumber[16];
static const char logo[] PROGMEM = "<style>html{ background-color: #01DF3A;}</style><div class='s'><svg version='1.1' id='l' x='0' y='0' viewBox='0 0 200 200' xml:space='preserve'><path d='M59.3,2.5c18.1,0.6,31.8,8,40.2,23.5c3.1,5.7,4.3,11.9,4.1,18.3c-0.1,3.6-0.7,7.1-1.9,10.6c-0.2,0.7-0.1,1.1,0.6,1.5c12.8,7.7,25.5,15.4,38.3,23c2.9,1.7,5.8,3.4,8.7,5.3c1,0.6,1.6,0.6,2.5-0.1c4.5-3.6,9.8-5.3,15.7-5.4c12.5-0.1,22.9,7.9,25.2,19c1.9,9.2-2.9,19.2-11.8,23.9c-8.4,4.5-16.9,4.5-25.5,0.2c-0.7-0.3-1-0.2-1.5,0.3c-4.8,4.9-9.7,9.8-14.5,14.6c-5.3,5.3-10.6,10.7-15.9,16c-1.8,1.8-3.6,3.7-5.4,5.4c-0.7,0.6-0.6,1,0,1.6c3.6,3.4,5.8,7.5,6.2,12.2c0.7,7.7-2.2,14-8.8,18.5c-12.3,8.6-30.3,3.5-35-10.4c-2.8-8.4,0.6-17.7,8.6-22.8c0.9-0.6,1.1-1,0.8-2c-2-6.2-4.4-12.4-6.6-18.6c-6.3-17.6-12.7-35.1-19-52.7c-0.2-0.7-0.5-1-1.4-0.9c-12.5,0.7-23.6-2.6-33-10.4c-8-6.6-12.9-15-14.2-25c-1.5-11.5,1.7-21.9,9.6-30.7C32.5,8.9,42.2,4.2,53.7,2.7c0.7-0.1,1.5-0.2,2.2-0.2C57,2.4,58.2,2.5,59.3,2.5z M76.5,81c0,0.1,0.1,0.3,0.1,0.6c1.6,6.3,3.2,12.6,4.7,18.9c4.5,17.7,8.9,35.5,13.3,53.2c0.2,0.9,0.6,1.1,1.6,0.9c5.4-1.2,10.7-0.8,15.7,1.6c0.8,0.4,1.2,0.3,1.7-0.4c11.2-12.9,22.5-25.7,33.4-38.7c0.5-0.6,0.4-1,0-1.6c-5.6-7.9-6.1-16.1-1.3-24.5c0.5-0.8,0.3-1.1-0.5-1.6c-9.1-4.7-18.1-9.3-27.2-14c-6.8-3.5-13.5-7-20.3-10.5c-0.7-0.4-1.1-0.3-1.6,0.4c-1.3,1.8-2.7,3.5-4.3,5.1c-4.2,4.2-9.1,7.4-14.7,9.7C76.9,80.3,76.4,80.3,76.5,81z M89,42.6c0.1-2.5-0.4-5.4-1.5-8.1C83,23.1,74.2,16.9,61.7,15.8c-10-0.9-18.6,2.4-25.3,9.7c-8.4,9-9.3,22.4-2.2,32.4c6.8,9.6,19.1,14.2,31.4,11.9C79.2,67.1,89,55.9,89,42.6z M102.1,188.6c0.6,0.1,1.5-0.1,2.4-0.2c9.5-1.4,15.3-10.9,11.6-19.2c-2.6-5.9-9.4-9.6-16.8-8.6c-8.3,1.2-14.1,8.9-12.4,16.6C88.2,183.9,94.4,188.6,102.1,188.6z M167.7,88.5c-1,0-2.1,0.1-3.1,0.3c-9,1.7-14.2,10.6-10.8,18.6c2.9,6.8,11.4,10.3,19,7.8c7.1-2.3,11.1-9.1,9.6-15.9C180.9,93,174.8,88.5,167.7,88.5z'/></svg>";

ESP8266WebServer httpServer(81);
ESP8266HTTPUpdateServer httpUpdater;
WiFiManager wifiManager;
Ticker ticker;
Ticker tickerB;
Adafruit_PWMServoDriver pwm0 = Adafruit_PWMServoDriver(0x40);
Adafruit_PWMServoDriver pwm1 = Adafruit_PWMServoDriver(0x41);
Adafruit_PWMServoDriver pwm2 = Adafruit_PWMServoDriver(0x42);
Adafruit_PWMServoDriver pwm3 = Adafruit_PWMServoDriver(0x43);
Button3 buttonA = Button3(button_0_pin);
Button3 buttonB = Button3(button_1_pin);
Button3 buttonC = Button3(button_2_pin);

Supla::Control::Relay *relay_0 = nullptr;
Supla::Control::Relay *relay_1 = nullptr;
Supla::Control::Relay *relay_2 = nullptr;
Supla::Control::Relay *relay_3 = nullptr;

void setPCA9685(uint8_t num, uint16_t on, uint16_t off) {

  if ( num < 16) {
    pwm0.setPWM(num, on, off);      // PCA-0 from 0 to 15
  } else if (( num > 15 ) && (num < 32)) {
    pwm1.setPWM(num - 16, on, off); // PCA-1 from 16 to 31
  } else if (( num > 31 ) && (num < 48)) {
    pwm2.setPWM(num - 32, on, off); // PCA-2 from 32 to 47
  } else if (( num > 47 ) && (num < 64)) {
    pwm3.setPWM(num - 48, on, off); // PCA-3 from 48 to 63
  }
}

class PwmDimm : public Supla::Control::DimmerBase {
  public:
    PwmDimm(int pwmChannel)
      : pwmChannel(pwmChannel) {
    }
    void setRGBWValueOnDevice(uint32_t red,
                              uint32_t green,
                              uint32_t blue,
                              uint32_t colorBrightness,
                              uint32_t brightness) {

      uint32_t brightnessAdj = brightness;

      if ( pwmChannel == 0) {
        brightnessAdj = map(brightnessAdj, 0, 1023, 2047, 4095);
        for (uint8_t i = 0; i < numPwmOut; i++) {
          if (pwmOutLevel[i] >= pwmMaxLevel) {
            setPCA9685(i, 0, brightnessAdj);
            pwmOutLevel[i] = brightnessAdj;
          }
        }
        pwmMaxLevel = brightnessAdj;
      }
      else if ( pwmChannel == 1) {
        brightnessAdj = map(brightnessAdj, 0, 1023, 0, 2047);
        for (uint8_t i = 0; i < numPwmOut; i++) {
          if (pwmOutLevel[i] <= pwmMinLevel) {
            setPCA9685(i, 0, brightnessAdj);
            pwmOutLevel[i] = brightnessAdj;
          }
        }
        pwmMinLevel = brightnessAdj;
      }
    }
  protected:
    int pwmChannel;
};
class CustomControl : public Supla::Io {
  public:
    void customDigitalWrite(int channelNumber, uint8_t pin, uint8_t val) {

      if ((pin == relay_0_pin) && (setupEnd)) {
        if (val == 1) {
          relay_0_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 0;
          }
          currentPwmChannel = 0;
          runFadeEffect = fadeEffect;
          pwmSequence = PWM_SEQUENCE_ON_0_TO_XX;
          Serial.println("ON Min to Max");
        }
        else if ((val == 0) && (setupEnd)) {
          relay_0_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 1;
            currentPwmChannel = 0;
            runFadeEffect = fadeEffect * 2;
            pwmSequence = PWM_SEQUENCE_OFF_0_TO_XX;
            Serial.println("OFF Min to Max");
          }
        }
      }
      else if ((pin == relay_1_pin) && (setupEnd)) {
        if (val == 1) {
          relay_1_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 2;
          }
          runFadeEffect = fadeEffect;
          pwmSequence = PWM_SEQUENCE_ON_ALL;
          Serial.println("On All");
        }
        if (val == 0) {
          relay_1_state = false;
          if (setOff == false) {
            setOff = true;
            offTriger = 2;
            runFadeEffect = fadeEffect * 2;
            pwmSequence = PWM_SEQUENCE_OFF_ALL;
            Serial.println("Off All");
          }
        }
      }
      else if ((pin == relay_2_pin) && (setupEnd)) {
        if (val == 1) {
          relay_2_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 3;
          }
          currentPwmChannel = numPwmOut - 1;
          runFadeEffect = fadeEffect;
          pwmSequence = PWM_SEQUENCE_ON_XX_TO_0;
          Serial.println("ON Max to Min");
        }
        if (val == 0) {
          relay_2_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 4;
            currentPwmChannel = numPwmOut - 1;
            runFadeEffect = fadeEffect * 2;
            pwmSequence = PWM_SEQUENCE_OFF_XX_TO_0;
            Serial.println("OFF Max to Min");
          }
        }
      }
      else if ((pin == relay_3_pin) && (setupEnd)) {
        if (val == 1) {
          relay_3_state = true;
          if (setOff == false) {
            setOff = true;
            offTriger = 5;
          }
          upSequense = true;
          downSequence = true;
          upPwmChannel = numCenter;
          downPwmChannel = (numCenter - 1);
          runFadeEffect = fadeEffect;
          pwmSequence = PWM_SEQUENCE_ON_X_TO_MAX_MIN;
          Serial.println("ON Center to MaxMin");
        }
        if (val == 0) {
          relay_3_state = false;
          if (relay_1->isOn())return;
          if (setOff == false) {
            setOff = true;
            offTriger = 6;
            upSequense = true;
            downSequence = true;
            upPwmChannel = numCenter;
            downPwmChannel = (numCenter - 1);
            runFadeEffect = fadeEffect * 2;
            pwmSequence = PWM_SEQUENCE_OFF_X_TO_MAX_MIN;
            Serial.println("OFF Center to MaxMin");
          }
        }
      }
      else {
        return ::digitalWrite(pin, val);
      }
    }

    int customDigitalRead(int channelNumber, uint8_t pin) {
      if (pin == relay_0_pin) {
        return relay_0_state;
      } else if (pin == relay_1_pin) {
        return relay_1_state;
      } else if (pin == relay_2_pin) {
        return relay_2_state;
      } else if (pin == relay_3_pin) {
        return relay_3_state;
      } else {
        return ::digitalRead(pin);
      }
    }
} CustomControl;

void rampa() {
  unsigned long timePast = millis() - ultimaPasada;
  ultimaPasada = millis();
  if (timePast > 0) {
    double divisor = 1.0 * runFadeEffect / timePast;
    if (divisor <= 0) {
      divisor = 1;
    }
    int psos = pwmMaxLevel / divisor;
    if (psos < 1) {
      psos = 1;
    }

    switch (pwmSequence) {

      case PWM_SEQUENCE_STOP: break;

      case PWM_SEQUENCE_ON_0_TO_XX: {
          pwmOutLevel[currentPwmChannel] += psos;
          if (pwmOutLevel[currentPwmChannel] >= pwmMaxLevel) {
            int sobras = (pwmOutLevel[currentPwmChannel] - pwmMaxLevel) + pwmOutLevel[currentPwmChannel + 1];
            pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
            if (currentPwmChannel < (numPwmOut - 1)) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel ++;
              if (sobras <= pwmMaxLevel) {
                pwmOutLevel[currentPwmChannel] = sobras;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMaxLevel);
              pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);;
          }
        } break;

      case PWM_SEQUENCE_OFF_XX_TO_0: {
          pwmOutLevel[currentPwmChannel] -= psos;
          if (pwmOutLevel[currentPwmChannel] <= pwmMinLevel) {
            int faltas = (pwmOutLevel[currentPwmChannel] - pwmMinLevel) + pwmOutLevel[currentPwmChannel - 1];
            pwmOutLevel[currentPwmChannel] = pwmMinLevel;
            if (currentPwmChannel > 0) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel --;
              if (faltas >= pwmMinLevel) {
                pwmOutLevel[currentPwmChannel] = faltas;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMinLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMinLevel);
              pwmOutLevel[currentPwmChannel] = pwmMinLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_ON_ALL: {
          for (uint8_t i = 0; i < numPwmOut; i++) {
            pwmOutLevel[i] += psos;
            if (pwmOutLevel[i] >= pwmMaxLevel) {
              pwmOutLevel[i] = pwmMaxLevel;
              setPCA9685(i, 0, pwmOutLevel[i]);
              if (i >= (numPwmOut - 1)) {
                pwmSequence = PWM_SEQUENCE_STOP;
                Serial.println("PWM_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(i, 0, pwmOutLevel[i]);
            }
          }
        } break;

      case PWM_SEQUENCE_OFF_ALL: {
          for (uint8_t i = 0; i < numPwmOut; i++) {
            pwmOutLevel[i] -= psos;
            if (pwmOutLevel[i] <= pwmMinLevel) {
              pwmOutLevel[i] = pwmMinLevel;
              setPCA9685(i, 0, pwmOutLevel[i]);
              if (i >= (numPwmOut - 1)) {
                pwmSequence = PWM_SEQUENCE_STOP;
                Serial.println("PWM_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(i, 0, pwmOutLevel[i]);
            }
          }
        } break;

      case PWM_SEQUENCE_ON_XX_TO_0: {
          pwmOutLevel[currentPwmChannel] += psos;
          if (pwmOutLevel[currentPwmChannel] >= pwmMaxLevel) {
            int sobras = (pwmOutLevel[currentPwmChannel] - pwmMaxLevel) + pwmOutLevel[currentPwmChannel - 1];
            pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
            if (currentPwmChannel > 0) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel --;
              if (sobras <= pwmMaxLevel) {
                pwmOutLevel[currentPwmChannel] = sobras;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMaxLevel);
              pwmOutLevel[currentPwmChannel] = pwmMaxLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_OFF_0_TO_XX: {
          pwmOutLevel[currentPwmChannel] -= psos;
          if (pwmOutLevel[currentPwmChannel] <= pwmMinLevel) {
            int faltas = (pwmOutLevel[currentPwmChannel] - pwmMinLevel) + pwmOutLevel[currentPwmChannel + 1];
            pwmOutLevel[currentPwmChannel] = pwmMinLevel;
            if (currentPwmChannel < (numPwmOut - 1)) {
              setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              currentPwmChannel ++;
              if (faltas >= pwmMinLevel) {
                pwmOutLevel[currentPwmChannel] = faltas;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              } else {
                pwmOutLevel[currentPwmChannel] = pwmMinLevel;
                setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
              }
            } else {
              setPCA9685(currentPwmChannel, 0, pwmMinLevel);
              pwmOutLevel[currentPwmChannel] = pwmMinLevel;
              pwmSequence = PWM_SEQUENCE_STOP;
              Serial.println("PWM_SEQUENCE_STOP");
            }
          } else {
            setPCA9685(currentPwmChannel, 0, pwmOutLevel[currentPwmChannel]);
          }
        } break;

      case PWM_SEQUENCE_ON_X_TO_MAX_MIN: {
          if ((upSequense) && (upPwmChannel < numPwmOut)) {
            pwmOutLevel[upPwmChannel] += psos;
            if (pwmOutLevel[upPwmChannel] >= pwmMaxLevel) {
              int upSobras = (pwmOutLevel[upPwmChannel] - pwmMaxLevel) + pwmOutLevel[upPwmChannel + 1];
              pwmOutLevel[upPwmChannel] = pwmMaxLevel;
              if (upPwmChannel < (numPwmOut - 1)) {
                setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                upPwmChannel ++;
                if (upSobras <= pwmMaxLevel) {
                  pwmOutLevel[upPwmChannel] = upSobras;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                } else {
                  pwmOutLevel[upPwmChannel] = pwmMaxLevel;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                }
              } else {
                setPCA9685(upPwmChannel, 0, pwmMaxLevel);
                pwmOutLevel[upPwmChannel] = pwmMaxLevel;
                upSequense = false;
                Serial.println("PWM_UP_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);;
            }
          }
          if ((downSequence) && (downPwmChannel >= 0)) {
            pwmOutLevel[downPwmChannel] += psos;
            if (pwmOutLevel[downPwmChannel] >= pwmMaxLevel) {
              int downSobras = (pwmOutLevel[downPwmChannel] - pwmMaxLevel) + pwmOutLevel[downPwmChannel - 1];
              pwmOutLevel[downPwmChannel] = pwmMaxLevel;
              if (downPwmChannel > 0) {
                setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                downPwmChannel --;
                if (downSobras <= pwmMaxLevel) {
                  pwmOutLevel[downPwmChannel] = downSobras;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                } else {
                  pwmOutLevel[downPwmChannel] = pwmMaxLevel;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                }
              } else {
                setPCA9685(downPwmChannel, 0, pwmMaxLevel);
                pwmOutLevel[downPwmChannel] = pwmMaxLevel;
                downSequence = false;
                Serial.println("PWM_DOWN_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);;
            }
          }
          if ((!upSequense) && (!downSequence)) {
            pwmSequence = PWM_SEQUENCE_STOP;
            Serial.println("PWM_SEQUENCE_STOP");
          }
        } break;

      case PWM_SEQUENCE_OFF_X_TO_MAX_MIN: {
          if ((upSequense) && (upPwmChannel < numPwmOut)) {
            pwmOutLevel[upPwmChannel] -= psos;
            if (pwmOutLevel[upPwmChannel] <= pwmMinLevel) {
              int upFaltas = (pwmOutLevel[upPwmChannel] - pwmMinLevel) + pwmOutLevel[upPwmChannel + 1];
              pwmOutLevel[upPwmChannel] = pwmMinLevel;
              if (upPwmChannel < (numPwmOut - 1)) {
                setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                upPwmChannel ++;
                if (upFaltas >= pwmMinLevel) {
                  pwmOutLevel[upPwmChannel] = upFaltas;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                } else {
                  pwmOutLevel[upPwmChannel] = pwmMinLevel;
                  setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
                }
              } else {
                setPCA9685(upPwmChannel, 0, pwmMinLevel);
                pwmOutLevel[upPwmChannel] = pwmMinLevel;
                upSequense = false;
                Serial.println("PWM_UP_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(upPwmChannel, 0, pwmOutLevel[upPwmChannel]);
            }
          }
          if ((downSequence) && (downPwmChannel >= 0)) {
            pwmOutLevel[downPwmChannel] -= psos;
            if (pwmOutLevel[downPwmChannel] <= pwmMinLevel) {
              int downFaltas = (pwmOutLevel[downPwmChannel] - pwmMinLevel) + pwmOutLevel[downPwmChannel - 1];
              pwmOutLevel[downPwmChannel] = pwmMinLevel;
              if (downPwmChannel > 0) {
                setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                downPwmChannel --;
                if (downFaltas >= pwmMinLevel) {
                  pwmOutLevel[downPwmChannel] = downFaltas;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                } else {
                  pwmOutLevel[downPwmChannel] = pwmMinLevel;
                  setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]);
                }
              } else {
                setPCA9685(downPwmChannel, 0, pwmMinLevel);
                pwmOutLevel[downPwmChannel] = pwmMinLevel;
                downSequence = false;
                Serial.println("PWM_DOWN_SEQUENCE_STOP");
              }
            } else {
              setPCA9685(downPwmChannel, 0, pwmOutLevel[downPwmChannel]); // ----- here was the bug -----
            }
          }
          if ((!upSequense) && (!downSequence)) {
            pwmSequence = PWM_SEQUENCE_STOP;
            Serial.println("PWM_SEQUENCE_STOP");
          }
        } break;
    }
  }
}

void tick() {
  int state = digitalRead(LED_PIN);
  digitalWrite(LED_PIN, !state);
}

void botones() {
  buttonA.loop();
  buttonB.loop();
  buttonC.loop();
}

void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

void ondemandwifiCallback () {
  ticker.detach();
  digitalWrite(LED_PIN, statusLedOn);
  tikOn = false;

  WiFiManagerParameter custom_Supla_server("server", "supla server", Supla_server, 81, "required");
  WiFiManagerParameter custom_Email("email", "Email", Email, 81, "required");
  WiFiManagerParameter custom_Supla_name("name", "Supla Device Name", Supla_name, 81, "required");
  WiFiManagerParameter custom_FadeTime("FadeTime", "Fade Time for each Step", FadeTime, 5, "required");
  WiFiManagerParameter custom_NumPwmOut("NumPwmOut", "Number of Step", NumPwmOut, 2, "required");
  WiFiManagerParameter custom_NumCenter("NumCenter", "Center Step", NumCenter, 2, "required");
  WiFiManagerParameter custom_html_id21("<div><h4> - Supla State -   ");
  WiFiManagerParameter custom_html_id22( Supla_status);
  WiFiManagerParameter custom_html_id23( "</h4></div>");

  wifiManager.setBreakAfterConfig(true);
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  wifiManager.addParameter(&custom_Supla_server);
  wifiManager.addParameter(&custom_Email);
  wifiManager.addParameter(&custom_Supla_name);
  wifiManager.addParameter(&custom_FadeTime);
  wifiManager.addParameter(&custom_NumPwmOut);
  wifiManager.addParameter(&custom_NumCenter);
  wifiManager.addParameter(&custom_html_id21);
  wifiManager.addParameter(&custom_html_id22);
  wifiManager.addParameter(&custom_html_id23);

  wifiManager.setCustomHeadElement(logo);
  wifiManager.setMinimumSignalQuality(8);
  wifiManager.setConfigPortalTimeout(300);

  if (!wifiManager.startConfigPortal("SuplaPCA9685")) {
    Serial.println("Not connected to WiFi but continuing anyway.");
  } else {
    Serial.println("connected...yeey :)");
  }
  strcpy(Supla_server, custom_Supla_server.getValue());
  strcpy(Email, custom_Email.getValue());
  strcpy(Supla_name, custom_Supla_name.getValue());
  strcpy(FadeTime, custom_FadeTime.getValue());
  strcpy(NumPwmOut, custom_NumPwmOut.getValue());
  strcpy(NumCenter, custom_NumCenter.getValue());
  wifiManager.getWiFiSSID().toCharArray(Router_SSID, 33);
  wifiManager.getWiFiPass().toCharArray(Router_Pass, 65);
  if (strcmp(Supla_server, "get_new_guid_and_authkey") == 0) {
    Serial.println("new guid & authkey.");
    EEPROM.write(300, 0);
    EEPROM.commit();
    delay(100);
    ESP.reset();
  }
  if (shouldSaveConfig == true) {
    Serial.println(" config...");
    DynamicJsonDocument json(1024);
    json["Supla_server"] = Supla_server;
    json["Email"] = Email;
    json["Supla_name"] = Supla_name;
    json["FadeTime"] = FadeTime;
    json["NumPwmOut"] = NumPwmOut;
    json["NumCenter"] = NumCenter;
    json["Router_SSID"] = Router_SSID;
    json["Router_Pass"] = Router_Pass;
    File configFile = LittleFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }
    serializeJsonPretty(json, Serial);
    serializeJson(json, configFile);
    configFile.close();
    Serial.println("Config written successfully");
    shouldSaveConfig = false;
    initialConfig = false;
    WiFi.mode(WIFI_STA);
    delay(5000);
    ESP.restart();
  }
  WiFi.softAPdisconnect(true);
  initialConfig = false;
}

void status_func(int status, const char *msg) {
  if (s != status) {
    s = status;
    if (s != 10) {
      strcpy(Supla_status, msg);
    }
  }
}

void guid_authkey(void) {
  if (EEPROM.read(300) != 60) {
    int eep_gui = 301;
    ESP8266TrueRandom.uuid(uuidNumber);
    String uuidString = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString += "0123456789abcdef"[topDigit];
      uuidString += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid = uuidString.length();
    for (int i = 0; i < length_uuid; ++i) {
      EEPROM.put(eep_gui + i, uuidString[i]);
    }
    int eep_aut = 341;
    ESP8266TrueRandom.uuid(uuidNumber);
    String uuidString2 = "";
    for (int i = 0; i < 16; i++) {
      int topDigit = uuidNumber[i] >> 4;
      int bottomDigit = uuidNumber[i] & 0x0f;
      uuidString2 += "0123456789abcdef"[topDigit];
      uuidString2 += "0123456789abcdef"[bottomDigit];
    }
    int length_uuid2 = uuidString2.length();
    for (int i = 0; i < length_uuid2; ++i) {
      EEPROM.put(eep_aut + i, uuidString2[i]);
    }
    EEPROM.write(300, 60);
    EEPROM.commit();
    delay(0);
  }
  read_guid();
  read_authkey();
  Serial.print("GUID : "); Serial.println(read_guid());
  Serial.print("AUTHKEY : "); Serial.println(read_authkey());
}

String read_guid(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 301;
  int end_guid = eep_star + SUPLA_GUID_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_guid + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_guid = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      GUID[ii] = strtoul( _guid, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}

String read_authkey(void) {
  String read_eeprom = "";
  int i, ii = 0;
  int eep_star = 341;
  int end_authkey = eep_star + SUPLA_AUTHKEY_SIZE;
  String temp_read = "0x";
  for (i = eep_star; i < end_authkey + 16;  i = i + 1) {
    temp_read += char(EEPROM.read(i));
    read_eeprom += char(EEPROM.read(i));
    if ( (i % 2) == 0) {
      char *_authkey = strcpy((char*)malloc(temp_read.length() + 1), temp_read.c_str());
      AUTHKEY[ii] = strtoul( _authkey, NULL, 16);
      temp_read = "0x";
      ii++;
    }
  }
  return read_eeprom;
}

void setup() {

  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY, 1);
  delay(10);
  Serial.println(" ");
  Serial.println(" ");
  pinMode(button_0_pin, INPUT_PULLUP);
  pinMode(button_1_pin, INPUT_PULLUP);
  pinMode(button_2_pin, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  ticker.attach(0.5, tick);
  EEPROM.begin(1024);

  if (EEPROM.read(300) != 60) {
    initialConfig = true;
  }

  guid_authkey();

  if (WiFi.SSID() == "") {
    initialConfig = true;
  }
  if (LittleFS.begin()) {
    Serial.println("mounted file system");
    if (LittleFS.exists("/config.json")) {
      Serial.println("reading config file");
      File configFile = LittleFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        std::unique_ptr<char[]> buf(new char[size]);
        configFile.readBytes(buf.get(), size);
        DynamicJsonDocument json(1024);
        DeserializationError deserializeError = deserializeJson(json, buf.get());
        serializeJsonPretty(json, Serial);
        if (!deserializeError) {
          Serial.println("\nparsed json");
          if (json.containsKey("Supla_server")) strcpy(Supla_server, json["Supla_server"]);
          if (json.containsKey("Email")) strcpy(Email, json["Email"]);
          if (json.containsKey("Supla_name")) strcpy(Supla_name, json["Supla_name"]);
          if (json.containsKey("FadeTime")) strcpy(FadeTime, json["FadeTime"]);
          if (json.containsKey("NumPwmOut")) strcpy(NumPwmOut, json["NumPwmOut"]);
          if (json.containsKey("NumCenter")) strcpy(NumCenter, json["NumCenter"]);
          if (json.containsKey("Router_SSID")) strcpy(Router_SSID, json["Router_SSID"]);
          if (json.containsKey("Router_Pass")) strcpy(Router_Pass, json["Router_Pass"]);
          fadeEffect = atoi(FadeTime);
          numPwmOut = atoi(NumPwmOut);
          numCenter = atoi(NumCenter);
          if (numPwmOut < 2) numPwmOut = 2;
          if (numPwmOut > 64) numPwmOut = 64;
          if (numCenter < 1) numCenter = 1;
          if (numCenter > (numPwmOut - 1)) numCenter = (numPwmOut - 1);
        } else {
          Serial.println("failed to load json config");
          initialConfig = true;
        }
        configFile.close();
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  wifi_station_set_hostname(Supla_name);
  WiFi.mode(WIFI_STA);

  Wire.begin(SDA_PIN, SCL_PIN);
  pwm0.begin();
  pwm0.reset();
  pwm0.setOscillatorFrequency(27000000);
  pwm0.setPWMFreq(400);  // This is the PWM frequency
  pwm1.begin();
  pwm1.reset();
  pwm1.setOscillatorFrequency(27000000);
  pwm1.setPWMFreq(400);  // This is the PWM frequency
  pwm2.begin();
  pwm2.reset();
  pwm2.setOscillatorFrequency(27000000);
  pwm2.setPWMFreq(400);  // This is the PWM frequency
  pwm3.begin();
  pwm3.reset();
  pwm3.setOscillatorFrequency(27000000);
  pwm3.setPWMFreq(400);  // This is the PWM frequency
  Wire.setClock(400000);

  auto miDimA = new PwmDimm(0);
  auto miDimB = new PwmDimm(1);
  relay_0 = new Supla::Control::Relay(relay_0_pin, true, 192);
  relay_0->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_0->keepTurnOnDuration();
  relay_0->disableChannelState();
  relay_2 = new Supla::Control::Relay(relay_2_pin, true, 192);
  relay_2->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_2->keepTurnOnDuration();
  relay_2->disableChannelState();
  relay_3 = new Supla::Control::Relay(relay_3_pin, true, 192);
  relay_3->getChannel()->setDefault(SUPLA_CHANNELFNC_STAIRCASETIMER);
  relay_3->keepTurnOnDuration();
  relay_3->disableChannelState();
  relay_1 = new Supla::Control::Relay(relay_1_pin, true, 64);
  relay_1->getChannel()->setDefault(SUPLA_CHANNELFNC_LIGHTSWITCH);
  relay_1->setDefaultStateOff();
  relay_1->disableChannelState();

  buttonA.setClickHandler(clickA);
  buttonA.setLongClickHandler(clickA);
  buttonA.setDoubleClickHandler(doubleClickA);
  buttonB.setClickHandler(clickB);
  buttonB.setLongClickHandler(clickB);
  buttonB.setDoubleClickHandler(doubleClickA);
  buttonC.setClickHandler(clickC);
  buttonC.setLongClickHandler(clickC);
  buttonC.setDoubleClickHandler(doubleClickA);

  SuplaDevice.setName(Supla_name);
  SuplaDevice.setStatusFuncImpl(&status_func);
  wifi.enableSSL(false);
  wifi.setSsid(Router_SSID);
  wifi.setPassword(Router_Pass);
  SuplaDevice.begin(GUID, Supla_server, Email, AUTHKEY);

  if (initialConfig == true) {
    ondemandwifiCallback();
  }

  for (uint8_t i = 0; i < numPwmOut; i++) {
    setPCA9685(i, 0, pwmMinLevel);
    pwmOutLevel[currentPwmChannel] = pwmMinLevel;
  }

  tickerB.attach_ms(50, botones);

  setupEnd = true;
}

void loop() {

  int C_W_read = digitalRead(button_0_pin); {
    if (C_W_read != last_C_W_state) {
      time_last_C_W_change = millis();
    }
    if ((millis() - time_last_C_W_change) > C_W_delay) {
      if (C_W_read != C_W_state) {
        C_W_state = C_W_read;
        if (C_W_state == LOW) {
          ondemandwifiCallback () ;
        }
      }
    }
    last_C_W_state = C_W_read;
  }

  SuplaDevice.iterate();

  delay(25);

  if (WiFi.status() == WL_CONNECTED) {
    if (starting) {
      httpUpdater.setup(&httpServer, "/update", "admin", "pass");
      httpServer.begin();
      starting = false;
    }
    httpServer.handleClient();
  }
  if (s == STATUS_REGISTERED_AND_READY) {
    if (tikOn) {
      ticker.detach();
      digitalWrite(LED_PIN, !statusLedOn);
      tikOn = false;
    }
  } else if (!tikOn) {
    ticker.attach(0.5, tick);
    tikOn = true;
  }

  if (setOff) {
    if ((offTriger == 0) || (offTriger == 1)) {
      if ((offTriger == 0) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if (offTriger == 2) {
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if ((offTriger == 3) || (offTriger == 4)) {
      if ((offTriger == 3) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_3->isOn())relay_3->turnOff();
    }
    else if ((offTriger == 5) || (offTriger == 6)) {
      if ((offTriger == 5) && (relay_1->isOn()))relay_1->turnOff();
      if (relay_0->isOn())relay_0->turnOff();
      if (relay_2->isOn())relay_2->turnOff();
    }
    offTriger = -1;
    setOff = false;
  }
  rampa();
}
void clickA(Button3 & btn) {
  Serial.println("Click A");
  relay_0->toggle();
}

void doubleClickA(Button3& btn) {
  Serial.println("longClick A");
  relay_1->toggle();
}

void clickB(Button3 & btn) {
  Serial.println("Click B");
  relay_2->toggle();
}

void clickC(Button3 & btn) {
  Serial.println("Click B");
  relay_3->toggle();
}
Rampa_DOUT_16Mbit.rar
compiled firmware
(359.72 KiB) Downloaded 124 times
Post Reply

Return to “Ideas and concepts”