Skip to content

Commit f32ddcb

Browse files
committed
Made it work
Let's just say I've changed everything and be done with it. This version has been verified to work for a set of 4 buttons and the new PCB
1 parent 7d27ab6 commit f32ddcb

24 files changed

+337
-247
lines changed

3D/Double.jpg 3DModel/Double.jpg

File renamed without changes.

3D/Single.jpg 3DModel/Single.jpg

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

Arduino/Arduino.ino

+96-44
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
/*
2-
Program written by JelleWho
3-
Board: https://dl.espressif.com/dl/package_esp32_index.json
4-
Sketch from: https://github.com/jellewie/Arduino-smart-home-switch
1+
/*Written by JelleWho https://github.com/jellewie
2+
TODO: https://github.com/jellewie/Arduino-smart-home-switch/issues
53
*/
64
#if !defined(ESP32)
75
#error "Please check if the 'DOIT ESP32 DEVKIT V1' board is selected, which can be downloaded at https://dl.espressif.com/dl/package_esp32_index.json"
@@ -11,10 +9,12 @@
119

1210
#ifdef SerialEnabled
1311
#include <rom/rtc.h> //This is for rtc_get_reset_reason
12+
#define OTA_EnabledOnBoot
1413
#define WiFiManager_SerialEnabled
1514
//#define Button_SerialEnabled
1615
//#define SerialEnabled_Speed //SP:
1716
//#define SerialEnabled_Convert //CV:
17+
#define SerialEnabled_CheckButton
1818
#endif //SerialEnabled
1919

2020
#include "WiFiManagerBefore.h" //Define what options to use/include or to hook into WiFiManager
@@ -25,14 +25,15 @@
2525
char Hub_IP[16] = "192.168.255.255"; //The url to connect to
2626
int Hub_Port = 80;
2727
const byte AB = 4; //Amount_Buttons
28-
Button ButtonA[AB] = {{34, INPUT_PULLUP, 21}, {35, INPUT_PULLUP, 19}, {32, INPUT_PULLUP, 18}, {33, INPUT_PULLUP, 5}}; //Bunch up the 4 buttons to be 1 switch set (Only used for reference pin pares, not which command is connected to which pin)
29-
Button ButtonB[AB] = {{26, INPUT_PULLUP, 23}, {27, INPUT_PULLUP, 22}, {14, INPUT_PULLUP, 4}, {12, INPUT_PULLUP, 15}}; // ^
28+
Button ButtonA[AB] = {{32, INPUT_PULLUP, 21}, {33, INPUT_PULLUP, 19}, {25, INPUT_PULLUP, 18}, {26, INPUT_PULLUP, 5}}; //Bunch up the 4 buttons to be 1 switch set (Only used for reference pin pares, not which command is connected to which pin)
29+
Button ButtonB[AB] = {{27, INPUT_PULLUP, 23}, {14, INPUT_PULLUP, 22}, {12, INPUT_PULLUP, 4}, {13, INPUT_PULLUP, 15}}; // ^
3030
String Path_A[AB] = {"", "", "", ""}; //SOFT_SETTING
3131
String Path_B[AB] = {"", "", "", ""}; // ^
3232
String Json_A[AB] = {"", "", "", ""}; //SOFT_SETTING
3333
String Json_B[AB] = {"", "", "", ""}; // ^
3434
byte RotationA = NORMAL; //SOFT_SETTING Rotation of the PCB seen from the case
3535
byte RotationB = UNUSED; // ^ RIGHT=PCB 90° clockwise to case
36+
const byte BootButtonsWaitMs = 100; //Wait for a period of this length on boot for the buttons to be NOT pressed
3637

3738
#include "WiFiManagerLater.h" //Define options of WiFiManager (can also be done before), but WiFiManager can also be called here (example for DoRequest)
3839

@@ -62,39 +63,41 @@ void setup() {
6263
//===========================================================================
6364
//Wait for all buttons to be NOT pressed
6465
//===========================================================================
65-
byte ButtonPressedID = 1;
66-
while (ButtonPressedID > 0) {
67-
#ifdef SerialEnabled
68-
Serial.println("Waiting on a button(s) " + String(ButtonPressedID, BIN) + " before starting up");
69-
#endif //SerialEnabled
70-
ButtonPressedID = 0; //Set to NOT pressed by default, will be overwritten
66+
unsigned long WaitUntil = millis() + BootButtonsWaitMs;
67+
while (WaitUntil > millis()) {
68+
byte ButtonStatesA = 0, ButtonStatesB = 0;
69+
for (byte i = 0; i < AB; i++) {
70+
if (ButtonA[i].CheckButton().Pressed) {
71+
bitSet(ButtonStatesA, i);
72+
WaitUntil = millis() + BootButtonsWaitMs;
73+
}
74+
if (RotationB != UNUSED) {
75+
if (ButtonB[i].CheckButton().Pressed) {
76+
bitSet(ButtonStatesB, i);
77+
WaitUntil = millis() + BootButtonsWaitMs;
78+
}
79+
}
80+
}
7181
static unsigned long LastTimeA = 0; //Set to 0, so the first call is FALSE
72-
if (TickEveryXms(&LastTimeA, 50)) { //Wait here for 50ms (so an error blink would look nice)
73-
//Returns the button states in bits; Like 0000<button1><b2><b3><b4> where 1 is HIGH and 0 is LOW
74-
//Example '00001001' = Buttons 1 and 4 are HIGH (Note we count from LSB)
75-
byte ButtonID = 0;
82+
if (TickEveryXms(&LastTimeA, 50)) { //Execute every 50ms (so an error blink would look nice)
7683
for (byte i = 0; i < AB; i++) {
77-
ButtonID = ButtonID << 1; //Move bits 1 to the left (it’s like *2)
78-
Button_Time Value = ButtonA[i].CheckButton();
79-
if (Value.Pressed) {
80-
ButtonID += 1; //Flag this button as on
84+
if (bitRead(ButtonStatesA, i)) {
85+
bitClear(ButtonStatesA, i);
8186
if (ButtonA[i].PIN_LED > 0) digitalWrite(ButtonA[i].PIN_LED, !digitalRead(ButtonA[i].PIN_LED));
82-
} else if (ButtonA[i].PIN_LED > 0)
83-
digitalWrite(ButtonA[i].PIN_LED, LOW);
84-
}
85-
if (RotationB != UNUSED) {
86-
for (byte i = 0; i < AB; i++) {
87-
ButtonID = ButtonID << 1; //Move bits 1 to the left (it’s like *2)
88-
Button_Time Value = ButtonB[i].CheckButton();
89-
if (Value.Pressed) {
90-
ButtonID += 1; //Flag this button as on
91-
if (ButtonA[i].PIN_LED > 0) digitalWrite(ButtonB[i].PIN_LED, !digitalRead(ButtonB[i].PIN_LED));
92-
} else if (ButtonB[i].PIN_LED > 0)
93-
digitalWrite(ButtonB[i].PIN_LED, LOW);
87+
} else {
88+
if (ButtonA[i].PIN_LED > 0) digitalWrite(ButtonA[i].PIN_LED, LOW);
89+
}
90+
if (bitRead(ButtonStatesB, i)) {
91+
bitClear(ButtonStatesB, i);
92+
if (ButtonB[i].PIN_LED > 0) digitalWrite(ButtonB[i].PIN_LED, !digitalRead(ButtonB[i].PIN_LED));
93+
} else {
94+
if (ButtonB[i].PIN_LED > 0) digitalWrite(ButtonB[i].PIN_LED, LOW);
9495
}
9596
}
96-
ButtonPressedID = ButtonID; //Get the button state, here 1 is HIGH in the form of '0000<Button 1><2><3><4> '
9797
}
98+
#ifdef SerialEnabled
99+
Serial.println("Waiting on a button(s) " + String(ButtonStatesA, BIN) + "_" + String(ButtonStatesB, BIN) + " before starting up, wait ms=" + String(WaitUntil - millis()));
100+
#endif //SerialEnabled
98101
}
99102
for (byte i = 0; i < AB; i++) {
100103
digitalWrite(ButtonA[i].PIN_LED, LOW); //Make sure all LED's are off
@@ -104,6 +107,7 @@ void setup() {
104107
//===========================================================================
105108
//Start WIFI
106109
//===========================================================================
110+
server.on("/test", handle_Test); //Declair the TEST urls
107111
byte Answer = WiFiManager.Start();
108112
if (Answer != 1) {
109113
#ifdef SerialEnabled
@@ -114,8 +118,14 @@ void setup() {
114118
WiFiManager.OTA_Enabled = false;
115119
WiFiManager.EnableSetup(true); //Start the server (if you also need it for other stuff)
116120
//===========================================================================
117-
//Get Reset reason (This could be/is useful for power outage)
121+
//Get Reset reason (This could be/is useful for power outage?)
118122
//===========================================================================
123+
#ifdef OTA_EnabledOnBoot
124+
//WiFiManager.OTA_Enabled = true;
125+
# ifdef SerialEnabled
126+
Serial.println("Due to 'OTA_EnabledOnBoot' debug mode, OTA is enabled after boot by default");
127+
# endif //SerialEnabled
128+
#endif //OtaEnabledOnBoot
119129
#ifdef SerialEnabled
120130
Serial.println("Done with boot, resetted due to " + ResetReasonToString(GetResetReason()) + " boottime=" + String(millis()));
121131
#endif //SerialEnabled
@@ -139,21 +149,31 @@ void loop() {
139149

140150
for (byte i = 0; i < AB; i++) {
141151
Check(ButtonA[i].CheckButton(), //The button state (contains info like if its just pressed and such)
142-
Path_A[i] == "" ? Path_A[1] : Path_A[RotatedButtonID(RotationA, i)] , //The URL, if(non given){default to first given path}
143-
Json_A[RotatedButtonID(RotationA, i)], //The command to execute
152+
Path_A[RotatedButtonID(RotationA, i)] == "" ? Path_A[0] : Path_A[RotatedButtonID(RotationA, i)] , //The URL, if(non given){default to first given path}
153+
Json_A[RotatedButtonID(RotationA, i)], //The command to execute
144154
ButtonA[i].PIN_LED); //The LED corospanding to this button
145155
if (RotationB != UNUSED)
146156
Check(ButtonB[i].CheckButton(),
147-
Path_B[i] == "" ? Path_B[1] : Path_A[RotatedButtonID(RotationB, i)] ,
157+
Path_B[RotatedButtonID(RotationB, i)] == "" ? Path_B[0] : Path_B[RotatedButtonID(RotationB, i)] ,
148158
Json_B[RotatedButtonID(RotationB, i)],
149159
ButtonB[i].PIN_LED);
150160
}
151161
}
152162
//===========================================================================
153-
void Check(Button_Time Value, String Path, String Json, byte LEDpin) {
154-
#ifdef SerialEnabled
155-
Serial.println(String(Value.Pressed) + " S=" + String(Value.StartPress) + " L=" + String(Value.PressedLong) + " SL=" + String(Value.StartLongPress) + " LEDpin=" + String(LEDpin) + " Path=" + String(Path) + " Json=" + String(Json));
156-
#endif //SerialEnabled
163+
byte Check(Button_Time Value, String Path, String Json, byte LEDpin) {
164+
byte Answer = 0;
165+
#ifdef SerialEnabled_CheckButton
166+
if (Value.StartPress or Value.Pressed or
167+
Value.StartLongPress or Value.PressedLong or
168+
Value.StartDoublePress or Value.DoublePress or
169+
Value.StartRelease) //If there was an update
170+
Serial.println("CB: S" + String(Value.StartPress) + "_" + String(Value.Pressed) + " "
171+
"L" + String(Value.StartLongPress) + "_" + String(Value.PressedLong) + " "
172+
"D" + String(Value.StartDoublePress) + "_" + String(Value.DoublePress) + " "
173+
"R" + String(Value.StartRelease) + "_" + String(Value.PressEnded) + " "
174+
"T" + String(Value.PressedTime) + " "
175+
"LEDpin=" + String(LEDpin) + " Path=" + String(Path) + " Json=" + String(Json));
176+
#endif //SerialEnabled_CheckButton
157177

158178
if (Value.StartPress) { //If button is just pressed in
159179

@@ -162,10 +182,9 @@ void Check(Button_Time Value, String Path, String Json, byte LEDpin) {
162182
#endif //SerialEnabled_Speed
163183

164184
if (LEDpin > 0) digitalWrite(LEDpin, HIGH); //If a LED pin was given; Set that buttons LED on
165-
byte Answer = WiFiManager.DoRequest(Hub_IP, Hub_Port, Path, Json);
185+
Answer = WiFiManager.DoRequest(Hub_IP, Hub_Port, Path, Json);
166186
if (LEDpin > 0) digitalWrite(LEDpin, LOW); //If a LED pin was given; Set that buttons LED off
167187

168-
Answer = Answer + 0; //mask compiler warning if 'SerialEnabled' is not defined
169188
#ifdef SerialEnabled
170189
Serial.println("DoRequest executed with responce code '" + DoRequestReasonToString(Answer) + "'"); //The return codes can be found in "WiFiManager.cpp" in "CWiFiManager::DoRequest("
171190
# ifdef SerialEnabled_Speed
@@ -176,10 +195,13 @@ void Check(Button_Time Value, String Path, String Json, byte LEDpin) {
176195
} else if (Value.StartLongPress) {
177196
WiFiManager.OTA_Enabled = !WiFiManager.OTA_Enabled; //Toggle OTA on/off
178197
if (LEDpin > 0) digitalWrite(LEDpin, LOW); //If a LED pin was given; Set that buttons LED off
198+
#ifdef SerialEnabled
199+
Serial.println("Toggled OTA " + String(WiFiManager.OTA_Enabled ? "ON" : "OFF"));
200+
#endif //SerialEnabled
179201
}
180202
if (Value.PressedLong) { //If it is/was a long press
181203
if (Value.Pressed) { //If we are still pressing
182-
if (Value.PressedTime > Time_ESPrestartMS - 1000) {
204+
if (Value.PressedTime > Time_ESPrestartMS - 2000) {
183205
if (LEDpin > 0) BlinkEveryMs(LEDpin, 10); //If a LED pin was given; Blink that button LED
184206
} else
185207
digitalWrite(LED_BUILTIN, HIGH);
@@ -188,6 +210,7 @@ void Check(Button_Time Value, String Path, String Json, byte LEDpin) {
188210
if (LEDpin > 0) digitalWrite(LEDpin, LOW); //If a LED pin was given; Blink that button LED
189211
}
190212
}
213+
return Answer;
191214
}
192215
byte RotatedButtonID(byte Rotation, byte i) {
193216
switch (Rotation) {
@@ -217,6 +240,35 @@ byte RotatedButtonID(byte Rotation, byte i) {
217240
}
218241
return 0;
219242
}
243+
void handle_Test() {
244+
byte i = 0;
245+
char m = 'A';
246+
if (server.args()) {
247+
String ArguName = server.argName(i);
248+
ArguName.toUpperCase();
249+
ArguName.substring(0, 1);
250+
if (ArguName == "B") m = 'B';
251+
i = server.arg(i).toInt();
252+
if (i > 4) i = 3;
253+
if (i < 1) i = 1;
254+
}
255+
String Path = Path_A[RotatedButtonID(RotationA, i - 1)] == "" ? Path_A[0] : Path_A[RotatedButtonID(RotationA, i - 1)];
256+
String Json = Json_A[RotatedButtonID(RotationA, i - 1)];
257+
byte LEDpin = ButtonA[i].PIN_LED;
258+
if (m == 'B') {
259+
Path = Path_B[RotatedButtonID(RotationB, i - 1)] == "" ? Path_B[0] : Path_B[RotatedButtonID(RotationB, i - 1)];
260+
Json = Json_B[RotatedButtonID(RotationB, i - 1)];
261+
LEDpin = ButtonB[i].PIN_LED;
262+
}
263+
264+
Button_Time Dummy;
265+
Dummy.StartPress = true;
266+
byte Answer = Check(Dummy, Path, Json, LEDpin);
267+
268+
server.send(200, "text/plain", "DoRequest " + String(m) + String(i) + " with result " + String(Answer) + "\n\n"
269+
"" + String(Hub_IP) + ":" + String(Hub_Port) + String(Path) + "\n"
270+
"" + String(Json));
271+
}
220272
//===========================================================================
221273
void ISR_A0() {
222274
ButtonA[0].Pinchange();

Arduino/Button/Button.cpp

+22-18
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
Button::Button(const byte _PIN_Button, const byte _ButtonPinMode, const byte _PIN_LED) {
55
this->PIN_Button = _PIN_Button; //Set the pointer, so we point to the pins
66
this->PIN_LED = _PIN_LED; //Set the pointer, so we point to the pins
7-
pinMode(PIN_Button, _ButtonPinMode); //Set the button pin as INPUT
8-
if (_ButtonPinMode == INPUT_PULLUP) HighState = LOW; //If we have an inverse button (Pushed is 0V/GNS, and released/default is HIGH)
7+
pinMode(PIN_Button, _ButtonPinMode); //Set the button pin as INPUT
8+
if (_ButtonPinMode == INPUT_PULLUP) HighState = LOW; //If we have an inverse button (Pushed is 0V/GNS, and released/default is HIGH)
99
if (PIN_LED != 0) //If a LED pin is given
1010
pinMode(PIN_LED, OUTPUT); //Set the LED pin as output
1111
Pinchange(); //Init the pin, this will make sure it starts in the right HIGH or LOW state
@@ -14,8 +14,6 @@ Button_Time Button::CheckButton() {
1414
if (!State.PressEnded)
1515
State.PressedTime = millis() - ButtonStartTime; //If still pushing; give back pushed time so far
1616
if (State.PressedTime > Time_StartLongPressMS) { //if it was/is a long press
17-
if (State.PressedTime > Time_ESPrestartMS) //if it was/is a way to long press
18-
ESP.restart(); //Restart the ESP
1917
State.PressedLong = true; //Flag it's a long pres
2018
if (!StartLongFlagged) { //If it's started to be a long press
2119
State.StartLongPress = true; //Flag that this was a long press
@@ -28,6 +26,7 @@ Button_Time Button::CheckButton() {
2826
if (State.PressEnded) {
2927
State.Pressed = false;
3028
State.DoublePress = false;
29+
StartLongFlagged = false;
3130
}
3231

3332
Button_Time ReturnValue = State;
@@ -44,10 +43,10 @@ Button_Time Button::CheckButton() {
4443
}
4544
#ifdef Button_SerialEnabled
4645
Serial.println("BU:CheckButton="
47-
"S" + String(State.StartPress) + "." + String(State.Pressed) + "_"
48-
"L" + String(State.StartLongPress) + "." + String(State.PressedLong) + "_"
49-
"D" + String(State.StartDoublePress) + "." + String(State.DoublePress) + "_"
50-
"R" + String(State.StartRelease) + "." + String(State.PressEnded) + "_"
46+
"S" + String(State.StartPress) + "_" + String(State.Pressed) + " "
47+
"L" + String(State.StartLongPress) + "_" + String(State.PressedLong) + " "
48+
"D" + String(State.StartDoublePress) + "_" + String(State.DoublePress) + " "
49+
"R" + String(State.StartRelease) + "_" + String(State.PressEnded) + " "
5150
"T" + String(State.PressedTime));
5251
#endif //Button_SerialEnabled
5352
return ReturnValue;
@@ -56,16 +55,21 @@ void Button::Pinchange() {
5655
//We do not need special overflow code here. Here I will show you with 4 bits as example
5756
//ButtonStartTime = 12(1100) millis = 3(0011) PressedTime should be = 7 (13,14,15,0,1,2,3 = 7 ticks)
5857
//PressedTime = millis() - ButtonStartTime[i] = 3-12=-9(1111 0111) overflow! = 7(0111) Thus there is nothing to fix, it just works
59-
if (digitalRead(PIN_Button) == HighState) { //If button is pressed
58+
bool NewState = digitalRead(PIN_Button); //Filter all double reportings (Like UP,UP,UP)
59+
if (NewState == OldState)
60+
return;
61+
OldState = NewState;
62+
63+
if (NewState == HighState) { //If button is pressed
6064
State.PressedTime = 0;
6165
State.Pressed = true;
6266
State.PressEnded = false;
63-
StartLongFlagged = false;
67+
6468
StartReleaseFlagged = false;
6569
unsigned long ElapsedTimeSinceLast = millis() - LastButtonEndTime;
66-
#ifdef Button_SerialEnabled
67-
Serial.println("BU:Up TsinceLast=" + String(ElapsedTimeSinceLast));
68-
#endif //Button_SerialEnabled
70+
#ifdef Button_SerialEnabledExtra
71+
Serial.println("BU:^T" + String(ElapsedTimeSinceLast));
72+
#endif //Button_SerialEnabledExtra
6973
if (ElapsedTimeSinceLast > Time_RejectStarts) {
7074
ButtonStartTime = millis(); //Save the start time
7175
State.StartPress = true;
@@ -74,15 +78,15 @@ void Button::Pinchange() {
7478
State.DoublePress = true;
7579
}
7680
}
77-
} else if (millis() - ButtonStartTime > Time_ESPrestartMS) { //If the button was pressed longer than 10 seconds
78-
ESP.restart(); //Restart the ESP
7981
} else {
8082
State.PressEnded = true;
8183
State.PressedTime = millis() - ButtonStartTime;
84+
if (State.PressedTime > Time_ESPrestartMS) //If the button was pressed longer than 10 seconds
85+
ESP.restart(); //Restart the ESP
8286
LastButtonEndTime = millis();
83-
#ifdef Button_SerialEnabled
84-
Serial.println("BU:Down PressT=" + String(State.PressedTime));
85-
#endif //Button_SerialEnabled
87+
#ifdef Button_SerialEnabledExtra
88+
Serial.println("BU:vT" + String(State.PressedTime));
89+
#endif //Button_SerialEnabledExtra
8690
}
8791
}
8892

0 commit comments

Comments
 (0)