#include #include // #include #include #include "settings.h" #ifdef WIFI_ENTERPRISE_ENABLED // Ref https://github.com/martinius96/ESP32-WPA2-enterprise/blob/master/ESP32_WPA2enterprise.ino #include "esp_wpa2.h" #include "esp_wifi.h" #endif #ifdef MQTT_NO_TLS #include #else #include #endif #include // These libraries need installing in the Arduino IDE Library Manager (if you install the BME280 one it should prompt for the unified sensor library automatically) #include #include // WAS D5 D6 D7 #define MULTIPLEX_PINA 17 #define MULTIPLEX_PINB 16 #define MULTIPLEX_PINC 4 // WAS A0 #define ANALOG_PIN 34 /* 000 0 001 1 010 2 011 3 100 4 101 5 110 6 111 7 */ #define SOIL_A 0 #define SOIL_B 6 #define WATER_LEVEL_A 2 #define WATER_LEVEL_B 4 #define REFERENCE_VOLTAGE 3.3 // Ref https://stackoverflow.com/a/523737/1460422 #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) #ifdef MQTT_NO_TLS WiFiClient transport; #else WiFiClientSecure transport; #endif PubSubClient mqtt; Adafruit_BME280 bme; // I2C void connect_wifi() { #ifndef WIFI_ENTERPRISE_ENABLED Serial.print("personal"); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); #else Serial.print("enterprise"); // Ref https://github.com/martinius96/ESP32-WPA2-enterprise/blob/master/ESP32_WPA2enterprise.ino // For ESP32 ONLY! For esp8266, see the code with the esp8266-last tag, which is the last commit that supports the esp8266. WiFi.disconnect(true); WiFi.mode(WIFI_STA); const char* user = WIFI_ENTERPRISE_USERNAME; const char* pass = WIFI_ENTERPRISE_PASSWORD; // 'esp_wifi_sta_wpa2_ent_set_identity' was not declared in this scope :-( esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)user, strlen(user)); esp_wifi_sta_wpa2_ent_set_username((uint8_t *)user, strlen(user)); esp_wifi_sta_wpa2_ent_set_password((uint8_t *)pass, strlen(pass)); esp_wifi_sta_wpa2_ent_enable(&config); // esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); // esp_wifi_sta_wpa2_ent_enable(&config); WiFi.begin(WIFI_SSID); #endif } float read_analog(int channel) { const char* bin = std::bitset<8>(channel).to_string().c_str(); bool b0 = bin[7] == u'1'; bool b1 = bin[6] == u'1'; bool b2 = bin[5] == u'1'; digitalWrite(MULTIPLEX_PINA, b2); digitalWrite(MULTIPLEX_PINB, b1); digitalWrite(MULTIPLEX_PINC, b0); int rawValue = analogRead(ANALOG_PIN); float parsedValue = ((float)rawValue) / 1024.0 * REFERENCE_VOLTAGE; return parsedValue; } void connect_mqtt() { if(!mqtt.connect( ("autoplant_" + String(random(0, 999999))).c_str(), MQTT_USERNAME, MQTT_PASSWORD) ) { /* Ref https://pubsubclient.knolleary.net/api#state -4 : MQTT_CONNECTION_TIMEOUT - the server didn't respond within the keepalive time -3 : MQTT_CONNECTION_LOST - the network connection was broken -2 : MQTT_CONNECT_FAILED - the network connection failed -1 : MQTT_DISCONNECTED - the client is disconnected cleanly 0 : MQTT_CONNECTED - the client is connected 1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn't support the requested version of MQTT 2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier 3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection 4 : MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected 5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect */ int error_code = mqtt.state(); Serial.println("failed, error code "+String(error_code)); while(true) delay(10000); } Serial.println("ok"); } void check_mqtt(bool reset = false) { if(mqtt.connected() == 0) { if(reset) { Serial.print("MQTT reconnect: "); connect_mqtt(); delay(2000); if(mqtt.connected() == 0) { Serial.println("failed! rebooting.\n\n"); ESP.restart(); } } else { Serial.print("MQTT reconnect: "); connect_mqtt(); } } else { Serial.println("MQTT: connection ok"); } } bool send_mqtt(String id, String sensor, float value) { // StaticJsonDocument<96> data; // // data["id"] = id; // data["sensor"] = sensor; // data["value"] = value; String payload = "{\"id\": \""+id+"\",\"sensor\": \""+sensor+"\",\"value\": "+String(value)+"}"; // int length = measureJson(&data); // char* payload = new char[length](); // serializeJson(data, payload, length); check_mqtt(false); check_mqtt(true); bool result = mqtt.publish("sensors/data", payload.c_str()); // delete[] payload; return result; } void setup() { Serial.begin(9600); delay(1000); Serial.println("\nAnalogue Soil Sensor Test"); Serial.println("========================="); Serial.print("PIN MODES: "); pinMode(MULTIPLEX_PINA, OUTPUT); pinMode(MULTIPLEX_PINB, OUTPUT); pinMode(MULTIPLEX_PINC, OUTPUT); Serial.println("ok"); // Enterprise WiFi example: // https://gist.github.com/Matheus-Garbelini/2cd780aed2eddbe17eb4adb5eca42bd6 // TODO Add support for enterprise WiFi here so we can connect to eduroam Serial.print("WIFI: "); connect_wifi(); int attempts = 0; while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); attempts++; if(attempts > 25) break; } if(WiFi.status() == WL_CONNECTED) { Serial.print("ok, IP: "); Serial.println(WiFi.localIP()); } else { // Ref https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/readme.html#check-return-codes Serial.print("failed, error code "); Serial.println(WiFi.status()); } Serial.print("MQTT: "); #ifdef MQTT_NO_TLS Serial.print("notls"); #else Serial.print("tls"); transport.setInsecure(); Serial.print("."); #endif // mqtt.setBufferSize(1000); mqtt.setClient(transport); Serial.print("."); mqtt.setServer(MQTT_SERVER, MQTT_PORT); Serial.print("."); mqtt.setKeepAlive(INTERVAL / 2); // Serial.print(MQTT_SERVER); // Serial.print(":"); // Serial.print(MQTT_PORT); // Serial.print("."); connect_mqtt(); Serial.print("BME280: "); if(!bme.begin(0x76)) { Serial.println("failed!"); } else { Serial.println("ok"); } } void loop() { float soil_a = read_analog(SOIL_A); float soil_b = read_analog(SOIL_B); float water_level_a = read_analog(WATER_LEVEL_A); float water_level_b = read_analog(WATER_LEVEL_B); float temp = bme.readTemperature(); float humidity = bme.readHumidity(); float pressure = bme.readPressure() / 100.0F; // StaticJsonDocument<96> data; if(!send_mqtt( "autoplant-a", "soil", soil_a )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-a", "water-level", water_level_a )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-b", "soil", soil_b )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-b", "water-level", water_level_b )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-a", "temperature", temp )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-a", "humidity", humidity )) Serial.println("[mqtt] Failed to send message"); if(!send_mqtt( "autoplant-a", "pressure", pressure )) Serial.println("[mqtt] Failed to send message"); // data["id"] = "autoplant-a"; // data["sensor"] = "soil"; // data["value"] = soil_a; // if(!send_mqtt(&data)) Serial.println("[mqtt] Failed to send message"); // // data["sensor"] = "water-level"; // data["value"] = water_level_a; // if(!send_mqtt(&data)) Serial.println("[mqtt] Failed to send message"); // // data["id"] = "autoplant-b"; // data["value"] = water_level_a; // if(!send_mqtt(&data)) Serial.println("[mqtt] Failed to send message"); // // data["sensor"] = "soil"; // data["value"] = soil_a; // if(!send_mqtt(&data)) Serial.println("[mqtt] Failed to send message"); Serial.print("SOIL_A\t"); Serial.println(soil_a); Serial.print("SOIL_B\t"); Serial.println(soil_b); Serial.print("WATER_LEVEL_A\t"); Serial.println(water_level_a); Serial.print("WATER_LEVEL_B\t"); Serial.println(water_level_b); Serial.println("\n\n\n\n\n"); delay(INTERVAL); }