arduino-sketches – Blame information for rev 7

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