arduino-sketches – Blame information for rev 15

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