Is it possible to configure the fuzzy system to only operate at specific times, namely 00:00:00, 04:00:00, 08:00:00, 12:00:00, 16:00:00, and 20:00:00 (GMT+7)? Additionally, I would like to send these eight data points to my first ThingSpeak account every minute, precisely at the 00th second (e.g., at 14:30:00). Can this be done?
#include <ModbusMaster.h>
#include <Fuzzy.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <HTTPClient.h>
// WiFi credentials
const char* ssid = "R3";
const char* password = "samsungwifi";
// ThingSpeak credentials first account
const char* apiKey = "JM9M79MC4KUXXXXX"; // Write API Key
const char* channelID = "2572XXX";
// ThingSpeak credentials second account
const char* apiKey2 = "UDBQZQ7GOODXXXXX"; // Write API Key for second account
const char* channelID2 = "2765XXX";
// NTP client setup
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7 * 3600); // Offset GMT+7
// Initialize ModbusMaster for sensors and relay
ModbusMaster THCPH;
ModbusMaster relay;
ModbusMaster NPK; // Sensor NPK
// Variables to store sensor values
float soilMoistureValue = 0.0;
float soilTemperatureValue = 0.0;
float conductivityValue = 0.0;
float pHValue = 0.0;
// NPK values
int nitrogenValue = 0;
int phosphorusValue = 0;
int potassiumValue = 0;
// Fuzzy logic setup
Fuzzy *fuzzy = new Fuzzy();
// FuzzyInput for Soil Moisture
FuzzyInput *soilMoistureInput = new FuzzyInput(1);
FuzzySet *dry = new FuzzySet(0, 0, 50, 60);
FuzzySet *moist = new FuzzySet(50, 60, 80, 90);
FuzzySet *wet = new FuzzySet(80, 90, 100, 100);
// FuzzyInput for Soil Temperature
FuzzyInput *soilTemperatureInput = new FuzzyInput(2);
FuzzySet *cold = new FuzzySet(0, 0, 21, 24);
FuzzySet *slightlyCold = new FuzzySet(21, 24, 24, 27);
FuzzySet *normal = new FuzzySet(24, 27, 27, 30);
FuzzySet *hot = new FuzzySet(27, 30, 50, 50);
// FuzzyOutput for Watering Duration
FuzzyOutput *wateringDurationOutput = new FuzzyOutput(1);
FuzzySet *veryFast = new FuzzySet(0, 17, 17, 34);
FuzzySet *fast = new FuzzySet(17, 34, 34, 51);
FuzzySet *medium = new FuzzySet(34, 51, 51, 68);
FuzzySet *longDuration = new FuzzySet(51, 68, 68, 85);
FuzzySet *veryLong = new FuzzySet(68, 85, 85, 102);
// Variables for time-based control
unsigned long nextActivationTime = 0;
unsigned long previousMillis = 0;
const long interval = 500; // Interval for checking
// Function to send data to ThingSpeak first account
void sendToThingSpeak(float moisture, float temperature, float conductivity, float pH, float waterDuration, int nitrogen, int phosphorus, int potassium) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = "http://api.thingspeak.com/update?api_key=" + String(apiKey) +
"&field1=" + String(moisture) +
"&field2=" + String(temperature) +
"&field3=" + String(conductivity) +
"&field4=" + String(pH) +
"&field5=" + String(nitrogen) +
"&field6=" + String(phosphorus) +
"&field7=" + String(potassium) +
"&field8=" + String(waterDuration);
http.begin(url);
int httpResponseCode = http.GET(); // Send the request
if (httpResponseCode > 0) {
String response = http.getString(); // Get the response
} else {
Serial.print("Error on sending POST: ");
Serial.println(httpResponseCode);
}
http.end(); // Free resources
} else {
Serial.println("WiFi not connected");
}
}
// Function to send updated data to ThingSpeak second account
void sendToThingSpeakSecondAccount(float updatedMoisture, float updatedTemperature, float updatedConductivity, float updatedPH) {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = "http://api.thingspeak.com/update?api_key=" + String(apiKey2) + "&field1=" + String(updatedMoisture) + "&field2=" + String(updatedTemperature) + "&field3=" + String(updatedConductivity) + "&field4=" + String(updatedPH);
http.begin(url);
int httpResponseCode = http.GET(); // Send the request
if (httpResponseCode > 0) {
String response = http.getString(); // Get the response
} else {
Serial.print("Error on sending POST to second account: ");
Serial.println(httpResponseCode);
}
http.end(); // Free resources
} else {
Serial.println("WiFi not connected");
}
}
void setup() {
Serial.begin(9600);
Serial.println("Fuzzy Logic with Sensor Data and Relay Control");
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize NTP client
timeClient.begin();
timeClient.update();
// Set next activation time to the next :00 second
nextActivationTime = timeClient.getEpochTime();
nextActivationTime = nextActivationTime - (nextActivationTime % 60) + 60;
// Initialize Modbus
Serial2.begin(9600, SERIAL_8N1, 16, 17); // RX=16, TX=17
THCPH.begin(2, Serial2); // Slave ID for sensors
relay.begin(1, Serial2); // Slave ID for relay
NPK.begin(3, Serial2); // Slave ID for NPK sensor
// Fuzzy logic setup
fuzzy->addFuzzyInput(soilMoistureInput);
soilMoistureInput->addFuzzySet(dry);
soilMoistureInput->addFuzzySet(moist);
soilMoistureInput->addFuzzySet(wet);
fuzzy->addFuzzyInput(soilTemperatureInput);
soilTemperatureInput->addFuzzySet(cold);
soilTemperatureInput->addFuzzySet(slightlyCold);
soilTemperatureInput->addFuzzySet(normal);
soilTemperatureInput->addFuzzySet(hot);
fuzzy->addFuzzyOutput(wateringDurationOutput);
wateringDurationOutput->addFuzzySet(veryFast);
wateringDurationOutput->addFuzzySet(fast);
wateringDurationOutput->addFuzzySet(medium);
wateringDurationOutput->addFuzzySet(longDuration);
wateringDurationOutput->addFuzzySet(veryLong);
// Add fuzzy rules
FuzzyRuleAntecedent *rule1Antecedent = new FuzzyRuleAntecedent();
rule1Antecedent->joinWithAND(wet, cold);
FuzzyRuleConsequent *rule1Consequent = new FuzzyRuleConsequent();
rule1Consequent->addOutput(veryFast);
fuzzy->addFuzzyRule(new FuzzyRule(1, rule1Antecedent, rule1Consequent));
FuzzyRuleAntecedent *rule2Antecedent = new FuzzyRuleAntecedent();
rule2Antecedent->joinWithAND(moist, cold);
FuzzyRuleConsequent *rule2Consequent = new FuzzyRuleConsequent();
rule2Consequent->addOutput(fast);
fuzzy->addFuzzyRule(new FuzzyRule(2, rule2Antecedent, rule2Consequent));
FuzzyRuleAntecedent *rule3Antecedent = new FuzzyRuleAntecedent();
rule3Antecedent->joinWithAND(dry, cold);
FuzzyRuleConsequent *rule3Consequent = new FuzzyRuleConsequent();
rule3Consequent->addOutput(longDuration);
fuzzy->addFuzzyRule(new FuzzyRule(3, rule3Antecedent, rule3Consequent));
FuzzyRuleAntecedent *rule4Antecedent = new FuzzyRuleAntecedent();
rule4Antecedent->joinWithAND(wet, slightlyCold);
FuzzyRuleConsequent *rule4Consequent = new FuzzyRuleConsequent();
rule4Consequent->addOutput(veryFast);
fuzzy->addFuzzyRule(new FuzzyRule(4, rule4Antecedent, rule4Consequent));
FuzzyRuleAntecedent *rule5Antecedent = new FuzzyRuleAntecedent();
rule5Antecedent->joinWithAND(moist, slightlyCold);
FuzzyRuleConsequent *rule5Consequent = new FuzzyRuleConsequent();
rule5Consequent->addOutput(fast);
fuzzy->addFuzzyRule(new FuzzyRule(5, rule5Antecedent, rule5Consequent));
FuzzyRuleAntecedent *rule6Antecedent = new FuzzyRuleAntecedent();
rule6Antecedent->joinWithAND(dry, slightlyCold);
FuzzyRuleConsequent *rule6Consequent = new FuzzyRuleConsequent();
rule6Consequent->addOutput(longDuration);
fuzzy->addFuzzyRule(new FuzzyRule(6, rule6Antecedent, rule6Consequent));
FuzzyRuleAntecedent *rule7Antecedent = new FuzzyRuleAntecedent();
rule7Antecedent->joinWithAND(wet, normal);
FuzzyRuleConsequent *rule7Consequent = new FuzzyRuleConsequent();
rule7Consequent->addOutput(fast);
fuzzy->addFuzzyRule(new FuzzyRule(7, rule7Antecedent, rule7Consequent));
FuzzyRuleAntecedent *rule8Antecedent = new FuzzyRuleAntecedent();
rule8Antecedent->joinWithAND(moist, normal);
FuzzyRuleConsequent *rule8Consequent = new FuzzyRuleConsequent();
rule8Consequent->addOutput(medium);
fuzzy->addFuzzyRule(new FuzzyRule(8, rule8Antecedent, rule8Consequent));
FuzzyRuleAntecedent *rule9Antecedent = new FuzzyRuleAntecedent();
rule9Antecedent->joinWithAND(dry, normal);
FuzzyRuleConsequent *rule9Consequent = new FuzzyRuleConsequent();
rule9Consequent->addOutput(veryLong);
fuzzy->addFuzzyRule(new FuzzyRule(9, rule9Antecedent, rule9Consequent));
FuzzyRuleAntecedent *rule10Antecedent = new FuzzyRuleAntecedent();
rule10Antecedent->joinWithAND(wet, hot);
FuzzyRuleConsequent *rule10Consequent = new FuzzyRuleConsequent();
rule10Consequent->addOutput(fast);
fuzzy->addFuzzyRule(new FuzzyRule(10, rule10Antecedent, rule10Consequent));
FuzzyRuleAntecedent *rule11Antecedent = new FuzzyRuleAntecedent();
rule11Antecedent->joinWithAND(moist, hot);
FuzzyRuleConsequent *rule11Consequent = new FuzzyRuleConsequent();
rule11Consequent->addOutput(medium);
fuzzy->addFuzzyRule(new FuzzyRule(11, rule11Antecedent, rule11Consequent));
FuzzyRuleAntecedent *rule12Antecedent = new FuzzyRuleAntecedent();
rule12Antecedent->joinWithAND(dry, hot);
FuzzyRuleConsequent *rule12Consequent = new FuzzyRuleConsequent();
rule12Consequent->addOutput(veryLong);
fuzzy->addFuzzyRule(new FuzzyRule(12, rule12Antecedent, rule12Consequent));
}
void loop() {
unsigned long currentMillis = millis();
// Update NTP time periodically (non-blocking)
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
timeClient.update();
}
// Check if it's time for the next activation
unsigned long currentTime = timeClient.getEpochTime();
if (currentTime >= nextActivationTime) {
Serial.println("Activating sensors and fuzzy logic...");
// Read soil moisture and temperature
uint8_t result = THCPH.readHoldingRegisters(0x0000, 1);
if (result == THCPH.ku8MBSuccess) {
soilMoistureValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading soil moisture: ");
Serial.println(result);
}
result = THCPH.readHoldingRegisters(0x0001, 1);
if (result == THCPH.ku8MBSuccess) {
soilTemperatureValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading soil temperature: ");
Serial.println(result);
}
result = THCPH.readHoldingRegisters(0x0002, 1);
if (result == THCPH.ku8MBSuccess) {
conductivityValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading conductivity: ");
Serial.println(result);
}
result = THCPH.readHoldingRegisters(0x0003, 1);
if (result == THCPH.ku8MBSuccess) {
pHValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading pH: ");
Serial.println(result);
}
// Read NPK sensor
result = NPK.readHoldingRegisters(0x001E, 1);
if (result == NPK.ku8MBSuccess) nitrogenValue = NPK.getResponseBuffer(0x00);
result = NPK.readHoldingRegisters(0x001F, 1);
if (result == NPK.ku8MBSuccess) phosphorusValue = NPK.getResponseBuffer(0x00);
result = NPK.readHoldingRegisters(0x0020, 1);
if (result == NPK.ku8MBSuccess) potassiumValue = NPK.getResponseBuffer(0x00);
// Apply fuzzy logic
fuzzy->setInput(1, soilMoistureValue);
fuzzy->setInput(2, soilTemperatureValue);
fuzzy->fuzzify();
float wateringDurationValue = fuzzy->defuzzify(1);
// Display sensor values
Serial.print("Soil Moisture: ");
Serial.print(soilMoistureValue);
Serial.print("% | Soil Temperature: ");
Serial.print(soilTemperatureValue);
Serial.print("°C | Water Duration: ");
Serial.print(wateringDurationValue);
Serial.print("seconds | Conductivity: ");
Serial.print(conductivityValue);
Serial.print("µS/cm | pH: ");
Serial.println(pHValue);
Serial.print("Nitrogen: ");
Serial.print(nitrogenValue);
Serial.print(" | Phosphorus: ");
Serial.print(phosphorusValue);
Serial.print(" | Potassium: ");
Serial.println(potassiumValue);
// Send data to ThingSpeak first account
sendToThingSpeak(soilMoistureValue, soilTemperatureValue, conductivityValue, pHValue, wateringDurationValue, nitrogenValue, phosphorusValue, potassiumValue);
// Activate relay
if (wateringDurationValue > 0) {
String formattedTime = timeClient.getFormattedTime();
result = relay.writeSingleCoil(0x0000, 1);
if (result == relay.ku8MBSuccess) {
Serial.print("Relay activated: ");
Serial.print(formattedTime);
Serial.println(" WIB");
}
// Wait for watering duration using millis() (non-blocking)
unsigned long wateringStartTime = millis();
while (millis() - wateringStartTime < (unsigned long)(wateringDurationValue * 1000)) {
// Allow NTP updates and other background tasks
timeClient.update();
}
// Deactivate relay
formattedTime = timeClient.getFormattedTime();
result = relay.writeSingleCoil(0x0000, 0);
if (result == relay.ku8MBSuccess) {
Serial.print("Relay deactivated: ");
Serial.print(formattedTime);
Serial.println(" WIB");
// Add delay for stabilization
delay(1000);
// Read updated soil moisture and temperature after watering
result = THCPH.readHoldingRegisters(0x0000, 1);
if (result == THCPH.ku8MBSuccess) {
soilMoistureValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading updated soil moisture: ");
Serial.println(result);
}
result = THCPH.readHoldingRegisters(0x0001, 1);
if (result == THCPH.ku8MBSuccess) {
soilTemperatureValue = THCPH.getResponseBuffer(0x00) / 10.0f;
} else {
Serial.print("Error reading updated soil temperature: ");
Serial.println(result);
}
// Send updated data to ThingSpeak second account
sendToThingSpeakSecondAccount(soilMoistureValue, soilTemperatureValue, conductivityValue, pHValue);
// Display updated sensor values
Serial.print("Updated Soil Moisture: ");
Serial.print(soilMoistureValue);
Serial.print(" % | Updated Soil Temperature: ");
Serial.print(soilTemperatureValue);
Serial.println(" °C");
Serial.print("---------------------------------------------------------------------------------------");
Serial.println(" ");
}
}
// Set next activation time to the next minute's :00 second
nextActivationTime = currentTime - (currentTime % 60) + 60;
if (wateringDurationValue > 60) {
nextActivationTime += 60; // Add time if duration is more than 1 minute
}
}
}
This is the output of the code