////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// COFFEE TABLE CONTROLER //////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This code defines: Objects: Required Variable Definitions:
//
// 4 custom objects: - MomentaryLEDButton ::Locally Defined::
// Button Pin
// Led Pin
// Name [Default = "null"]
// Button Type: 1 = normal on/off momentary, 2 = momentary w/ single, double, long press feedback, [Default = 1]
// Memorized Type: -1 = not set, settable range = 0 to 100, [Default = -1]
// ::Globally Defined::
// DebounceTime
// LongPress
// DoublePress
// LEDBrightness
// LEDBlinkRate
// LEDPulseRate
// LEDFadeRate
// LEDIlluminationDuration
// ::Globally Declared::
// NumLEDsActive volatile int
// ModuleLocked volatile bool
// SleepState volatile bool
// LastButtonInput volatile unsigned long
// PulseBrightnessTimer volatile unsigned long
//
// - CapacitiveSensor ::Locally Defined::
// Data Pin
// Name
// Maximum Acceptable Data Value
// Minimum Acceptable Data Value
// Data Value Representing a Trigger
//
// - LiftActuator ::Locally Defined::
// Lift Pin
// Lower Pin
//
// - ControlModule ::Globally Defined::
// NumExpectedLEDs
//
// 1 homeSpan custom object: - DEV_CoffeeTable ::Locally Defined::
// Name
// Lift Pin
// Lower Pin
// Led Pin
// ::Globally Defined::
// Period
// ::Globally Declared::
// CoffeeTableHeight volatile int
//
// 2 homeSpan LED objects: - DEV_LED ::Locally Defined::
// Led Pin
//
// - DEV_DimmableLED ::Locally Defined::
// Led Pin
// Name
//
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// LIBRARY DEFINITIONS //////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
#include "Arduino.h"
#include "HomeSpan.h"
#include <Preferences.h>
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////// GLOBAL VARIABLES ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Flash Memory Storage Setup
Preferences preferences;
// led pinnout red wire to led output pin, blue wire to button input pin, black wire to ground, green wire to 3.3v
// actuator / lift pins
#define Lift_Pin 4
#define Lower_Pin 16
// capacitive sensor pins
#define Max_Homing_Sensor 39
#define Min_Homing_Sensor 36
// button input pins
#define Lift_Button 34 // brown wire
#define Lower_Button 35 // maroon wire
#define Memory_1_Button 21 // grey wire
#define Memory_2_Button 19 // orange wire
#define Memory_3_Button 18 // purple wire
// button LED output pins
#define Lift_Button_LED 23 // green wire
#define Lower_Button_LED 22 // red wire
#define Memory_1_Button_LED 26 // white wire
#define Memory_2_Button_LED 27 // yellow wire
#define Memory_3_Button_LED 13 // blue wire
// control module button count
#define NumExpectedLEDs 5
// accent LED pins
#define Accent_LED_Strip 17
// potentiall add remote control over external esp32 allowing the spotlight LEDs for the coffee table to be contorled by this same object
// settings
#define NumLEDsInModule 5 // total number of LED Buttons in Module
// actuator / lift settings
#define MaxLiftDuration 25 // in seconds, total time it takes to raise the table from fully closed to fully open
// button settings
#define DebounceTime 20 // in milliseconds
#define LongPress 1500 // in milliseconds, total time a button must be pressed in order to consider it a Long Press
#define DoublePress 350 // in milliseconds, total amount of time allowed between button presses for them to be considered in sequence (aka to increase button press counter)
// led settings
#define LEDBrightness 100 // out of 1 to 225
#define LEDBlinkRate 500 // in milliseconds, total duration of on and off states
#define LEDPulseRate 12000 // in milliseconds, total duraiton to pulse LED on and pulse LED off (note: used for on and off fading while in pulse mode)
#define LEDFadeRate 5500 // in milliseconds, total duration to fade LED on and fade LED off (note: used for wake and sleep fading)
#define LEDIlluminationDuration 20000 // in milliseconds, total duration for LEDs to be illuminated after the last button input register
#define LEDWakeDelay 1500 // in milliseconds, total duration to delay recording button input after wake
// poll / loop settings
#define Period 1000 // in milliseconds, total time required to pass before registering another evaluation of table height (note: this will be the unit of measurement for the max lift duration... i.e. if max lift duration is in seconds, this should be 1000)
// HomeSpan Active Status
volatile int HomeSpan_State = 0;
// Manual Input Status
volatile int ManualInput_State = 0;
// LED Active Status
volatile int NumLEDsActive = 0;
volatile int NumLEDsPulse = 0;
volatile int NumLEDsBlink = 0;
// LED Sleep Status
volatile bool SleepState = true;
volatile unsigned long LEDWakeTimer = 0;
volatile bool DelayLEDWake = true;
volatile bool StartUp = true;
// Coffee Table Height
volatile int CoffeeTableHeight = 0;
// Homing Sensor Trigger Values [NOTE: Only needed if activated in homeSpan loops]
volatile bool MinTriggered;
volatile bool MaxTriggered;
// Last Button Input
volatile unsigned long LastButtonInput;
// Global Pulse Timer for syncronization
volatile unsigned long GlobalPulseBrightness; // Current brightness of LEDs currently pulsing | Note: This ensures they all pulse in unison
volatile unsigned long GlobalBlinkState;
// Lock Control Module Variables
volatile int lockControls = 0;
volatile unsigned long lockControlsStartTimer = millis();
volatile unsigned long postLockControlTimer = millis();
volatile bool ModuleLocked = false;
volatile bool ModuleStateUpdated = false;
volatile int UnlockDelay = 1000; // Time in milliseconds the lock timer will wait between toggles until re-evaluating button input
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN STRUCT DEFINITIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MOMENTARY LED BUTTON STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct MomentaryLEDButton {
// input / output pins
int _button_pin;
int _led_pin;
// mode settings
int _current_button_mode = 1; // Allows for alternate button modes / functions, this is the current mode the button is set to
int _target_button_mode = 1; // This represents the mode state the button should change to
// setting variables
int _current_button_type; // Current button type | Momentary Push Button = 1, Memory Latch Button = 2
int _1st_mode_button_type; // Used for Alternate Button Modes (i.e. normal mode) Momentary Push Button = 1, Memory Latch Button = 2
int _2nd_mode_button_type; // Used for Alternate Button Modes (i.e. locked mode) Momentary Push Button = 1, Memory Latch Button = 2
String _name; // Button Name
// button status variables
int _lastRecordedButtonState = 0; // Not Engaged = 0, Engagegd = 1
int _pressType = 0; // Not Pressed = 0, Single Press = 1, Double Press = 2, Long Press = 3
int _pressCount = 0; // Counts the number of times a button has been pressed in succession within doublePress timeframe between each press
bool _buttonPressed = false; // New Button Press = true, Button Release = false
bool _buttonLongPressed = false;
bool _updateButton = false; // Once Button has been released = true, once button press type has been determined and updated = false
bool _buttonUpdated = false; // Once new button press registered and button type determined = true can be externally accessed via newButtonInput(), once buttonInputProcessed() called = false;
//bool _ledTargetWakeModeSet = false;
// led status variables
bool _sleepState = true; // When in sleep mode = true, when awake = false
int _ledPowerState = 0; // Fully Off = 0, Fully On = 1 (fully as defined by the variable _ledMaxBrightness)
int _ledActiveState = 0; // Fully Off = 0, Mode Sequence Active = 1 (Seqences resulting in 1: Steady On, Pulse, Blink, FadeOn, FadeOff)
int _ledCurrentMode = 0; // Current Mode of LED (Steady Off = 0, Steady On = 1, Blink = 2, FadeOff = 3, FadeOn = 4, Pulse = 5)
int _ledTargetMode = 0; // Target Mode for LED (aka what is the new mode you would like the LED to display?)
int _ledLockedPreviousTargetMode = 4; // Allowing for the maintenance of different button led modes for each module state
int _ledUnlockTargetMode = 4;
int _ledPreviousTargetMode = 4; // Set to 4 for initial StartUp however this will hold the value of the previous mode the LED was set to before it was sent a new Target Mode call
int _ledMaxBrightness = round(LEDBrightness/100*225); // Maximum Brightness setting of LED (LED Acceptable Range = 0 to 225, Globally defined LEDBrightness Acceptable Range as % 0 to 100, this formula converts LEDBrightness to % of Acceptable Range)
int _currentBrightness = 0; // Current brightness of the LED
int _fades = LEDFadeRate/_ledMaxBrightness; // number of cycles necessary to achieve _ledMaxBrightness by LEDFadeRate
int _fadeRate = _ledMaxBrightness/_fades; // incremental brightness change needed to achieve _ledMaxBrightness by globally defined LEDFadeRate
int _fadesPulse = LEDPulseRate/_ledMaxBrightness; // number of cycles necessary to achieve _ledMaxBrightness by LEDPulseRate
int _fadeRatePulse = _ledMaxBrightness/_fades; // incremental brightness change needed to achieve _ledMaxBrightness by globally defined LEDPulseRate
// memory variables
int _memorizedHeight; // accessible when _current_button_type = 2. No Height Set = -1, Settable Height Range from 0 to 100
// timer variables
unsigned long _ledTimer = millis();
unsigned long _pressTimer = millis();
unsigned long _releaseTimer = millis();
unsigned long _pressDuration = millis();
unsigned long _inactiveDuration = millis();
void initialize(int BUTTONpin, int LEDpin, String name = "null", int firstStateButtonType = 1, int secondStateButtonType = 1, int memorizedHeight = -1) {
_button_pin = BUTTONpin;
_led_pin = LEDpin;
_name = name;
_1st_mode_button_type = firstStateButtonType;
_2nd_mode_button_type = secondStateButtonType;
_current_button_type = _1st_mode_button_type;
_memorizedHeight = memorizedHeight;
_ledCurrentMode = 0;
_ledTargetMode = 0;
_ledPowerState = 0;
_ledActiveState = 0;
pinMode(_button_pin, INPUT_PULLDOWN);
pinMode(_led_pin, OUTPUT);
digitalWrite(_led_pin, LOW);
}
void updatePreviousTargetMode(){
_ledPreviousTargetMode = _ledTargetMode;
}
void activateUnlockMode(){
_ledTargetMode = _ledUnlockTargetMode;
updateLED();
}
void setUnlockMode(int mode){
_ledUnlockTargetMode = mode;
}
void setTargetMode(int targetMode){
updatePreviousTargetMode();
_ledTargetMode = targetMode;
}
void activatePreviousTargetMode(){
_ledTargetMode = _ledPreviousTargetMode;
updateLED();
}
void off() {
if (_ledTargetMode == 5){
NumLEDsPulse--;
} else if (_ledTargetMode == 2){
NumLEDsBlink--;
}
setTargetMode(0);
if (_ledActiveState == 1) {
analogWrite(_led_pin, 0);
NumLEDsActive = 0;
_ledPowerState = 0;
_ledActiveState = 0;
_ledCurrentMode = 0;
}
}
void on() {
setTargetMode(1);
if (_ledActiveState == 0) {
analogWrite(_led_pin, _ledMaxBrightness);
NumLEDsActive += 1;
_ledPowerState = 1;
_ledActiveState = 1;
_ledCurrentMode = 1;
}
}
void blink() {
if (_ledTargetMode != 2){
NumLEDsBlink++;
setTargetMode(2);
Serial.print("NumLEDsBlink: ");
Serial.println(NumLEDsBlink);
}
if(_ledActiveState == 0){
NumLEDsActive += 1;
_ledActiveState = 1;
}
analogWrite(_led_pin, GlobalBlinkState);
}
void fadeOff(){
if (_ledTargetMode != 3){
setTargetMode(3);
_currentBrightness = _ledMaxBrightness;
if (_ledTargetMode == 5){
NumLEDsPulse--;
} else if (_ledTargetMode == 2){
NumLEDsBlink--;
}
}
if (millis() - _ledTimer > _fades){
_currentBrightness = _currentBrightness - _fadeRate;
if(_currentBrightness <= 0){ _currentBrightness = 0;}
analogWrite(_led_pin, _currentBrightness);
if (_currentBrightness == 0){
NumLEDsActive = 0;
_ledPowerState = 0;
_ledActiveState = 0;
_ledCurrentMode = 3;
}
_ledTimer = millis();
}
}
void fadeOn(){
setTargetMode(4);
if (_current_button_type == 2 && _memorizedHeight == -1){
pulse();
} else {
if(_ledActiveState == 0){
NumLEDsActive += 1;
_ledActiveState = 1;
}
if (millis() - _ledTimer > _fades){
_currentBrightness = _currentBrightness + _fadeRate;
if(_currentBrightness > _ledMaxBrightness){ _currentBrightness = _ledMaxBrightness;}
analogWrite(_led_pin, _currentBrightness);
if (_currentBrightness == _ledMaxBrightness && _ledPowerState == 0){
_ledPowerState = 1;
_ledCurrentMode = 4;
}
_ledTimer = millis();
}
}
}
void pulse() {
if (_ledTargetMode != 5){
NumLEDsPulse++;
setTargetMode(5);
}
if(_ledActiveState == 0){
NumLEDsActive += 1;
_ledActiveState = 1;
}
analogWrite(_led_pin, GlobalPulseBrightness);
}
void sleep(){
if(_ledTargetMode == 0){
off();
} else {
fadeOff();
}
DelayLEDWake = true;
StartUp = true;
_sleepState = true;
if(!SleepState){
SleepState = _sleepState;
}
}
void wake(){
activatePreviousTargetMode();
//_ledTargetWakeModeSet = false;
LEDWakeTimer = millis();
_sleepState = false;
if(SleepState){
SleepState = _sleepState;
}
}
bool getSleepState(){
return _sleepState;
}
void checkWakeSleep() {
if (millis() - LastButtonInput >= LEDIlluminationDuration){
sleep();
} else
/*if (_ledActiveState == 0 && NumLEDsActive > 0 && _sleepState){
wake();
} else*/
if (_ledActiveState == 0 && _lastRecordedButtonState == HIGH && _sleepState){
wake();
} else
if (!SleepState && _sleepState){
wake();
}
}
/*void wakeLED() {
if(_ledCurrentMode != _ledTargetWakeMode){
switch (_ledTargetWakeMode){
case 0:
off();
break;
case 1:
on();
break;
case 2:
blink();
break;
case 3:
fadeOff();
break;
case 4:
fadeOn();
break;
case 5:
pulse();
break;
}
}
}*/
void updateLED() {
if(_ledCurrentMode != _ledTargetMode){
switch (_ledTargetMode){
case 0:
off();
break;
case 1:
on();
break;
case 2:
blink();
break;
case 3:
fadeOff();
break;
case 4:
fadeOn();
break;
case 5:
pulse();
break;
}
}
}
void updateCurrentButtonState(){
if (millis() - _pressTimer >= DebounceTime){
if(digitalRead(_button_pin)){
LastButtonInput = millis();
_lastRecordedButtonState = 1;
ManualInput_State = 1;
} else {
_lastRecordedButtonState = 0;
ManualInput_State = 0;
}
}
}
void updateButtonPressType(){
if (DelayLEDWake){
if(_lastRecordedButtonState == HIGH && millis() - LEDWakeTimer >= LEDWakeDelay){
if (StartUp){
StartUp = false;
Serial.println("StartUp");
} else {
DelayLEDWake = false;
Serial.println("LEDWake has been delayed");
}
}
} else
if (_current_button_type == 1){
if (_lastRecordedButtonState == HIGH && !_buttonPressed) {
_buttonPressed = true;
} else if (_lastRecordedButtonState == LOW && _buttonPressed){
_buttonPressed = false;
}
} else if (_current_button_type == 2){
// Check if button is pressed (note button press is called in every loop cycle)
if (_lastRecordedButtonState == HIGH && !_buttonPressed) {
_buttonPressed = true;
_pressTimer = millis();
_inactiveDuration = _pressTimer - _releaseTimer;
}
// Check if the button is released
if (_lastRecordedButtonState == LOW && _buttonPressed) {
_buttonPressed = false;
if(!_buttonLongPressed){
_buttonUpdated = false;
_updateButton = true;
_pressCount++;
_releaseTimer = millis();
_pressDuration = _releaseTimer - _pressTimer;
} else {
_buttonLongPressed = false;
}
}
if (_buttonPressed && !_buttonLongPressed && millis() - _pressTimer >= LongPress){
_pressType = 3;
_pressCount = 0;
_buttonUpdated = true;
_buttonLongPressed = true;
Serial.print(_name);
Serial.println(" button: Long Press");
}
if (_updateButton){
if (_inactiveDuration < DoublePress && _pressCount == 2) {
_pressType = 2;
_pressCount = 0;
_updateButton = false;
_buttonUpdated = true;
Serial.print(_name);
Serial.println(" button: Double Press");
} else
// Check for a single press
if (millis() - _releaseTimer > DoublePress) {
_pressType = 1;
_pressCount = 0;
_updateButton = false;
_buttonUpdated = true;
Serial.print(_name);
Serial.println(" button: Single Press");
}
}
}
}
/*void setWakeMode(int wakeMode){
_ledTargetWakeMode = wakeMode;
}*/
int getButtonState(){
return _lastRecordedButtonState;
}
bool newButtonInput(){
return _buttonUpdated;
}
void buttonInputProcessed(){
_buttonUpdated = false;
}
int getPressType(){
return _pressType;
}
void resetPressType(){
_pressType = 0;
}
int getMemorizedHeight(){
return _memorizedHeight;
}
void setMemorizedHeight(){
_memorizedHeight = CoffeeTableHeight;
//NumLEDsActive -= 1;
fadeOn();
Serial.print(_name);
Serial.print(" memorized height set to: ");
Serial.println(_memorizedHeight);
}
void resetMemorizedHeight(){
_memorizedHeight = -1;
pulse();
Serial.print(_name);
Serial.print(" memorized height reset to: ");
Serial.println(_memorizedHeight);
}
void setButtonMode(int mode){
if (_current_button_mode != mode){
switch(mode){
case 1:
_target_button_mode = 1;
_current_button_mode = _1st_mode_button_type;
break;
case 2:
_target_button_mode = 2;
_current_button_mode = _2nd_mode_button_type;
break;
}
}
}
void updateButtonMode(){
if (ModuleLocked){
setButtonMode(2);
} else {
setButtonMode(1);
}
}
void poll(){
checkWakeSleep();
updateLED();
updateCurrentButtonState();
updateButtonPressType();
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// CONTROL MODULE STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct ControlModule {
int _numDefinedLEDs = -1; // Number of LED Buttons initialized;
MomentaryLEDButton _momentaryLEDButtons[NumExpectedLEDs];
bool _moduleLocked = false; // false if all buttons are receiving input, true if button input is locked to only ready for unlock sequence
bool _checkingLockInput = false; // used to set the timestamp for checking the lockControlsTimer
int _ledActiveState = 0; // All LEDs Steady Off = 0, 1 or more LEDs not off = 1
int _numLEDsActive = 0; // Number of LEDs currently steady on or running a Mode Animation;
bool _sleepState = true; // true if all LEDs are off, false if any LEDs are active
int _pulseBrightness; // Brightness level for pulsing LEDs (to ensure they are syncronized)
int _blinkState; // Brightness level for blinking LEDs (to ensure they are syncronized)
int _ledMaxBrightness = round(LEDBrightness/100*225); // Maximum Brightness setting of LED (LED Acceptable Range = 0 to 225, Globally defined LEDBrightness Acceptable Range as % 0 to 100, this formula converts LEDBrightness to % of Acceptable Range)
int _fades = LEDFadeRate/_ledMaxBrightness; // number of cycles necessary to achieve _ledMaxBrightness by LEDFadeRate
int _fadeRate = _ledMaxBrightness/_fades; // incremental brightness change needed to achieve _ledMaxBrightness by globally defined LEDFadeRate
int _fadesPulse = LEDPulseRate/_ledMaxBrightness; // number of cycles necessary to achieve _ledMaxBrightness by LEDPulseRate
int _fadeRatePulse = _ledMaxBrightness/_fades; // incremental brightness change needed to achieve _ledMaxBrightness by globally defined LEDPulseRate
int _ledPowerState;
unsigned long lockControlsTimer = millis(); // timer to determine if pause sequence button(s) have been been pressed for the duration required to lock module input
unsigned long LastButtonInput; // The timestamp of when the last button was pressed
unsigned long _ledPulseTimer = millis();
unsigned long _ledBlinkTimer = millis();
void initialize(int NumLEDsinModule, bool sleepOnStartUp = true){
_sleepState = sleepOnStartUp;
}
void addButton(int BUTTONpin, int LEDpin, String name = "null", int buttonType = 1, int memorizedHeight = -1){
_numDefinedLEDs++;
_momentaryLEDButtons[_numDefinedLEDs].initialize(BUTTONpin, LEDpin, name, buttonType, memorizedHeight);
}
void updatePulseBrightness() {
if (millis() - _ledPulseTimer > _fadesPulse){
if (_ledPowerState != 1) {
_pulseBrightness = _pulseBrightness + _fadeRatePulse;
if(_pulseBrightness > _ledMaxBrightness){ _pulseBrightness = _ledMaxBrightness; _ledPowerState = 1;}
} else {
_pulseBrightness = _pulseBrightness - _fadeRatePulse;
if(_pulseBrightness < 0){ _pulseBrightness = 0; _ledPowerState = 0;}
}
_ledPulseTimer = millis();
GlobalPulseBrightness = _pulseBrightness;
}
}
void updateBlinkBrightness() {
if (millis() - _ledBlinkTimer > LEDBlinkRate) {
if (_blinkState == 0) {
_blinkState = _ledMaxBrightness;
} else {
_blinkState = 0;
}
_ledBlinkTimer = millis();
GlobalBlinkState = _blinkState;
}
}
void poll(){
/*for(int i = 0; i <= _numDefinedLEDs; i++){
_momentaryLEDButtons[i].poll();
}*/
if (NumLEDsBlink > 0){
updateBlinkBrightness();
}
if (NumLEDsPulse > 0){
updatePulseBrightness();
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// CAPACITIVE SENSOR STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct CapacitiveSensor {
int _data_pin;
String _name;
String _NVS_Trigger;
int _maxReading = 225; // Maximum expected reading
int _minReading = 0; // Minimum expected reading
int _triggerReading = 4; // Reading required to be considered triggered (aka once this is reached, do something or stop doing something)
int _currentReading; // The current data reading from the sensor
int _errorStatus = 0; // No Error = 0, Out of bounds minReading = 1, Out of bounds maxReading = 2, No Reading Present = -1 (aka, not receiving power)
bool _maxCalibrated = false; // Allows for manaul calibration of Maximum Expected Reading
bool _minCalibrated = false; // Allows for manaul calibration of Minumum Expected Reading
bool _triggerCalibrated = false; // Allows for manaul calibration of Trigger Reading
bool _triggered; // true if currrent reading >= trigger reading, otherwise false
// note these settings should only be used for magnetic sensors
int _currentMode = 0; // Current Sensor Mode (Normally LOW = 0, Normally HIGH = 1)
int _targetMode = 0; // Requested Sensor Mode
unsigned long _startMillis; // For reducing data noise?
void initialize(int datapin, String name, int maxReading = 225, int minReading = 0, int triggerReading = 175) {
_data_pin = datapin;
_name = name;
_maxReading = maxReading;
_minReading = minReading;
_triggerReading = triggerReading;
_NVS_Trigger = _name + "_trigger";
preferences.begin("Calibration",false);
if(preferences.getInt(_NVS_Trigger.c_str()) != 0){
_triggerReading = preferences.getInt(_NVS_Trigger.c_str());
}
preferences.end();
pinMode(_data_pin, INPUT);
}
///////////////////////////////////////
// update reading function for poll ///
///////////////////////////////////////
void updateReading(){
_currentReading = analogRead(_data_pin);
}
///////////////////////////////////////
// calibrate variable data functions //
///////////////////////////////////////
void calibrateMin() {
_minReading = getReading();
_minCalibrated = true;
Serial.print("In calibrateMin() | _minReading = ");
Serial.println(_minReading);
Serial.print(" | _minCalibrated = ");
Serial.println(_minCalibrated);
Serial.print(" | _errorStatus = ");
Serial.println(getError());
}
void calibrateMax() {
_maxReading = getReading();
_maxCalibrated = true;
Serial.print("In calibrateMax() | _maxReading = ");
Serial.println(_maxReading);
Serial.print(" | _maxCalibrated = ");
Serial.println(_maxCalibrated);
Serial.print(" | _errorStatus = ");
Serial.println(getError());
}
void calibrateTrigger() {
if (getError() == 0) {
_triggerReading = getReading();
_triggerCalibrated = true;
preferences.begin("Calibration",false);
preferences.putInt(_NVS_Trigger.c_str(), _triggerReading);
preferences.end();
}
Serial.print("In ");
Serial.print(_name);
Serial.print(" calibrateTrigger() | _triggerReading = ");
Serial.println(_triggerReading);
Serial.print(" | _triggerCalibrated = ");
Serial.println(_triggerCalibrated);
Serial.print(" | _errorStatus = ");
Serial.println(getError());
}
///////////////////////////////////////
// set variable data functions ////////
///////////////////////////////////////
void setMin(int minRangeValue) {
_minReading = minRangeValue;
_minCalibrated = true;
Serial.print("In setMin() | _minReading = ");
Serial.println(_minReading);
}
void setMax(int maxRangeValue) {
_maxReading = maxRangeValue;
_maxCalibrated = true;
Serial.print("In setMax() | _maxReading = ");
Serial.println(_maxReading);
}
void setTrigger(int triggerValue) {
_triggerReading = triggerValue;
_triggerCalibrated = true;
Serial.print("In setTrigger() | _triggerReading = ");
Serial.println(_triggerReading);
}
///////////////////////////////////////
// get variable data functions ////////
///////////////////////////////////////
int getReading(){
return _currentReading;
Serial.print("In getReading() | _currentReading = ");
Serial.println(_currentReading);
}
int getMin() {
return _minReading;
Serial.print("In getMin() | _minReading = ");
Serial.println(_minReading);
}
int getMax() {
return _maxReading;
Serial.print("In getMax() | _maxReading = ");
Serial.println(_maxReading);
}
int getTrigger() {
return _triggerReading;
Serial.print("In getTrigger() | _triggerReading = ");
Serial.println(_triggerReading);
}
int getError(){
return _errorStatus;
Serial.print("In getError() | _errorStatus = ");
Serial.println(_errorStatus);
}
bool minCalibrated(){
return _minCalibrated;
Serial.print("In minCalibrated() | _minCalibrated = ");
Serial.println(_minCalibrated);
}
bool maxCalibrated(){
return _maxCalibrated;
Serial.print("In maxCalibrated() | _maxCalibrated = ");
Serial.println(_maxCalibrated);
}
bool triggerCalibrated(){
return _triggerCalibrated;
Serial.print("In triggerCalibrated() | _triggerCalibrated = ");
Serial.println(_triggerCalibrated);
}
bool triggered(){
return _triggered;
}
///////////////////////////////////////
// poll function //////////////////////
///////////////////////////////////////
void poll(){
updateReading();
Serial.print(_name);
Serial.print(" _currentReading: ");
Serial.println(_currentReading);
if (_currentReading < _minReading){
_errorStatus = 1;
} else if (_currentReading > _maxReading){
_errorStatus = 2;
} else if (_currentReading == -1){
_errorStatus = -1;
} else {
_errorStatus = 0;
}
if (_currentReading <= _triggerReading){
_triggered = true;
} else {
_triggered = false;
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAGNETIC REED SWITCH STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct ReedSwitch {
int _data_pin;
String _name;
int _type; // 0 = Normally Open, 1 = Normally Closed
int _currentReading; // The current data reading from the sensor
int _previousReading; // allows to check if the state has been updated or not
bool _triggered; // true if currrent reading >= trigger reading, otherwise false
bool _stateUpdated; // true every time the switch state is updated
unsigned long _startMillis; // For reducing data noise?
void initialize(int datapin, String name, int type) {
_data_pin = datapin;
_name = name;
_type = type;
pinMode(_data_pin, INPUT);
if (digitalRead(_data_pin)){
_triggered = true;
} else {
_triggered = false;
}
}
///////////////////////////////////////
// update reading function for poll ///
///////////////////////////////////////
void updateReading(){
_currentReading = digitalRead(_data_pin);
}
///////////////////////////////////////
// get variable data functions ////////
///////////////////////////////////////
int getReading(){
return _currentReading;
Serial.print("In getReading() | _currentReading = ");
Serial.println(_currentReading);
}
bool triggered(){
return _triggered;
}
bool updated(){
return _stateUpdated;
}
void updateReceived(){
_stateUpdated = false;
}
///////////////////////////////////////
// poll function //////////////////////
///////////////////////////////////////
void poll(){
updateReading();
if (_type == 0 && _currentReading != _previousReading){
if(_currentReading){
_triggered = true;
} else {
_triggered = false;
}
_stateUpdated = true;
_previousReading = _currentReading;
Serial.print(_name);
Serial.print(" _triggered: ");
Serial.println(_triggered);
} else if (_type == 1 && _currentReading != _previousReading){
if(!_currentReading){
_triggered = true;
} else {
_triggered = false;
}
_stateUpdated = true;
_previousReading = _currentReading;
Serial.print(_name);
Serial.print(" _triggered: ");
Serial.println(_triggered);
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// LIFT ACTUATOR STRUCT - MAIN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct LiftActuator {
int _lift_pin;
int _lower_pin;
int _max_homing_pin; // If -1 no sensor attached
int _min_homing_pin; // If -1 no sensor attached
int _maxHeight = 100;
int _minHeight = 0;
int _currentHeight = 0; // The current height of the table between 0 and 100
int _targetHeight; // Where to move the table between 0 and 100
int _currentMode = 0; // Current Mode of lift (Lower = -1, Off = 0, Raise = 1, GoTo = 2)
int _targetMode; // Requested Mode of the Lift
int _activeState = 0; // Table Not Moving = 0, Table Moving = 1
int _goToState = 0;
int _previousGoToState;
unsigned long _startMillis;
unsigned long _maxLiftDurationMillis = MaxLiftDuration * 1000; // milliseconds for full movement
unsigned long _millisPeriod = _maxLiftDurationMillis / _maxHeight; // milliseconds per percentage movement
void initialize(int liftpin, int lowerpin, int maxHomingPin = -1, int minHomingPin = -1) {
_lift_pin = liftpin;
_lower_pin = lowerpin;
_max_homing_pin = maxHomingPin;
_min_homing_pin = minHomingPin;
pinMode(_lift_pin, OUTPUT);
pinMode(_lower_pin, OUTPUT);
digitalWrite(_lift_pin, LOW);
digitalWrite(_lower_pin, LOW);
}
void Raise() {
if (_max_homing_pin != -1 && MaxTriggered){
CoffeeTableHeight = 100;
_currentHeight = 100;
_targetMode = 0;
Serial.println("In void Raise() | Max Homing Sensor Triggered");
} else {
_targetMode = 1;
if(_activeState == 0){
_startMillis = millis();
digitalWrite(_lift_pin, HIGH);
_currentMode = 1;
_activeState = 1;
}
if (millis() - _startMillis >= _millisPeriod){
_currentHeight = _currentHeight + 1;
if (_currentHeight > 100){ _currentHeight = 100;}
CoffeeTableHeight = _currentHeight;
_startMillis = millis();
}
Serial.print("In void Raise() | _currentHeight: ");
Serial.println(_currentHeight);
}
}
void Lower() {
if (_min_homing_pin != -1 && MinTriggered){
CoffeeTableHeight = 0;
_currentHeight = 0;
_targetMode = 0;
Serial.println("In void Lower() | Min Homing Sensor Triggered");
} else {
_targetMode = -1;
if(_activeState == 0){
_startMillis = millis();
digitalWrite(_lower_pin, HIGH);
_currentMode = -1;
_activeState = 1;
}
if (millis() - _startMillis >= _millisPeriod){
_currentHeight = _currentHeight - 1;
if (_currentHeight < 0){ _currentHeight = 0;}
CoffeeTableHeight = _currentHeight;
_startMillis = millis();
}
Serial.print("In void Lower() | _currentHeight: ");
Serial.println(_currentHeight);
}
}
void Stop() {
_targetMode = 0;
if(_currentMode != _targetMode){
digitalWrite(_lift_pin, LOW);
digitalWrite(_lower_pin, LOW);
if(millis() - _startMillis >= _millisPeriod){
_currentHeight = _currentHeight + _currentMode;
if(_currentHeight > 100){
_currentHeight = 100;
}
if(_currentHeight < 0){
_currentHeight = 0;
}
CoffeeTableHeight = _currentHeight;
}
_currentMode = 0;
_activeState = 0;
LastButtonInput = millis();
Serial.print("In void Stop() | _currentHeight: ");
Serial.println(_currentHeight);
Serial.print(" | _goToState: ");
Serial.println(_goToState);
}
}
void GoTo(int Height = 0) {
if(_goToState == 0){
_goToState = 1;
_targetHeight = Height;
}
if(_currentHeight == _targetHeight){
_goToState = 0;
Stop();
} else if(_currentHeight < _targetHeight){
Raise();
LastButtonInput = millis();
} else {
Lower();
LastButtonInput = millis();
}
}
void resetGoTo(){
_targetHeight = _currentHeight;
Stop();
}
void resetCurrentHeight(int Height){
_currentHeight = Height;
}
void poll(){
_currentHeight = CoffeeTableHeight;
if(_goToState == 1){
GoTo();
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// HOMESPAN STRUCT DEFINITIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// //
// DEV TABLE - HOMESPAN //
// //
//////////////////////////////////////////////////////////////////////////////////////////
struct DEV_LED : Service::LightBulb { // ON/OFF LED
int ledPin; // pin number defined for this LED
SpanCharacteristic *power; // reference to the On Characteristic
DEV_LED(int ledPin) : Service::LightBulb(){ // constructor() method
power=new Characteristic::On();
this->ledPin=ledPin;
pinMode(ledPin,OUTPUT);
} // end constructor
boolean update(){ // update() method
digitalWrite(ledPin,power->getNewVal());
return(true); // return true
} // update
};
//////////////////////////////////
// Here's the new code defining DEV_DimmableLED - changes from above are noted in the comments
struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
LedPin *ledPin; // NEW! Create reference to LED Pin instantiated below
SpanCharacteristic *power; // reference to the On Characteristic
SpanCharacteristic *level; // NEW! Create a reference to the Brightness Characteristic instantiated below
SpanCharacteristic *name;
DEV_DimmableLED(int pin, const char * _name) : Service::LightBulb(){ // constructor() method
name=new Characteristic::ConfiguredName(_name,true);
power=new Characteristic::On();
level=new Characteristic::Brightness(50); // NEW! Instantiate the Brightness Characteristic with an initial value of 50% (same as we did in Example 4)
level->setRange(5,100,1); // NEW! This sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% (different from Example 4 values)
this->ledPin=new LedPin(pin); // NEW! Configures a PWM LED for output to the specified pin. Note pinMode() does NOT need to be called in advance
} // end constructor
boolean update(){ // update() method
// Here we set the brightness of the LED by calling ledPin->set(brightness), where brightness=0-100.
// Note HomeKit sets the on/off status of a LightBulb separately from its brightness, which means HomeKit
// can request a LightBulb be turned off, but still retains the brightness level so that it does not need
// to be resent once the LightBulb is turned back on.
// Multiplying the newValue of the On Characteristic ("power", which is a boolean) with the newValue of the
// Brightness Characteristic ("level", which is an integer) is a short-hand way of creating the logic to
// set the LED level to zero when the LightBulb is off, or to the current brightness level when it is on.
ledPin->set(power->getNewVal()*level->getNewVal());
return(true); // return true
} // update
};
struct DEV_CoffeeTable : Service::WindowCovering { // A motorized Window Shade with Hold Feature
SpanCharacteristic *current;
SpanCharacteristic *target;
SpanCharacteristic *positionState;
int raisePin;
int lowerPin;
int ledPin;
int activeDuration;
int _maxHomingValue;
int _minHomingValue;
int _maxHomingPin;
int _minHomingPin;
bool _manualInputState_Updated = false;
const char *actuatorName;
SpanCharacteristic *name;
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
DEV_CoffeeTable(const char *vName, int raisePin, int lowerPin, int ledPin) : Service::WindowCovering() {
name = new Characteristic::Name(vName, true);
this->raisePin = raisePin;
this->lowerPin = lowerPin;
this->ledPin = ledPin;
current = new Characteristic::CurrentPosition(0,true); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised)
target = new Characteristic::TargetPosition(0,true); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised)
target->setRange(0, 100, 10); // set the allowable target-position range to 0-100 IN STEPS of 10
CoffeeTableHeight = current->getVal();
positionState = new Characteristic::PositionState(2);
Serial.print("Configuring Coffee Table Lift Acutator");
Serial.print("\n");
}
void debugActiveDurationRaising(){
Serial.print("Raising Coffee Table | current->getVal(): ");
Serial.print(current->getVal());
Serial.print(" | target->getNewVal(): ");
Serial.print(target->getNewVal());
Serial.print(" | activeDuration: ");
Serial.println(activeDuration);
}
void debugActiveDurationLowering(){
Serial.print("Lowering Coffee Table | current->getVal(): ");
Serial.print(current->getVal());
Serial.print(" | target->getNewVal(): ");
Serial.print(target->getNewVal());
Serial.print(" | activeDuration: ");
Serial.println(activeDuration);
}
boolean update() {
//current->setVal(current->getNewVal());
if (target->getNewVal() > current->getVal()) {
startMillis = millis(); //initial start time
LOG1("Raising Coffee Table\n");
digitalWrite(lowerPin, LOW);
digitalWrite(raisePin, HIGH);
activeDuration = abs(MaxLiftDuration*(current->getVal()-target->getNewVal())/100);
HomeSpan_State = 1;
debugActiveDurationRaising();
} else if (target->getNewVal() < current->getVal()) {
startMillis = millis(); //initial start time
LOG1("Lowering Coffee Table\n");
digitalWrite(raisePin, LOW);
digitalWrite(lowerPin, HIGH);
activeDuration = abs(MaxLiftDuration*(current->getVal()-target->getNewVal())/100);
HomeSpan_State = 1;
debugActiveDurationLowering();
}
return (true);
}
void loop() {
if (ManualInput_State == 1 && !_manualInputState_Updated) {
_manualInputState_Updated = true;
HomeSpan_State = 0;
current->setVal(CoffeeTableHeight, true);
target->setVal(CoffeeTableHeight, true);
} else {
if(CoffeeTableHeight != current->getVal() && millis() - startMillis >= Period){
current->setVal(CoffeeTableHeight, true);
target->setVal(CoffeeTableHeight, true);
}
if(current->getVal() != target->getVal() && millis() - startMillis >= Period){
if (ManualInput_State == 0){
_manualInputState_Updated = false;
if(target->getVal() > current->getVal()){
current->setVal(current->getVal()+(100/MaxLiftDuration));
CoffeeTableHeight = current->getVal();
startMillis = millis();
} else {
current->setVal(current->getVal()-(100/MaxLiftDuration));
CoffeeTableHeight = current->getVal();
startMillis = millis();
}
}
}
if (current->getVal() != target->getVal() && target->timeVal() > activeDuration*1000) {
current->setVal(target->getVal());
CoffeeTableHeight = current->getVal();
digitalWrite(raisePin, LOW);
digitalWrite(lowerPin, LOW);
HomeSpan_State = 0;
Serial.println("Done.");
}
}
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN PROGRAM STRUCT DECLARATIONS //
// //
//////////////////////////////////////////////////////////////////////////////////////////
// CREATE MODULE //
//////////////////////////////////////////////////////////////////////////////////////////
// _________________________________________________ // ____ DOTS ____ | ____ WIRE ____ //
ControlModule(controlModule1); // NA | NA //
// ------------------------------------------------------------------- | -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
// CREATE BUTTONS //
//////////////////////////////////////////////////////////////////////////////////////////
// __________________________________________________________________ // ____ WIRE ____ //
MomentaryLEDButton(liftButton); // //
MomentaryLEDButton(lowerButton); // //
MomentaryLEDButton(memory1Button); // //
MomentaryLEDButton(memory2Button); // //
MomentaryLEDButton(memory3Button); // //
// ------------------------------------------------------------------ // -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
// CREATE LIFT //
//////////////////////////////////////////////////////////////////////////////////////////
// _________________________________________________ // ____ LIFT ____ | ____ LOWER ___ //
LiftActuator(coffeeTable); // WHITE | BLACK //
// ------------------------------------------------------------------- | -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
// CREATE SENSORS //
//////////////////////////////////////////////////////////////////////////////////////////
// _________________________________________________ // ____ LIFT ____ | ____ LOWER ___ //
ReedSwitch(MaxHomingSensor); // | //
ReedSwitch(MinHomingSensor); // | //
// ------------------------------------------------------------------- | -------------- //
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// //
// SETUP //
// //
//////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
// initializing scissor lift
coffeeTable.initialize(Lift_Pin, Lower_Pin, Max_Homing_Sensor, Min_Homing_Sensor);
// initializing led buttons
liftButton.initialize(Lift_Button, Lift_Button_LED, "Lift",1,2);
lowerButton.initialize(Lower_Button, Lower_Button_LED, "Lower",1,2);
memory1Button.initialize(Memory_1_Button, Memory_1_Button_LED, "Memory_1",2,2,100);
memory2Button.initialize(Memory_2_Button, Memory_2_Button_LED, "Memory_2",2,2,50);
memory3Button.initialize(Memory_3_Button, Memory_3_Button_LED, "Memory_3",2,2,0);
// initializing sensors
MaxHomingSensor.initialize(Max_Homing_Sensor, "MaxHomingSensor", 0);
MinHomingSensor.initialize(Min_Homing_Sensor, "MinHomingSensor", 0);
MaxTriggered = MaxHomingSensor.triggered();
MinTriggered = MinHomingSensor.triggered();
// initializing homespan
//homeSpan.enableOTA();
homeSpan.begin(Category::WindowCoverings, "Coffee Table");
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Coffee Table");
(new DEV_CoffeeTable("Coffee Table", Lift_Pin, Lower_Pin, Accent_LED_Strip))->addLink(new DEV_DimmableLED(Accent_LED_Strip, "Accent Lights"));
delay(500);
}
bool homespan_blink_update = false;
//////////////////////////////////////////////////////////////////////////////////////////
// //
// MAIN LOOP //
// //
//////////////////////////////////////////////////////////////////////////////////////////
void loop() {
/////////////////////////////////////
// //
// OBJECTS TO UPDATED EVERY LOOP //
// //
/////////////////////////////////////
homeSpan.poll(); ////////////////////
/////////////////////////////////////
coffeeTable.poll(); /////////////////
/////////////////////////////////////
controlModule1.poll(); //////////////
/////////////////////////////////////
MaxHomingSensor.poll(); /////////////
MinHomingSensor.poll(); /////////////
/////////////////////////////////////
liftButton.poll(); //////////////////
lowerButton.poll(); /////////////////
memory1Button.poll(); ///////////////
memory2Button.poll(); ///////////////
memory3Button.poll(); ///////////////
/////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// // Handles: Wake / Sleep input delay //
// DEFINE WHAT TO DO WITH BUTTON INPUT // Locking / Unlocking Module //
// // Haulting HomeSpan when active //
///////////////////////////////////////////////////////////////////////////////////////////////
// ONLY PROCESS BUTTON INPUT WHEN MODULE IS NOT IN SLEEP MODE AND NOT JUST ENTERED WAKE MODE //
///////////////////////////////////////////////////////////////////////////////////////////////
if (!DelayLEDWake){
if (MaxHomingSensor.updated()){
MaxTriggered = MaxHomingSensor.triggered();
MaxHomingSensor.updateReceived();
}
if (MinHomingSensor.updated()){
MinTriggered = MinHomingSensor.triggered();
MinHomingSensor.updateReceived();
}
//////////////////////////////////////////////////////////////////////////////////////////////
// // Notes: Both Raise & Lower Buttons //
// CHECKING IF LOCK / UNLOCK CALL MADE // must be held down for LongPress //
// // in order to toggle lock / unlock //
//////////////////////////////////////////////////////////////////////////////////////////////
if (liftButton.getButtonState() == HIGH && lowerButton.getButtonState() == HIGH ){
// hault goTo() activity
if(coffeeTable._goToState == HIGH){
coffeeTable.resetGoTo();
}
// halt raise / lower / homespan activity
if(coffeeTable._activeState == 1){
coffeeTable.Stop();
}
if(lockControls == 0){
if (millis() - postLockControlTimer >= UnlockDelay){
lockControls = 1;
lockControlsStartTimer = millis();
}
}
// check press duration & ensure only one toggle is registered per Long Press...
// aka if buttons hold continues after long press, do not retrigger action
if (millis() - lockControlsStartTimer >= LongPress && lockControls == 1){
// LOCK MODULE
if(!ModuleLocked){
ModuleLocked = true;
lockControls = 0;
liftButton.pulse();
lowerButton.pulse();
memory1Button.off();
memory2Button.off();
memory3Button.off();
postLockControlTimer = millis();
Serial.println("Module Locked");
} else {
// UNLOCK MODULE
ModuleLocked = false;
lockControls = 0;
postLockControlTimer = millis();
liftButton.fadeOn();
lowerButton.fadeOn();
memory1Button.fadeOn();
memory2Button.fadeOn();
memory3Button.fadeOn();
liftButton.buttonInputProcessed();
lowerButton.buttonInputProcessed();
memory1Button.buttonInputProcessed();
memory2Button.buttonInputProcessed();
memory3Button.buttonInputProcessed();
Serial.println("Module UnLocked");
}
}
} else if (liftButton.getButtonState() == LOW || lowerButton.getButtonState() == LOW ){
if(lockControls == 1){
lockControls = 0;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// // Supports: Raise, Lower, Mem1, //
// DEFINE BUTTON ACTIONS WHEN UNLOCKED // Mem2, Mem3 button inputs //
// // //
/////////////////////////////////////////////////////////////////////////////////////////
if (!ModuleLocked){
////////////////////////////////////////////////////////////////////////////////////////////////////
// // Press or Press & Hold = Lower Actuator //
// LIFT BUTTON // //
// // Note: This will also stop all other commands //
// // currently active for the actuator //
// // [i.e. Raise(), goTo(), HomeSpan Calls] //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (liftButton.getButtonState() == HIGH && lowerButton.getButtonState() == LOW){
if (coffeeTable._goToState == HIGH){coffeeTable.resetGoTo();}
coffeeTable.Raise();
} else
////////////////////////////////////////////////////////////////////////////////////////////////////
// // Press or Press & Hold = Lower Actuator //
// LOWER BUTTON // //
// // Note: This will also stop all other commands //
// // currently active for the actuator //
// // [i.e. Raise(), goTo(), HomeSpan Calls] //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (lowerButton.getButtonState() == HIGH && liftButton.getButtonState() == LOW){
if (coffeeTable._goToState == HIGH){coffeeTable.resetGoTo();}
coffeeTable.Lower();
} else
////////////////////////////////////////////////////////////////////////////////////////////////////
// // //
// STOP LOGIC // When Raise, Lower and goTo() are all inactive //
// // send all control pins low //
// // //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (liftButton.getButtonState() == LOW && lowerButton.getButtonState() == LOW && coffeeTable._goToState == LOW && coffeeTable._activeState == 1){
coffeeTable.Stop();
}
// Turn on all memory button LEDs to steady on after a call to goTo has ended
////////////////////////////////////////////////////////////////////////////////////////////////////
// // //
// GOTO LOGIC // When actuator has made it to the memorized //
// // location, send LEDs back to their normal mode //
// // //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (coffeeTable._goToState == LOW && coffeeTable._previousGoToState == HIGH){
coffeeTable._previousGoToState = LOW;
memory1Button.fadeOn();
memory2Button.fadeOn();
memory3Button.fadeOn();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// // Single Press = if set, go to memorized height //
// BUTTON SEQUENCE FOR // Double Press = reset memorized height [to -1] //
// MEMORY 1 BUTTON // Long Press = set memorized height to current height //
// // //
// // LED Steady On = Memorized Height has been set //
// // LED Blink = actuator is going to Memorized Height //
// // LED Pulse = Memroized Height Not Set [currently -1] //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (memory1Button.newButtonInput()) {
if (memory1Button.getPressType() == 1){
if (memory1Button.getMemorizedHeight() != -1 && memory1Button.getMemorizedHeight() != CoffeeTableHeight){
if(coffeeTable._goToState == 0){
coffeeTable.GoTo(memory1Button.getMemorizedHeight());
coffeeTable._previousGoToState = HIGH;
memory1Button.blink();
} else {
coffeeTable.resetGoTo();
}
}
} else if (memory1Button.getPressType() == 2){
memory1Button.resetMemorizedHeight();
} else if (memory1Button.getPressType() == 3){
memory1Button.setMemorizedHeight();
}
memory1Button.buttonInputProcessed();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// // Single Press = if set, go to memorized height //
// BUTTON SEQUENCE FOR // Double Press = reset memorized height [to -1] //
// MEMORY 2 BUTTON // Long Press = set memorized height to current height //
// // //
// // LED Steady On = Memorized Height has been set //
// // LED Blink = actuator is going to Memorized Height //
// // LED Pulse = Memroized Height Not Set [currently -1] //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (memory2Button.newButtonInput()) {
if (memory2Button.getPressType() == 1){
if(memory2Button.getMemorizedHeight() != -1 && memory2Button.getMemorizedHeight() != CoffeeTableHeight){
if(coffeeTable._goToState == 0){
coffeeTable.GoTo(memory2Button.getMemorizedHeight());
coffeeTable._previousGoToState = HIGH;
memory2Button.blink();
} else {
coffeeTable.resetGoTo();
memory2Button.fadeOn();
}
}
} else if (memory2Button.getPressType() == 2){
memory2Button.resetMemorizedHeight();
} else if (memory2Button.getPressType() == 3){
memory2Button.setMemorizedHeight();
}
memory2Button.buttonInputProcessed();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// // Single Press = if set, go to memorized height //
// BUTTON SEQUENCE FOR // Double Press = reset memorized height [to -1] //
// MEMORY 3 BUTTON // Long Press = set memorized height to current height //
// // //
// // LED Steady On = Memorized Height has been set //
// // LED Blink = actuator is going to Memorized Height //
// // LED Pulse = Memroized Height Not Set [currently -1] //
////////////////////////////////////////////////////////////////////////////////////////////////////
if (memory3Button.newButtonInput()) {
if (memory3Button.getPressType() == 1){
if(memory3Button.getMemorizedHeight() != -1 && memory3Button.getMemorizedHeight() != CoffeeTableHeight){
if(coffeeTable._goToState == 0){
coffeeTable.GoTo(memory3Button.getMemorizedHeight());
coffeeTable._previousGoToState = HIGH;
memory3Button.blink();
} else {
coffeeTable.resetGoTo();
}
}
} else if (memory3Button.getPressType() == 2){
memory3Button.resetMemorizedHeight();
} else if (memory3Button.getPressType() == 3){
memory3Button.setMemorizedHeight();
}
memory3Button.buttonInputProcessed();
}
} else {
///////////////////////////////////////////////////////////////////////////////////////////////
// //
// DEFINE BUTTON ACTIONS WHEN LOCKED //
// //
///////////////////////////////////////////////////////////////////////////////////////////////
// // LIFT BUTTON HOLD controls Max Homing Sensor //
// BUTTON SEQUENCE FOR CALIBRATING // //
// MAX HOMING SENSOR // Long Press Mem1 = Calibrate Max Range Value //
// // Long Press Mem2 = Calibrate Trigger Value //
// // Long Press Mem3 = Calibrate Min Range Value //
// // //
// // Double Press Mem3 = Clear Max Range Value //
// // Double Press Mem3 = Clear Trigger Range Value //
// // Double Press Mem3 = Clear Min Range Value //
///////////////////////////////////////////////////////////////////////////////////////////////
/*if (liftButton.getButtonState() == HIGH && lowerButton.getButtonState() == LOW ) {
lowerButton.off();
if (memory1Button.newButtonInput()){
if (memory1Button.getPressType() == 3){
MaxHomingSensor.calibrateMax();
} else if (memory1Button.getPressType() == 2){
MaxHomingSensor._maxCalibrated = false;
}
memory1Button.buttonInputProcessed();
}
if (memory2Button.newButtonInput()){
if(memory2Button.getPressType() == 3){
MaxHomingSensor.calibrateTrigger();
} else if (memory2Button.getPressType() == 2){
MaxHomingSensor._triggerCalibrated = false;
}
memory2Button.buttonInputProcessed();
}
if (memory3Button.newButtonInput()){
if (memory3Button.getPressType() == 3){
MaxHomingSensor.calibrateMin();
} else if (memory3Button.getPressType() == 2){
MaxHomingSensor._minCalibrated = false;
}
memory3Button.buttonInputProcessed();
}
if (MaxHomingSensor.getError() == -1){
memory1Button.blink();
memory2Button.blink();
memory3Button.blink();
} else {
if(MaxHomingSensor.maxCalibrated()){
memory1Button.fadeOn();
} else {
memory1Button.pulse();
}
if(MaxHomingSensor.triggerCalibrated()){
memory2Button.fadeOn();
} else {
memory2Button.pulse();
}
if(MaxHomingSensor.minCalibrated()){
memory3Button.fadeOn();
} else {
memory3Button.pulse();
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// // LOWER BUTTON HOLD controls Min Homing Sensor //
// BUTTON SEQUENCE FOR CALIBRATING // //
// MIN HOMING SENSOR // Long Press Mem1 = Calibrate Max Range Value //
// // Long Press Mem2 = Calibrate Trigger Value //
// // Long Press Mem3 = Calibrate Min Range Value //
// // //
// // Double Press Mem3 = Clear Max Range Value //
// // Double Press Mem3 = Clear Trigger Range Value //
// // Double Press Mem3 = Clear Min Range Value //
///////////////////////////////////////////////////////////////////////////////////////////////
if (lowerButton.getButtonState() == HIGH && liftButton.getButtonState() == LOW ) {
liftButton.off();
if (memory1Button.newButtonInput()){
if (memory1Button.getPressType() == 3){
MinHomingSensor.calibrateMax();
} else if (memory1Button.getPressType() == 2){
MinHomingSensor._maxCalibrated = false;
}
memory1Button.buttonInputProcessed();
}
if (memory2Button.newButtonInput()){
if(memory2Button.getPressType() == 3){
MinHomingSensor.calibrateTrigger();
} else if (memory2Button.getPressType() == 2){
MinHomingSensor._triggerCalibrated = false;
}
memory2Button.buttonInputProcessed();
}
if (memory3Button.newButtonInput()){
if (memory3Button.getPressType() == 3){
MinHomingSensor.calibrateMin();
} else if (memory3Button.getPressType() == 2){
MinHomingSensor._minCalibrated = false;
}
memory3Button.buttonInputProcessed();
}
if (MinHomingSensor.getError() == -1){
memory1Button.blink();
memory2Button.blink();
memory3Button.blink();
} else {
if(MinHomingSensor.maxCalibrated()){
memory1Button.fadeOn();
} else {
memory1Button.pulse();
}
if(MinHomingSensor.triggerCalibrated()){
memory2Button.fadeOn();
} else {
memory2Button.pulse();
}
if(MinHomingSensor.minCalibrated()){
memory3Button.fadeOn();
} else {
memory3Button.pulse();
}
}
}
// return LEDs to default Locked State when lift & lower buttons are not active
if (liftButton.getButtonState() == LOW && lowerButton.getButtonState() == LOW ){
liftButton.pulse();
lowerButton.pulse();
memory1Button.fadeOff();
memory2Button.fadeOff();
memory3Button.fadeOff();
}*/
if (MaxHomingSensor.triggered()){
memory1Button.fadeOn();
} else {
memory1Button.off();
}
if (MinHomingSensor.triggered()){
memory3Button.fadeOn();
} else {
memory3Button.off();
}
}
}
if (HomeSpan_State == 1){
// if homeSpan activates, reset any automated manual functions currently active, namely coffeeTable.goTo()
coffeeTable.resetGoTo();
// blink corresponding button led if lift / actuator active via homespan
if(digitalRead(Lift_Pin) == HIGH){
if(!homespan_blink_update){
//liftButton._ledTargetWakeMode = liftButton._ledTargetMode;
liftButton.blink();
LastButtonInput = millis();
homespan_blink_update = true;
}
}
if(digitalRead(Lower_Pin) == HIGH){
if(!homespan_blink_update){
//lowerButton._ledTargetWakeMode = lowerButton._ledTargetMode;
lowerButton.blink();
LastButtonInput = millis();
homespan_blink_update = true;
}
}
} else {
if (homespan_blink_update){
NumLEDsBlink--;
liftButton.activatePreviousTargetMode();
lowerButton.activatePreviousTargetMode();
homespan_blink_update = false;
}
}
}