//Coded by J.Drage, 26-Aug-2020 STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY)); SYSTEM_THREAD(ENABLED); //STARTUP(WiFi.selectAntenna(ANT_EXTERNAL)); // Selects the external u.FL antenna; this line of code is disabled for the cellular version of the meter #include #include "DS18.h" //-------------------------------------------------------------------------- // Define pins on the IoT device: //-------------------------------------------------------------------------- #define WLsensor_power D2 // D2 pin powers the water level sensor on #define WLsensor_data D3 // D3 is pin for data output from the water level sensor DS18 tempSensor(D5); // D5 is pin for temperature data //-------------------------------------------------------------------------- // User Variables - to be entered by user for each water well //-------------------------------------------------------------------------- int MeasureTime=120; // Time between sensor measurements (seconds) int DelayTime=5; // Delay time until the first sensor measurement is taken, cannot be less than 5 (seconds) int ConnectTime=90000; // Time allowed IoT device to connect to the cloud before going back to sleep; cannot be less than 90,000 (milliseconds)for cellular version of the meter double Datum=0; // Datum elevation; typically top of well casing is used (metres) double HangDown=0; // Distance from datum to sensor (metres) double WellDepth=0; // Depth of well; measured from datum (metres) double K=0.3; // Cell constant for EC sensor (1/cm) double calibration=100; // Conductivity of calibration solution, compensated to 25 degrees C (uS/cm) //-------------------------------------------------------------------------- // Code Variables - for code calculations, these are not modified by user //-------------------------------------------------------------------------- double WLSensorValue=0; // Reading from water level sensor (mm) double DepthToWater=0; // Depth to water; measured by the sensor and then converted from mm to m (metres) double GWelevation=0; // Water table elevation; calculated by code (metres) double AvailableDD=0; // Available drawdown in well (metres) retained int Counter=0; // A counter used to activate the one-time only user specified delay time (no units) int Counter2=0; // A counter for the Temperature measurement loop (no units) double calculatedK=0; // Calculated cell constant of the EC sensor (1/cm) double temp=0; // Temperature measured by the thermometer (degrees C) double Vprobe=0; // Voltage from EC sensor as read from AO pin (volts) double R=0; // Resistance calculated from voltage on EC sensor (ohms) double EC=0; // Conductivity of water; not temperature compensated (S/cm) double EC25=0; // Conductivity of water compensated to 25 degrees C (uS/cm) double TDS=0; // TDS calculated from EC25 reading using conversion factor of 0.59 (mg/L) //-------------------------------------------------------------------------- void setup() { //-------------------------------------------------------------------------- // Configure pins on the IoT device //-------------------------------------------------------------------------- PMIC().disableCharging(); // This code line is only used to disable battery charging for the cellular version of the meter pinMode(WLsensor_power, OUTPUT); pinMode(WLsensor_data, INPUT); Serial.begin(9600); pinMode(D6, OUTPUT); // D6 is pin for Temperature sensor power pinMode(D7, OUTPUT); // D7 is pin for LED pinMode(A0, INPUT); // A0 is pin for EC sensor data pinMode(A1, OUTPUT); // A1 is pin for EC sensor gnd pinMode(A2, OUTPUT); // A2 is pin for EC sensor power, via voltage divider resistor digitalWrite(A1, LOW); // A1 pin is gnd for EC sensor, set to LOW permanently pinMode(A4, OUTPUT); // A4 is pin for Temperature sensor gnd digitalWrite(A4, LOW); // A4 is gnd on Temperature sensor, set to LOW permanently Particle.variable("CalculatedK", calculatedK); delay (100); } void loop() { //-------------------------------------------------------------------------- // Check that IoT device is connected to the cloud; if not then go to sleep to preserve the batteries //-------------------------------------------------------------------------- if( !Particle.connected() ) { Particle.connect(); if ( !waitFor(Particle.connected, ConnectTime) ) { delay(20000); System.sleep(SLEEP_MODE_DEEP, MeasureTime); } } //-------------------------------------------------------------------------- // Delay the first water level measurement by the user specified delay time //-------------------------------------------------------------------------- if (Counter==1) { Counter++; delay(20000); System.sleep(SLEEP_MODE_DEEP, DelayTime); } Counter++; Counter=0; //-------------------------------------------------------------------------- // Read the water level from the sensor //-------------------------------------------------------------------------- digitalWrite(WLsensor_power, HIGH); delay(1000); WLSensorValue = pulseIn(WLsensor_data, HIGH); digitalWrite(WLsensor_power, LOW); DepthToWater = WLSensorValue/1000; GWelevation = Datum-HangDown-DepthToWater; AvailableDD = WellDepth-HangDown-DepthToWater; //-------------------------------------------------------------------------- // Read the Temperature and EC sensors //-------------------------------------------------------------------------- digitalWrite(D6, HIGH); delay(1000); Counter2=0; while (!tempSensor.read()) { digitalWrite(D6, LOW); delay(1000); digitalWrite(D6, HIGH); Counter2++; if (Counter2==10) { delay(20000); // If the Temperature sensor fails to take a measurement after 10 attempts, go to sleep without reporting the result System.sleep(SLEEP_MODE_DEEP, MeasureTime); } } // Blink the LED to indicate a Temperature measurement has been taken digitalWrite(D7, HIGH); temp = (tempSensor.celsius()); digitalWrite(D6, LOW); delay(1000); digitalWrite(D7, LOW); // Take an EC sensor reading digitalWrite(A2, HIGH); Vprobe=analogRead(A0)*(3.3/4095); digitalWrite(A2, LOW); // Calculate EC25 R=(1000*Vprobe)/(3.3-Vprobe); // The 1000 Ohm value is for a 1000 Ohm resistor (1.0k) between the EC sensor pins A0 and A2; change this value if a different resistor is used EC=K/R; EC25=1000000*EC/(1+0.02*(temp-25)); calculatedK=calibration*(1+0.02*(temp-25))*R/1000000; TDS=0.59*EC25; //-------------------------------------------------------------------------- // Check if the water depth is out of sensor range; if it is out of range, go to sleep without reporting the result; sensor range is 0.3-5m (5m model) and 0.5-10m (10m model) //-------------------------------------------------------------------------- if (DepthToWater<0.31) { delay(20000); System.sleep(SLEEP_MODE_DEEP, MeasureTime); } if (DepthToWater>4.99) { delay(20000); System.sleep(SLEEP_MODE_DEEP, MeasureTime); } //-------------------------------------------------------------------------- // Send the water level, EC and Temperature data to ThingSpeak.com //-------------------------------------------------------------------------- Particle.publish("Insert_Webhook_Name_Inside_These_Quotes", "{ \"GWelevation\": \"" + String(GWelevation, 2) + "\", \"AvailableDD\": \"" + String(AvailableDD, 2) + "\", \"temp\": \"" + String(temp, 1) + "\", \"EC25\": \"" + String(EC25, 1) + "\", \"TDS\": \"" + String(TDS, 1) + "\"}", 60, PRIVATE); delay(20000); System.sleep(SLEEP_MODE_DEEP, MeasureTime); }