arduino-sketches – Blame information for rev 8

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