SKETCH : Single Button Push Dimmer (PWM MOSFET OUPUT)

Hi , i just created some sketch for single push button dimming .
(and communication with my homeautomation setup)
As i was not able to find anything good already made .

The sketch is intended to use with an arduino Mega but can be easily modified if you have knowledge.

It is a stripped down version from what i really use in my home but it must work .
(i have UDP connectivity and some other feature in my skecth )

The electrical part is up to you , there is many tutorial on the internet to wire a MOSFET.

Dont hesitate to ask question or propose any correction .

Have a nice day

// by TfouTfou for Arduino Forum , beta version 1.00

// preferably use with arduino MEGA

// Pin 22 to 34 used as Input 
// Each Input control this list of PWM ouput in the same order
// 2  3  5  6  7  8  9  11  12  44  45  46


// CHANGE THIS TO SET FADE TIME FROM OFF TO FULL
// PwmFadeTime X 255 = total time
// so 3922 X 255 = 1000110 microsecond = 1 second
unsigned long PwmFadeTime = 3922;

// CHANGE THIS TO CHANGE THE BUTTON PRESS TIME FOR DIMMING
// FROM OFF TO FULL = DimButtonLoopValue X 255 = 4.33 seconds
byte DimButtonLoopValue = 17; // value in Milliseconds


byte count;
// list of PWM pins on arduino MEGA
byte PwmPins[12] = { 2, 3, 5, 6, 7, 8, 9, 11, 12, 44, 45, 46};
byte VirtualInput[12] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
byte TriggerVirtualInput[12];
byte DimCounter[12];
byte PwmStatusUpdateTrigger[12];
bool DimDirection[12] = {true, true, true, true, true, true, true, true, true, true, true, true};
short PwmSetValue[12];
short PwmFadeValue[12];
unsigned long DimButtonLoop[12];
unsigned long TimerStartVirtualInput[12];
unsigned long TimerEndVirtualInput[12];
unsigned long ResultVirtualInput[12];
unsigned long TimerDimCounter[12];
unsigned long PwmStatusUpdateTimer[12];
unsigned long FadeTimerLast[12];


void SingleButtonDimmer() {
  for (count = 0; count < 12; count++) {
//FUNCTION FOR BUTTON PRESS SHORTER THAN 345 milliseconds
    if (VirtualInput[count] == 0) {
      TimerEndVirtualInput[count] = millis();
      if (TriggerVirtualInput[count] == 0) {
        TriggerVirtualInput[count] = 1;
        TimerStartVirtualInput[count] = millis();
      }
    }
    if (VirtualInput[count] == 1) {
      if (TriggerVirtualInput[count] == 1) {
        TriggerVirtualInput[count] = 0;
// INVERT DIM DIRECTION AFTER BUTTON PRESS
        DimDirection[count] = !DimDirection[count];
        ResultVirtualInput[count] = TimerEndVirtualInput[count] - TimerStartVirtualInput[count];
//INCREMENT COUNTER ON SHORT PRESS OF THE BUTTON (less than 345 milliseconds)
        if (ResultVirtualInput[count] > 10 && ResultVirtualInput[count] < 345) {
          TimerDimCounter[count] = millis();
          DimCounter[count] += 1;
        }
      }
    }
//PROCESS COUNTER VALUE
    if (millis() - TimerDimCounter[count] > 345 && millis() - TimerDimCounter[count] < 350 && VirtualInput[count] == 1) {
      if (DimCounter[count] == 1) {
//IF ONE PRESS AND LIGHT ON , TURN LIGHT OFF , THEN UPDATE STATUS TO HOME AUTOMATION SERVER AFTER
        if (PwmSetValue[count] > 0) {
          DimDirection[count] = true;
          PwmSetValue[count] = 0;
          PwmStatusUpdateTimer[count] = millis();
          PwmStatusUpdateTrigger[count] = 1;
        }
//IF ONE PRESS AND LIGHT OFF , ASK HOME AUTOMATION SERVER TO RESTORE STORED VALUE
//(temporarily restore to 50% right now , my actual use case is irelevant to you)
        else if (PwmSetValue[count] == 0) {
          DimDirection[count] = true;
          // ANY COMMAND TO HOME AUTOMATION SERVER
          // WE CAN WORK IN STANDALONE BY ADDING SOME FUNCTION TOO

          // right now i put 50% brightness temporarily for you
          PwmSetValue[count] = 128;
        }
      }
//IF FAST DOUBLE TAP ON BUTTON , SET FULL BRIGHTNESS (same behaviour as my Hardware Fibaro Dimmer)
      if (DimCounter[count] >= 2) {
        PwmSetValue[count] = 255;
        PwmStatusUpdateTimer[count] = millis();
        PwmStatusUpdateTrigger[count] = 1;
      }
//RESET TAP COUNTER AT THE END OF THE FUNCTION
      DimCounter[count] = 0;
    }
//RESET TAP COUNTER IF WAS NOT RESETED PREVIOUSLY
    if (millis() - TimerDimCounter[count] > 350) {
      DimCounter[count] = 0;
    }
//IF BUTTON NOT RELEASED AFTER 350ms THEN START DIMMING LIGHT LEVEL (one step every 17ms)
    if (VirtualInput[count] == 0 && millis() - TimerStartVirtualInput[count] > 350 && millis() - DimButtonLoop[count] >= DimButtonLoopValue) {
      DimButtonLoop[count] = millis();
      PwmStatusUpdateTimer[count] = millis();
      PwmStatusUpdateTrigger[count] = 1;
      if (DimDirection[count] == true) {
        PwmSetValue[count] = PwmSetValue[count] + 1;
        PwmSetValue[count] = constrain(PwmSetValue[count], 3, 255);
      }
      if (DimDirection[count] == false) {
        PwmSetValue[count] = PwmSetValue[count] - 1;
        PwmSetValue[count] = constrain(PwmSetValue[count], 3, 255);
      }
    }
// 1500 milliseconds after button released send STATUS UPDATE TO HOMEAUTOMATION SERVER
// THIS FUNCTION MAY BE USELESS TO YOU
    if (millis() - PwmStatusUpdateTimer[count] > 1500 && PwmStatusUpdateTrigger[count] == 1) {
      PwmStatusUpdateTrigger[count] = 0;
      // SEND COMMAND TO HOMEAUTOMATION SERVER HERE
    }
  }
}


void PWMCheck() {
  for (count = 0; count < 12; count++) { 
// LOOP TO SET PWM SMOOTHLY
    if ((micros() - FadeTimerLast[count]) >= PwmFadeTime) {
      FadeTimerLast[count] = micros();
      if(PwmSetValue[count] > PwmFadeValue[count]) {
        PwmFadeValue[count] = PwmFadeValue[count] + 1;
      }
      if(PwmSetValue[count] < PwmFadeValue[count]) {
        PwmFadeValue[count] = PwmFadeValue[count] - 1;
      }
      PwmFadeValue[count] = constrain(PwmFadeValue[count], 0, 255);
    }
    analogWrite(PwmPins[count], PwmFadeValue[count]);
  }
}


void setup() {
// set PWM output
  pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(5, OUTPUT);
  pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(8, OUTPUT);
  pinMode(9, OUTPUT); pinMode(11, OUTPUT); pinMode(12, OUTPUT);
  pinMode(44, OUTPUT); pinMode(45, OUTPUT); pinMode(46, OUTPUT);
// set Input pin
  for (count = 0; count < 12; count++) {
    pinMode(count + 22, INPUT_PULLUP);
  }
}


void loop() {
//update VirtualInput with actual button value for pin 22 to 34
  for (count = 0; count < 12; count++) {
    VirtualInput[count] = digitalRead(count + 22);
  }
  SingleButtonDimmer();
  PWMCheck();
}