-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcloudpad.ino
212 lines (178 loc) · 5.86 KB
/
cloudpad.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <Keypad.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Preferences.h>
Preferences preferences;
const char WIFI_SSID[] = "TODO";
const char WIFI_PASSWORD[] = "TODO";
String MDNS_HOSTNAME = "cloudpad";
String CLOUDLIGHT = "http://cloudlight.fritz.box/"; // needs / at the end because paths will be added without /
#define ROW_NUM 4 // four rows
#define COLUMN_NUM 4 // four columns
char KEYS[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
const char KEY_ON = '*';
const char KEY_OFF = '0';
const char KEY_PROGRAM = '#'; // long press to program the current scene on a button
const char KEY_DELETE = 'D'; // long press to delete a scene from a button (e.g. to be used when button misfires once in a while)
DynamicJsonDocument scenes(2048);
byte PIN_COLUMNS[ROW_NUM] = {19, 18, 5, 17}; // GPIO19, GPIO18, GPIO5, GPIO17 connect to the column pins
byte PIN_ROWS[COLUMN_NUM] = {16, 4, 0, 2}; // GPIO16, GPIO4, GPIO0, GPIO2 connect to the row pins
int program = 0;
char program_mode = '#'; // D -> Delete, # -> Program
Keypad keypad = Keypad( makeKeymap(KEYS), PIN_ROWS, PIN_COLUMNS, ROW_NUM, COLUMN_NUM );
void setup() {
Serial.begin(9600);
preferences.begin("cloudpad", false); //false --> RW mode
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
keypad.setHoldTime(2000); // set keypad hold to 2 seconds
keypad.addEventListener(keypadEvent);
}
// NOTES
// programmed scenes need to be written to and read from preferences: https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
// web server https://lastminuteengineers.com/creating-esp32-web-server-arduino-ide/
// save and load data with preferences https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
void activate(char key) {
String scene_id = preferences.getString(String(key).c_str(), "");
if (scene_id == "") {
return;
}
DynamicJsonDocument payload(2048);
payload["id"] = scene_id;
send("activate", payload);
}
void power(bool power_status) {
DynamicJsonDocument payload(2048);
payload["power_status"] = power_status;
send("set_power", payload);
}
void delete_scene(char key) {
String empty = "";
preferences.putString(String(key).c_str(), empty);
}
void program_active_scene(char key) {
HTTPClient http;
http.begin(CLOUDLIGHT + "active_scene");
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// file found at server
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
DynamicJsonDocument response(2048);
Serial.println(payload);
// Deserialize the JSON document
DeserializationError error = deserializeJson(response, payload);
// Test if parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String active_scene = response["scene_id"];
preferences.putString(String(key).c_str(), active_scene);
} else {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
}
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
void send(String path, DynamicJsonDocument payload) {
String json_string;
serializeJson(payload, json_string);
Serial.println(json_string);
HTTPClient http;
http.begin(CLOUDLIGHT + path);
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(json_string);
// httpCode will be negative on error
if (httpCode > 0) {
// file found at server
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
Serial.println(payload);
} else {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] POST... code: %d\n", httpCode);
}
} else {
Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
void loop() {
char key = keypad.getKey();
if (key) {
Serial.println(key);
switch (key) {
case KEY_ON:
power(true);
program = 0; // power cannot be reprogrammed
break;
case KEY_OFF:
power(false);
program = 0; // power cannot be reprogrammed
break;
case KEY_PROGRAM:
program = 0; // program key cannot be reprogrammed
break;
case KEY_DELETE:
program = 0; // program key cannot be reprogrammed
break;
default:
int time_since_program_mode = millis() - program;
if ((time_since_program_mode > 0) && (time_since_program_mode < 5000)) {
if (program_mode == KEY_PROGRAM) {
program_active_scene(key);
}
if (program_mode == KEY_DELETE) {
delete_scene(key);
}
program = 0;
} // 5 seconds to program after releasing hold on the program key
else {
activate(key);
}
break;
}
}
}
void keypadEvent(KeypadEvent key){
if (key != KEY_PROGRAM && key != KEY_DELETE) {
return;
}
switch (keypad.getState()){
case PRESSED:
Serial.println("delete or program key press");
break;
case RELEASED:
Serial.println("delete or program key release");
if (program == -1) {
program = millis();
program_mode = key;
Serial.println("program_mode_active");
Serial.println(program);
}
break;
case HOLD:
Serial.println("delete or program key hold");
program = -1;
break;
}
}