arduino-sketches – Blame information for rev 22

Subversion Repositories:
Rev:
Rev Author Line No. Line
15 office 1 /*************************************************************************/
2 /* Copyright (C) 2022 Wizardry and Steamworks - License: GNU GPLv3 */
3 /*************************************************************************/
4  
5 // The AP to connect to via Wifi.
6 #define STA_SSID ""
7 // The AP Wifi password.
8 #define STA_PSK ""
9 // The MQTT broker to connect to.
10 #define MQTT_HOST ""
11 // The MQTT broker username.
12 #define MQTT_USERNAME ""
13 // The MQTT broker password.
14 #define MQTT_PASSWORD ""
15 // The MQTT broker port.
16 #define MQTT_PORT 1883
17 // The default MQTT client ID is "esp-CHIPID" where CHIPID is the ESP8266
18 // or ESP32 chip identifier.
19 #define MQTT_CLIENT_ID() String("esp-" + String(GET_CHIP_ID(), HEX))
20 // The authentication password to use for OTA updates.
21 #define OTA_PASSWORD ""
22 // The OTA port on which updates take place.
23 #define OTA_PORT 8266
24 // The default topic that the sketch subscribes to is "esp/CHIPID" where
25 // CHIPID is the ESP8266 or ESP32 chip identifier.
26 #define MQTT_TOPIC() String("esp/" + String(GET_CHIP_ID(), HEX))
27  
28 // Platform specific defines.
29 #if defined(ARDUINO_ARCH_ESP8266)
30 #define GET_CHIP_ID() (ESP.getChipId())
31 #elif defined(ARDUINO_ARCH_ESP32)
32 #define GET_CHIP_ID() ((uint16_t)(ESP.getEfuseMac()>>32))
33 #endif
34  
35 // Miscellaneous defines.
36 //#define CHIP_ID_HEX (String(GET_CHIP_ID()).c_str())
37 #define HOSTNAME() String("esp-" + String(GET_CHIP_ID(), HEX))
38  
39 // Platform specific libraries.
40 #if defined(ARDUINO_ARCH_ESP8266)
41 #include <ESP8266WiFi.h>
42 #include <ESP8266mDNS.h>
43 #elif defined(ARDUINO_ARCH_ESP32)
44 #include <WiFi.h>
45 #include <ESPmDNS.h>
46 #endif
47 // General libraries.
48 #include <WiFiUdp.h>
49 #include <ArduinoOTA.h>
50 #include <PubSubClient.h>
51 #include <ArduinoJson.h>
52 #if defined(ARDUINO_ARCH_ESP32)
53 #include <FS.h>
54 #include <SPIFFS.h>
55 #endif
56  
57 WiFiClient espClient;
58 PubSubClient mqttClient(espClient);
59  
60 // Define GPIO pins for supported architectures.
61 #if defined(ARDUINO_ARCH_ESP8266)
62 int PINS[] = { D0, D1, D2, D3, D4, D5, D6, D7, D8 };
63 int ANAL[] = { A0 };
64 #elif defined(ARDUINO_ARCH_ESP32)
22 office 65 int PINS[] = {
66 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
67 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
68 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
69 31, 32, 33, 34, 35, 36, 37, 38, 39
70 };
71 int ANAL[] = {
72 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0,
73 0, 12, 13, 14, 15, 0, 0, 0, 0, 0,
74 0, 0, 0, 0, 25, 26, 27, 0, 0, 0,
75 0, 32, 33, 34, 35, 36, 0, 0, 39
76 };
15 office 77 #endif
78  
79 String mqttSerialize(StaticJsonDocument<256> msg) {
80 char output[256];
81 serializeJson(msg, output, 256);
82 return String(output);
83 }
84  
85 void mqttCallback(char *topic, byte *payload, unsigned int length) {
86 String msgTopic = String(topic);
87 // payload is not null terminated and casting will not work
88 char msgPayload[length + 1];
89 snprintf(msgPayload, length + 1, "%s", payload);
90 Serial.println("Message received on topic: " + String(topic) + " with payload: " + String(msgPayload));
91  
92 // Parse the payload sent to the MQTT topic as a JSON document.
93 StaticJsonDocument<256> doc;
94 Serial.println("Deserializing message....");
95 DeserializationError error = deserializeJson(doc, msgPayload);
96 if (error) {
97 Serial.println("Failed to parse MQTT payload as JSON: " + String(error.c_str()));
98 return;
99 }
100  
101 // Do not process messages without an action key.
102 if (!doc.containsKey("action")) {
103 return;
104 }
105  
106 String action = (const char *)doc["action"];
107 if(action == "set") {
108 String state = (const char *)doc["state"];
109 const int pin = (const int)doc["pin"];
110  
111 Serial.println("Setting pin: " + String(pin) + " to state: " + String(state));
112  
113 pinMode(PINS[pin], OUTPUT);
114  
115 if (state == "on") {
116 digitalWrite(PINS[pin], HIGH);
117 int status = digitalRead(PINS[pin]);
118 Serial.println("Pin " + String(pin) + " state is now: " + String(status));
119 return;
120 }
121  
122 digitalWrite(PINS[pin], LOW);
123 int status = digitalRead(PINS[pin]);
124 Serial.println("Pin " + String(pin) + " state is now: " + String(status));
125 return;
126 }
127  
128 if(action == "get") {
129 const int pin = (const int)doc["pin"];
130  
131 Serial.println("Getting pin: " + String(pin) + " state.");
132  
133 int status = digitalRead(PINS[pin]);
134 Serial.println("Pin " + String(pin) + " state is now: " + String(status));
135  
136 // Announce the action.
137 StaticJsonDocument<256> msg;
138 msg["pin"] = pin;
139 switch(status) {
140 case 1:
141 msg["state"] = "on";
142 break;
143 case 0:
144 msg["state"] = "off";
145 break;
146 default:
147 msg["state"] = "unknown";
148 break;
149 }
150  
151 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg).c_str());
152 return;
153 }
154  
22 office 155 if(action == "push") {
156 const int pin = (const int)doc["pin"];
157 int time = (const int)doc["delay"];
158 if(time <= 0) {
159 time = 75;
160 }
161  
162 Serial.println("Pushing pin: " + String(pin) + " with intermediate delay: " + String(time));
163  
164 pinMode(PINS[pin], OUTPUT);
165 digitalWrite(PINS[pin], HIGH);
166 delay(time);
167 digitalWrite(PINS[pin], LOW);
168  
169 return;
170 }
171  
15 office 172 if(action == "measure") {
173 const int pin = (const int)doc["pin"];
174  
175 Serial.println("Getting analog pin: " + String(pin) + " state.");
176 int analogValue = analogRead(ANAL[pin]);
177  
178 Serial.println("Value of analog pin " + String(pin) + " is: " + String(analogValue));
179  
180 // Announce the analog value.
181 StaticJsonDocument<256> msg;
182 msg["pin"] = pin;
183 msg["value"] = analogValue;
184  
185 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg).c_str());
186 return;
187 }
188 }
189  
190 bool mqttConnect() {
191 Serial.println("Attempting to connect to MQTT broker: " + String(MQTT_HOST));
192 mqttClient.setServer(MQTT_HOST, MQTT_PORT);
193  
194 StaticJsonDocument<256> msg;
195 if (mqttClient.connect(MQTT_CLIENT_ID().c_str(), MQTT_USERNAME, MQTT_PASSWORD)) {
196 Serial.println("Established connection with MQTT broker using client ID: " + MQTT_CLIENT_ID());
197 mqttClient.setCallback(mqttCallback);
198 msg["action"] = "connected";
199 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg).c_str());
200 Serial.println("Attempting to subscribe to MQTT topic: " + MQTT_TOPIC());
201 if (!mqttClient.subscribe(MQTT_TOPIC().c_str())) {
202 Serial.println("Failed to subscribe to MQTT topic: " + MQTT_TOPIC());
203 return false;
204 }
205 Serial.println("Subscribed to MQTT topic: " + MQTT_TOPIC());
206 msg.clear();
207 msg["action"] = "subscribed";
208 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg).c_str());
209 return true;
210 }
211  
212 Serial.println("Connection to MQTT broker failed with MQTT client state: " + String(mqttClient.state()));
213  
214 return false;
215 }
216  
217 bool loopWifiConnected() {
218 // Process OTA loop first since emergency OTA updates might be needed.
219 ArduinoOTA.handle();
220  
221 // Process MQTT client loop.
222 if (!mqttClient.connected()) {
223 // If the connection to the MQTT broker has failed then sleep before carrying on.
224 if (!mqttConnect()) {
225 return false;
226 }
227 }
228 mqttClient.loop();
229  
230 return true;
231 }
232  
233 void setup() {
234 Serial.begin(115200);
235 Serial.println("Booted, setting up Wifi in 10s...");
236 delay(10000);
237  
238 WiFi.mode(WIFI_STA);
239 #if defined(ARDUINO_ARCH_ESP8266)
240 WiFi.hostname(HOSTNAME().c_str());
241 #elif defined(ARDUINO_ARCH_ESP32)
242 WiFi.setHostname(HOSTNAME().c_str());
243 #endif
244 WiFi.begin(STA_SSID, STA_PSK);
245 while (WiFi.waitForConnectResult() != WL_CONNECTED) {
246 Serial.println("Failed to connect to Wifi, rebooting in 5s...");
247 delay(5000);
248 ESP.restart();
249 }
250  
251 Serial.print("Connected to Wifi: ");
252 Serial.println(WiFi.localIP());
253  
254 Serial.println("Setting up OTA in 10s...");
255 delay(10000);
256  
257 // Port defaults to 8266
258 ArduinoOTA.setPort(OTA_PORT);
259  
260 // Hostname defaults to esp-[ChipID]
261 ArduinoOTA.setHostname(HOSTNAME().c_str());
262  
263 // Set the OTA password
264 ArduinoOTA.setPassword(OTA_PASSWORD);
265  
266 ArduinoOTA.onStart([]() {
267 switch (ArduinoOTA.getCommand()) {
268 case U_FLASH: // Sketch
269 Serial.println("OTA start updating sketch.");
270 break;
271 #if defined(ARDUINO_ARCH_ESP8266)
272 case U_FS:
273 #elif defined(ARDUINO_ARCH_ESP32)
274 case U_SPIFFS:
275 #endif
276 Serial.println("OTA start updating filesystem.");
277 SPIFFS.end();
278 break;
279 default:
280 Serial.println("Unknown OTA update type.");
281 break;
282 }
283 });
284 ArduinoOTA.onEnd([]() {
285 Serial.println("OTA update complete.");
286 SPIFFS.begin();
287 #if defined(ARDUINO_ARCH_ESP8266)
288 // For what it's worth, check the filesystem on ESP8266.
289 SPIFFS.check();
290 #endif
291 ESP.restart();
292 });
293 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
294 Serial.printf("OTA update progress: %u%%\r", (progress / (total / 100)));
295 });
296 ArduinoOTA.onError([](ota_error_t error) {
297 Serial.printf("OTA update error [%u]: ", error);
298 switch (error) {
299 case OTA_AUTH_ERROR:
300 Serial.println("OTA authentication failed");
301 break;
302 case OTA_BEGIN_ERROR:
303 Serial.println("OTA begin failed");
304 break;
305 case OTA_CONNECT_ERROR:
306 Serial.println("OTA connect failed");
307 break;
308 case OTA_RECEIVE_ERROR:
309 Serial.println("OTA receive failed");
310 break;
311 case OTA_END_ERROR:
312 Serial.println("OTA end failed");
313 break;
314 default:
315 Serial.println("Unknown OTA failure");
316 break;
317 }
318 ESP.restart();
319 });
320 ArduinoOTA.begin();
321  
322 // Set up MQTT client.
323 mqttClient.setServer(MQTT_HOST, MQTT_PORT);
324 mqttClient.setCallback(mqttCallback);
325  
326 // Touchdown.
327 Serial.println("Setup complete.");
328 }
329  
330 void loop() {
331 // Check the Wifi connection status.
332 int wifiStatus = WiFi.status();
333 switch (wifiStatus) {
334 case WL_CONNECTED:
335 if (!loopWifiConnected()) {
336 delay(1000);
337 break;
338 }
339 delay(1);
340 break;
341 case WL_NO_SHIELD:
342 Serial.println("No Wifi shield present.");
343 goto DEFAULT_CASE;
344 break;
345 case WL_NO_SSID_AVAIL:
346 Serial.println("Configured SSID not found.");
347 goto DEFAULT_CASE;
348 break;
349 // Temporary statuses indicating transitional states.
350 case WL_IDLE_STATUS:
351 case WL_SCAN_COMPLETED:
352 delay(1000);
353 break;
354 // Fatal Wifi statuses trigger a delayed ESP restart.
355 case WL_CONNECT_FAILED:
356 case WL_CONNECTION_LOST:
357 case WL_DISCONNECTED:
358 default:
359 Serial.println("Wifi connection failed with status: " + String(wifiStatus));
360 DEFAULT_CASE:
361 delay(10000);
362 ESP.restart();
363 break;
364 }
365 }