/* * LM: Hybrid based on examples from Adafruit and dfRobot * with a little custom coding for Wi-Fi and other things ... */ // Adafruit - // http://www.instructables.com/id/Monochrome-096-i2c-OLED-display-with-arduino-SSD13/ // dfrobot sensor - // https://www.dfrobot.com/wiki/index.php/Capacitive_Soil_Moisture_Sensor_SKU:SEN0193#Test_Code // Wi-Fi configuration - // http://www.instructables.com/id/IoT-ESP8266-Series-1-Connect-to-WIFI-Router/ // Internet of Things - // https://thingspeak.com/pages/how_to #include #include #include #include #include // Wi-Fi const char* ssid = "primary"; const char* password = "password"; const char* altID = "secondary"; const char* altPW = "password"; // From WriteVoltage.ino example: int status = WL_IDLE_STATUS; WiFiClient client; // IOT const char* host = "api.thingspeak.com"; const char* writeAPIKey = "****************"; unsigned long channelID = 12345; unsigned long uploadInterval = 300000; // milliseconds unsigned long nextUploadTime = 0; boolean uploadEnabled = true; // false for calibration & testing boolean calibrate = false; // true to enable Serial output // Display #define OLED_RESET LED_BUILTIN // LM: For OLED that I am using Adafruit_SSD1306 display(OLED_RESET); // Sensor int sensorChannel = 0; // Sensor's analog pin number int senseInterval = 1000; // Milliseconds between readings // Next two values are for capacitive sensor (dfRobot) // int minA0 = 350; // Subject to calibration adjustment // int maxA0 = 700; // Ditto // Next two values are for home-made gypsum sensor int minA0 = 460; // Subject to calibration adjustment int maxA0 = 670; // 3.3v /* int maxA0 = 980; // 5v */ int percentMoisture; // Not really, but correlated int loopCount = 0; // Used for display formatting int iotDatum = 0; // Value to be uploaded to ThingSpeak // Gypsum probe charges when power is first applied causing // a few spurious readings - Do not upload these.. boolean stable = false; // Becomes true after probe stabilizes void setup() { // Adafruit OLED display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Initialize I2C display.clearDisplay(); display.display(); delay(2000); if (calibrate) Serial.begin(9600); // Display program title display.clearDisplay(); displayText("lloydm.net", 2, 0, 0, true, true); // Decoration displayText("ground", 2, 0, 16, false, false); displayText("wetness", 2, 0, 32, false, false); displayText("studies", 2, 0, 48, false, false); delay(5000); // Connect to LAN WiFi.disconnect(); // Improves connect chances displayText("Connect...", 2, 0, 0, true, true); WiFi.begin(ssid, password); //WiFi.begin(altID, altPW); for (int i=0; i<20; i++) { // Allow 10 seconds if (WiFi.status() == WL_CONNECTED) break; delay(500); } if (WiFi.status() == WL_CONNECTED) displayText("succeeded.", 2, 0, 25, false, false); else displayText("failed.", 2, 0, 25, false, false); delay (2000); // Initialize ThingSpeak connection ThingSpeak.begin(client); } void loop() { // Read sensor, display value, optionally upload unsigned long timeNow = millis(); String inWords = ""; int val = analogRead(sensorChannel); // raw voltage if (calibrate) Serial.println(val); // for initializing min & max // Allow range to expand - never contracts! /* if (val < minA0) minA0 = val; if (val > maxA0) maxA0 = val; */ // Convenience fraction float f = (float) ((val - minA0) / (float) (maxA0 - minA0)); percentMoisture = (int) 100. * (1. - f); // Force within 0 - 100 when range expansion is disabled if (percentMoisture > 100) percentMoisture = 100; if (percentMoisture < 0) percentMoisture = 0; iotDatum = percentMoisture; if (percentMoisture < 10) inWords = "very dry"; else if (percentMoisture < 20) inWords = "dry"; else if (percentMoisture < 40) inWords = "damp"; else if (percentMoisture < 60) inWords = "wet"; else if (percentMoisture < 70) inWords = "quite wet"; else if (percentMoisture < 80) inWords = "very wet"; else if (percentMoisture < 90) inWords = "soppin wet"; else inWords = "saturated"; displayText(String(percentMoisture),2,10,25, true, true); displayText("%", 2, 40, 25, false, false); displayText(inWords, 2, 0, 45, false, false); if (loopCount % 20 == 0) loopCount = 0; displayText("Moisture", 2, loopCount, 0, false, false); if (timeNow > nextUploadTime) if ((uploadEnabled == true) && (stable == true)) { writeToThingSpeak(); nextUploadTime = timeNow + uploadInterval; } if (loopCount++ > 9) stable = true; // After start-up delay(senseInterval); } // Wrappers void displayText(String x, int iSize, int iHor, int iVer, boolean clear, boolean eol) { display.setTextSize(iSize); display.setTextColor(WHITE); display.setCursor(iHor,iVer); if (clear) display.clearDisplay(); if (eol) display.println(x); else display.print(x); display.display(); } void writeToThingSpeak() { delay(2000); // For display clarity displayText("thingspeak", 2, 0, 25, true, true); if (WiFi.status() == WL_CONNECTED) { displayText("write try", 2, 0, 45, false, false); ThingSpeak.writeField(channelID, 1, iotDatum, writeAPIKey); } delay(2000); }