arduino-sketches – Blame information for rev 4

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*************************************************************************/
2 /* Copyright (C) 2020 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 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  
4 office 80 const char* mqttSerialize(StaticJsonDocument<256> msg) {
81 char message[256];
1 office 82 serializeJson(msg, message);
4 office 83 return (const char*) message;
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  
102 // Do not process messages with an action key.
103 if (doc.containsKey("action")) {
104 return;
105 }
106  
107 String state = (const char *)doc["state"];
108 const int pin = (const int)doc["pin"];
109  
110 Serial.println("Setting pin: " + String(pin) + " to state: " + String(state));
111 // Announce the action.
4 office 112 StaticJsonDocument<256> msg;
1 office 113 msg["pin"] = pin;
114 msg["state"] = state;
115 msg["action"] = "set";
116 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg));
117 pinMode(PINS[pin], OUTPUT);
118 if (state == "on") {
119 digitalWrite(PINS[pin], HIGH);
120 Serial.println("Pin set to HIGH");
121 return;
122 }
123  
124 digitalWrite(PINS[pin], LOW);
125 Serial.println("Pin set to LOW");
126 }
127  
128 bool mqttConnect() {
129 Serial.println("Attempting to connect to MQTT broker: " + String(mqtt_host));
130 mqttClient.setServer(mqtt_host, mqtt_port);
131  
132 StaticJsonDocument<255> msg;
133 if (mqttClient.connect(MQTT_CLIENT_ID().c_str(), mqtt_username, mqtt_password)) {
134 Serial.println("Established connection with MQTT broker using client ID: " + MQTT_CLIENT_ID());
135 mqttClient.setCallback(mqttCallback);
136 msg["action"] = "connected";
137 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg));
138 Serial.println("Attempting to subscribe to MQTT topic: " + MQTT_TOPIC());
139 if (!mqttClient.subscribe(MQTT_TOPIC().c_str())) {
140 Serial.println("Failed to subscribe to MQTT topic: " + MQTT_TOPIC());
141 return false;
142 }
143 Serial.println("Subscribed to MQTT topic: " + MQTT_TOPIC());
144 msg.clear();
145 msg["action"] = "subscribed";
146 mqttClient.publish(MQTT_TOPIC().c_str(), mqttSerialize(msg));
147 return true;
148 }
149 else {
150 Serial.println("Connection to MQTT broker failed with MQTT client state: " + String(mqttClient.state()));
151 }
152  
153 return false;
154 }
155  
156 bool loopWifiConnected() {
157 // Process OTA loop first since emergency OTA updates might be needed.
158 ArduinoOTA.handle();
159  
160 // Process MQTT client loop.
161 if (!mqttClient.connected()) {
162 // If the connection to the MQTT broker has failed then sleep before carrying on.
163 if (!mqttConnect()) {
164 return false;
165 }
166 }
167 mqttClient.loop();
168  
169 return true;
170 }
171  
172 void setup() {
173 Serial.begin(115200);
174 Serial.println("Booted, setting up Wifi in 10s...");
175 delay(10000);
176  
177 WiFi.mode(WIFI_STA);
178 #if defined(ARDUINO_ARCH_ESP8266)
179 WiFi.hostname(HOSTNAME().c_str());
180 #elif defined(ARDUINO_ARCH_ESP32)
181 WiFi.setHostname(HOSTNAME().c_str());
182 #endif
183 WiFi.begin(sta_ssid, sta_psk);
184 while (WiFi.waitForConnectResult() != WL_CONNECTED) {
185 Serial.println("Failed to connect to Wifi, rebooting in 5s...");
186 delay(5000);
187 ESP.restart();
188 }
189  
190 Serial.print("Connected to Wifi: ");
191 Serial.println(WiFi.localIP());
192  
193 Serial.println("Setting up OTA in 10s...");
194 delay(10000);
195  
196 // Port defaults to 8266
197 ArduinoOTA.setPort(ota_port);
198  
199 // Hostname defaults to esp-[ChipID]
200 ArduinoOTA.setHostname(HOSTNAME().c_str());
201  
202 // Set the OTA password
203 ArduinoOTA.setPassword(ota_password);
204  
205 ArduinoOTA.onStart([]() {
206 switch (ArduinoOTA.getCommand()) {
207 case U_FLASH: // Sketch
208 Serial.println("OTA start updating sketch.");
209 break;
210 #if defined(ARDUINO_ARCH_ESP8266)
211 case U_FS:
212 #elif defined(ARDUINO_ARCH_ESP32)
213 case U_SPIFFS:
214 #endif
215 Serial.println("OTA start updating filesystem.");
216 SPIFFS.end();
217 break;
218 default:
219 Serial.println("Unknown OTA update type.");
220 break;
221 }
222 });
223 ArduinoOTA.onEnd([]() {
224 Serial.println("OTA update complete.");
225 SPIFFS.begin();
226 #if defined(ARDUINO_ARCH_ESP8266)
227 // For what it's worth, check the filesystem on ESP8266.
228 SPIFFS.check();
229 #endif
230 ESP.restart();
231 });
232 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
233 Serial.printf("OTA update progress: %u%%\r", (progress / (total / 100)));
234 });
235 ArduinoOTA.onError([](ota_error_t error) {
236 Serial.printf("OTA update error [%u]: ", error);
237 switch (error) {
238 case OTA_AUTH_ERROR:
239 Serial.println("OTA authentication failed");
240 break;
241 case OTA_BEGIN_ERROR:
242 Serial.println("OTA begin failed");
243 break;
244 case OTA_CONNECT_ERROR:
245 Serial.println("OTA connect failed");
246 break;
247 case OTA_RECEIVE_ERROR:
248 Serial.println("OTA receive failed");
249 break;
250 case OTA_END_ERROR:
251 Serial.println("OTA end failed");
252 break;
253 default:
254 Serial.println("Unknown OTA failure");
255 break;
256 }
257 ESP.restart();
258 });
259 ArduinoOTA.begin();
260  
261 // Set up MQTT client.
262 mqttClient.setServer(mqtt_host, mqtt_port);
263 mqttClient.setCallback(mqttCallback);
264  
265 // Touchdown.
266 Serial.println("Setup complete.");
267 }
268  
269 void loop() {
270 // Check the Wifi connection status.
271 int wifiStatus = WiFi.status();
272 switch (wifiStatus) {
273 case WL_CONNECTED:
274 if (!loopWifiConnected()) {
275 delay(1000);
276 break;
277 }
278 delay(1);
279 break;
280 case WL_NO_SHIELD:
281 Serial.println("No Wifi shield present.");
282 goto DEFAULT_CASE;
283 break;
284 case WL_NO_SSID_AVAIL:
285 Serial.println("Configured SSID not found.");
286 goto DEFAULT_CASE;
287 break;
288 // Temporary statuses indicating transitional states.
289 case WL_IDLE_STATUS:
290 case WL_SCAN_COMPLETED:
291 delay(1000);
292 break;
293 // Fatal Wifi statuses trigger a delayed ESP restart.
294 case WL_CONNECT_FAILED:
295 case WL_CONNECTION_LOST:
296 case WL_DISCONNECTED:
297 default:
298 Serial.println("Wifi connection failed with status: " + String(wifiStatus));
299 DEFAULT_CASE:
300 delay(10000);
301 ESP.restart();
302 break;
303 }
304 }