arduino-sketches – Blame information for rev 14

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