Firmware update required

Hello All,

I have a watering system in production but its watering when it shouldnt, this only started yesterday to be fair and could be because the sensor got slightly wet when I watered in some seeds although it didnt seem to affect it at the time just a long time afterwards

so I attempted to tune the sketch over the air and now its asking me to update the firmware, which I really dont want to do as its in production and would mean taking it all apart and luging it in

anyone else had this issue and overcome it?

this is the code I am trying to run in

  Basil Plants Watering System
  
  Arduino IoT Cloud Variables description:
  - int moisture: Current soil moisture percentage
  - int moistureThreshold: Threshold percentage to trigger watering
  - int retestDuration: Time (in minutes) before rechecking soil moisture
  - int wateringTime: Watering duration (in seconds)
  - bool watering: Indicates whether watering is in progress
  - String debugMessage: Debug messages for status updates
  - bool belowThreshold: True if moisture is below threshold
  - int wateringEvent: Tracks watering events for graphing
*/

#include "thingProperties.h"

const int moisturePin = A1;       // Moisture sensor pin
const int relayPin = 2;           // Relay control pin
const int buttonSignalPin = 3;    // Grove button signal pin
const int buttonLedPin = 4;       // Grove button LED pin

unsigned long wateringStartTime = 0; // Tracks when watering started
unsigned long lastTestTime = 0;      // Tracks the last time moisture was checked
bool wasConnected = false;           // Tracks WiFi connection status

void setup() {
  Serial.begin(9600);
  delay(1500);

  // Initialize pins
  pinMode(relayPin, OUTPUT);
  pinMode(buttonSignalPin, INPUT_PULLUP);
  pinMode(buttonLedPin, OUTPUT);
  digitalWrite(relayPin, LOW);     // Ensure relay is off initially
  digitalWrite(buttonLedPin, LOW); // Ensure button LED is off initially

  // Initialize Arduino IoT Cloud
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(4);
  ArduinoCloud.printDebugInfo();

  debugMessage = "Setup complete.";
  Serial.println("Setup complete.");
}

void loop() {
  ArduinoCloud.update();

  // Check WiFi status
  checkWiFiStatus();

  // Read raw moisture value
  int rawMoisture = analogRead(moisturePin);
  Serial.print("Raw Moisture: ");
  Serial.println(rawMoisture);

  // Map raw moisture to percentage
  moisture = map(rawMoisture, 384, 865, 100, 0);
  moisture = constrain(moisture, 0, 100);

  Serial.print("Mapped Moisture Level: ");
  Serial.print(moisture);
  Serial.println("%");

  // Update belowThreshold status
  if (moisture < moistureThreshold) {
    if (!belowThreshold) {
      belowThreshold = true; // Syncs with Arduino IoT Cloud
      debugMessage = "Moisture below threshold.";
    }
  } else {
    if (belowThreshold) {
      belowThreshold = false; // Syncs with Arduino IoT Cloud
      debugMessage = "Moisture above threshold.";
    }
  }

  // Automatic watering logic
  if (millis() - lastTestTime >= retestDuration * 60000UL) { // Check moisture at intervals
    if (belowThreshold) {
      debugMessage = "Moisture below threshold. Starting watering.";
      startWatering();
      lastTestTime = millis(); // Reset the test timer
    } else {
      debugMessage = "Moisture above threshold. No watering needed.";
    }
  }

  // Stop watering after the configured duration
  if (watering && millis() - wateringStartTime >= wateringTime * 1000UL) {
    stopWatering();
    debugMessage = "Watering stopped.";
  }

  // Manual watering with button
  if (digitalRead(buttonSignalPin) == LOW) { // Button pressed
    debugMessage = "Button pressed! Starting watering.";
    startWatering();
    lastTestTime = millis(); // Reset test timer
    delay(200); // Debounce delay
  }

  delay(1000); // Delay for stability
}

void startWatering() {
  if (!watering) {
    watering = true;
    wateringStartTime = millis();
    digitalWrite(relayPin, HIGH); // Activate relay
    digitalWrite(buttonLedPin, HIGH); // Turn on button LED
    wateringEvent = 1; // Set watering event
    debugMessage = "Watering started.";
    Serial.println("Watering started.");
  }
}

void stopWatering() {
  if (watering) {
    watering = false;
    digitalWrite(relayPin, LOW); // Deactivate relay
    digitalWrite(buttonLedPin, LOW); // Turn off button LED
    wateringEvent = 0; // Reset watering event
    debugMessage = "Watering stopped.";
    Serial.println("Watering stopped.");
  }
}

void checkWiFiStatus() {
  if (WiFi.status() == WL_CONNECTED && !wasConnected) {
    char ipAddress[16]; // Buffer for IP address
    WiFi.localIP().toString(ipAddress, sizeof(ipAddress));
    debugMessage = "WiFi connected. SSID: " + String(WiFi.SSID()) + ", IP: " + String(ipAddress);
    Serial.println(debugMessage);
    wasConnected = true;
  } else if (WiFi.status() != WL_CONNECTED && wasConnected) {
    debugMessage = "WiFi disconnected.";
    Serial.println(debugMessage);
    wasConnected = false;
  }
}

// --- Callback Functions ---
void onDebugMessageChange() {
  Serial.println("Debug message updated: " + debugMessage);
}

void onMoistureThresholdChange() {
  debugMessage = "Moisture threshold updated to: " + String(moistureThreshold);
  Serial.println(debugMessage);
}

void onRetestDurationChange() {
  debugMessage = "Retest duration updated to: " + String(retestDuration) + " minutes.";
  Serial.println(debugMessage);
}

void onWateringTimeChange() {
  debugMessage = "Watering time updated to: " + String(wateringTime) + " seconds.";
  Serial.println(debugMessage);
}

when I try to upload it I get "Connectivity firmware update
Update the connectivity firmware to upload the sketch and enable the new version of the IoT Cloud library."

this is my dashboard that shows the watering events over the threshold

any thoughts would be appreciated

You have to apply the new firmware.

Why didn't you address the issue with the sensor first of all?

I am not sure what you mean, I was addressing the watering/sensor issue but I couldn't send the sketch OTA as it required the firmware update

My mistake, thought you was trying to fix an issue with the wet sensor by new firmware. Yet, you should make sure the part of the sensor with electronics is dry before anything else, or you risk corrosion.

yes the sensor did get misted, I dried it off, the erroneous watering happened after that but not immediately, it was a day or so after. I was looking to smooth out out the reading and and add a delay so that it wouldnt water under the threshold, I wanted to send that correction OTA but it said I had to update the firmware. In the end I had to break down the unit and plug it in to do the firmware update, all seems to be working again for now at least. this is an evolution of a system that I have used in the past and I hope to scale it up to my veg plot which will be .4 of an acre, I will gravity feed the water via pipes using solenoid valves, the capacitive sensors will also be upgraded although the industrial ones I saw do not seem to be available or at least were not last time I looked

1 Like

You got links for those industrial? I got a capacitive sensor myself and it's a interesting field. Also how to calibrate the readings to something useful.

I cant find a link for those now, they were always sold out anyway, they appeared to be a longer version of these here I have opted for the IP65 DFRobot Gravity: Analog Waterproof Capacitive sensors for now

here is the code I am currently running, seems to be working ok for the moment

/* 
  Basil Plants Watering System - OTA Compatible

  Fixes:
  - Corrects WiFi IP conversion (no `toString()` issue).
  - Ensures soil moisture stays below threshold for 10 seconds before watering.
  - Prevents unnecessary watering due to sensor fluctuations.

  Arduino IoT Cloud Variables:
  - int moisture: Current soil moisture percentage
  - int moistureThreshold: Threshold percentage to trigger watering
  - int retestDuration: Time (in minutes) before rechecking soil moisture
  - int wateringTime: Watering duration (in seconds)
  - bool watering: Indicates whether watering is in progress
  - String debugMessage: Debug messages for status updates
  - bool belowThreshold: True if moisture is below threshold
  - int wateringEvent: Tracks watering events for graphing
*/

#include "thingProperties.h"

const int moisturePin = A1;       // Moisture sensor pin
const int relayPin = 2;           // Relay control pin
const int buttonSignalPin = 3;    // Grove button signal pin
const int buttonLedPin = 4;       // Grove button LED pin

unsigned long wateringStartTime = 0;  // Tracks when watering started
unsigned long lastTestTime = 0;       // Tracks the last time moisture was checked
unsigned long moistureBelowThresholdTime = 0;  // Timer for moisture being below threshold
bool wasConnected = false;  // Tracks WiFi connection status

void setup() {
  Serial.begin(9600);
  delay(1500);

  // Initialize pins
  pinMode(relayPin, OUTPUT);
  pinMode(buttonSignalPin, INPUT_PULLUP);
  pinMode(buttonLedPin, OUTPUT);
  digitalWrite(relayPin, LOW);     // Ensure relay is off initially
  digitalWrite(buttonLedPin, LOW); // Ensure button LED is off initially

  // Initialize Arduino IoT Cloud
  initProperties();
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  setDebugMessageLevel(4);
  ArduinoCloud.printDebugInfo();

  debugMessage = "Setup complete.";
  Serial.println("Setup complete.");
}

void loop() {
  ArduinoCloud.update();  // IoT Cloud sync

  // Check WiFi status
  checkWiFiStatus();

  // Read raw moisture value
  int rawMoisture = analogRead(moisturePin);
  Serial.print("Raw Moisture: ");
  Serial.println(rawMoisture);

  // Map raw moisture to percentage
  moisture = map(rawMoisture, 384, 865, 100, 0);
  moisture = constrain(moisture, 0, 100);

  Serial.print("Mapped Moisture Level: ");
  Serial.print(moisture);
  Serial.println("%");

  // Handle threshold logic to prevent false triggers
  if (moisture < moistureThreshold) {
    if (!belowThreshold) {
      belowThreshold = true;
      moistureBelowThresholdTime = millis();  // Start timing the drop
      debugMessage = "Moisture below threshold, monitoring duration.";
    }
  } else {
    belowThreshold = false;
    moistureBelowThresholdTime = 0;  // Reset timer if moisture recovers
    debugMessage = "Moisture above threshold.";
  }

  // Only trigger watering if moisture is below threshold for 10 seconds
  if (belowThreshold && (millis() - moistureBelowThresholdTime >= 10000)) {
    if (millis() - lastTestTime >= retestDuration * 60000UL) {
      debugMessage = "Moisture below threshold for 10 sec. Starting watering.";
      startWatering();
      lastTestTime = millis();
    }
  }

  // Stop watering after the configured duration
  if (watering && millis() - wateringStartTime >= wateringTime * 1000UL) {
    stopWatering();
    debugMessage = "Watering stopped.";
  }

  // Manual watering with button
  if (digitalRead(buttonSignalPin) == LOW) { // Button pressed
    debugMessage = "Button pressed! Starting watering.";
    startWatering();
    lastTestTime = millis();
    delay(200); // Debounce delay
  }

  delay(1000); // Stability delay
}

void startWatering() {
  if (!watering) {
    watering = true;
    wateringStartTime = millis();
    digitalWrite(relayPin, HIGH); // Activate relay
    digitalWrite(buttonLedPin, HIGH); // Turn on button LED
    wateringEvent = 1; // Log watering event
    debugMessage = "Watering started.";
    Serial.println("Watering started.");
  }
}

void stopWatering() {
  if (watering) {
    watering = false;
    digitalWrite(relayPin, LOW); // Deactivate relay
    digitalWrite(buttonLedPin, LOW); // Turn off button LED
    wateringEvent = 0; // Log event stop
    debugMessage = "Watering stopped.";
    Serial.println("Watering stopped.");
  }
}

void checkWiFiStatus() {
  if (WiFi.status() == WL_CONNECTED && !wasConnected) {
    // Correct IP address conversion
    String ipAddress = String(WiFi.localIP()[0]) + "." + 
                       String(WiFi.localIP()[1]) + "." + 
                       String(WiFi.localIP()[2]) + "." + 
                       String(WiFi.localIP()[3]);

    debugMessage = "WiFi connected. SSID: " + String(WiFi.SSID()) + ", IP: " + ipAddress;
    Serial.println(debugMessage);
    wasConnected = true;
  } else if (WiFi.status() != WL_CONNECTED && wasConnected) {
    debugMessage = "WiFi disconnected.";
    Serial.println(debugMessage);
    wasConnected = false;
  }
}

// --- Callback Functions ---
void onDebugMessageChange() {
  Serial.println("Debug message updated: " + debugMessage);
}

void onMoistureThresholdChange() {
  debugMessage = "Moisture threshold updated to: " + String(moistureThreshold);
  Serial.println(debugMessage);
}

void onRetestDurationChange() {
  debugMessage = "Retest duration updated to: " + String(retestDuration) + " minutes.";
  Serial.println(debugMessage);
}

void onWateringTimeChange() {
  debugMessage = "Watering time updated to: " + String(wateringTime) + " seconds.";
  Serial.println(debugMessage);
}

you can see where I had these erroneous watering events, hopefully now sorted

From the sensor link you posted:
Description
Watermark® soil moisture sensor uses electrical resistance to measure the moisture level of the soil.
electrical resistance
Don't buy these...
You want the capacitive sensor.
Yes DFRobot makes good sensors, and got a longer variant as well (preferred).

I would not use resistive, the ones in the link are not the ones I originally looked at, they look similar although the others were a couple of feet long I think. Resistive sensors that you see in most watering projects corrode

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.