I've been triyng for the past ours to make a functioning clock, that get updated once every hour for an automated greenhouse I've been building.
The problem is that once I connect to the NTP server and get the time, if I want to get it in sync after same time(otherwise it drift dramaticcally over time), I can't get to make the timeClient.update(); function to work.
Here I'll provide the source code, the interesting part should be the syncTimeFromNTP() function:
void syncTimeFromNTP() {
// Check WiFi connection before attempting to update time
if (WiFi.status() != WL_CONNECTED) {
Serial.println("- WiFi not connected, skipping NTP sync");
return;
}
// Update time from NTP server
Serial.println("- Attempting to synchronize NTP time...");
timeClient.forceUpdate();
if (timeClient.forceUpdate() == 1) { // Ensure time was successfully updated
Serial.println("- NTP time synchronized successfully");
// Get the current date and time from an NTP server and convert
// it to UTC +2 by passing the time zone offset in hours.
// You may change the time zone offset to your local one.
auto timeZoneOffsetHours = 2;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
} else {
Serial.println("- Failed to synchronize NTP time");
}
}
and the set up and loop parts about the clock.
while (!Serial);
connectToWiFi();
RTC.begin();
Serial.println("\nStarting connection to server...");
timeClient.begin();
timeClient.update();
// Get the current date and time from an NTP server and convert
// it to UTC +2 by passing the time zone offset in hours.
// You may change the time zone offset to your local one.
auto timeZoneOffsetHours = 2;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
Here's the source code.
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
//tutta la roba per l'orologio
#include "RTC.h"
#include <NTPClient.h>
#if defined(ARDUINO_PORTENTA_C33)
#include <WiFiC3.h>
#elif defined(ARDUINO_UNOWIFIR4)
#include <WiFiS3.h>
#endif
#include <WiFiUdp.h>
#include "arduino_secrets.h"
//display base
uint8_t Frame[8][12] = {
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
byte Digits[6][33] = {
{1,1,1, 0,0,1, 1,1,1, 1,1,1, 1,0,0, 1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,1,1, 1,0,0},
{1,0,1, 0,0,1, 0,0,1, 0,0,1, 1,0,0, 1,0,0, 1,0,0, 0,0,1, 1,0,1, 1,0,1, 1,0,0},
{1,0,1, 0,0,1, 1,1,1, 0,1,1, 1,0,0, 1,1,1, 1,0,0, 0,0,1, 1,1,1, 1,1,1, 0,1,0},
{1,0,1, 0,0,1, 1,0,0, 0,0,1, 1,0,1, 0,0,1, 1,1,1, 0,0,1, 1,0,1, 0,0,1, 0,1,0},
{1,0,1, 0,0,1, 1,0,0, 0,0,1, 1,1,1, 0,0,1, 1,0,1, 0,0,1, 1,0,1, 0,0,1, 0,0,1},
{1,1,1, 0,0,1, 1,1,1, 1,1,1, 0,0,1, 1,1,1, 1,1,1, 0,0,1, 1,1,1, 1,1,1, 0,0,1},
};
int AirValue = 560;
int WaterValue = 240;
int soilMoistureValue = 0;
int soilmoisturepercent = 0;
int sensorStatusReset = 7;
bool sensorReset = 0;
bool sensorOn0 = 1; //attivano o meno i vari sensori
bool sensorOn1 = 1;
bool sensorOn2 = 1;
int valoriSensoriUmidity[3];
int s = 0; //somma valori dell'array
int mediaValori;
int counterStatus = 100; //per fare il check ogni 100 letture
int checkHS1; //primo dato di comparazione soil humidity sensor
int checkHS2; //secondo dato di comparazione soil humidity sensor
int resoult; //differenza tra checkHS 1 e 2
int debugLed = 8;
int debugLedButton = 0; //per poi leggere il valore del bottone
int pinPompa = 10; //pin che manda poi il segnale al relay
int bottonePompa = 12; //bottone manuale per attivare la pompa
int varBottonePompa = 0; //serve per leggere il valore del bottone e assegnarlo da qualche parte
int counterPompa = 0; //per dare il tempo alla terra di assorbire l'acqua e non darla nuovamente dopo 1 ciclo
//roba per l'orologio
char ssid[] = "FASTWEB-1-70E8EF-EXT"; // your network SSID (name)
char pass[] = "babbalussi"; // your network password (use for WPA, or use as key for WEP)
int wifiStatus = WL_IDLE_STATUS;
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP
NTPClient timeClient(Udp);
//illuminazione
int pinLampada = 11;
//bottone lampada
int pinBottoneLampada = 6;
int varBottoneLampada = 0; //contiene il valore(HIGH-LOW)
bool switchLampada = false; //gestisce se attivare o meno la mod. in automatico della lampada, quando è false serra in auto, quando è true serra in manual
void displayDigits(int d,int px,int py){
for (int i=0; i<6; i++)
for (int j=0; j<3; j++)
Frame[i+py][j+px]= Digits[i][j+d*3];
matrix.renderBitmap(Frame, 8, 12);
}
void soilMoistureCheck(){
Serial.println("-troubleshooting...");
counterStatus = 0;
for (int j=0; j<4; j++){
switch(j){
case 0:
checkHS1 = analogRead(A0);
delay(200);
checkHS2 = analogRead(A0);
resoult = checkHS1 - checkHS2; //check the difference beetwin the last two readings to see if they are consistant (when a sensor is disconnected the analog in pin trows random numbers)
Serial.println(abs(resoult));
Serial.println(checkHS1);
if(abs(resoult) > 300 || checkHS2 > 610){
sensorOn0 = 0;
Serial.println("-0: no consistent data, check connection");
}else{
Serial.println("-sensor 0 working!");
}
break;
case 1:
checkHS1 = analogRead(A1);
delay(200);
checkHS2 = analogRead(A1);
resoult = checkHS1 - checkHS2;
Serial.println(abs(resoult));
Serial.println(checkHS1);
if(abs(resoult) > 300 || checkHS2 > 610){
sensorOn1 = 0;
Serial.println("-1: no consistent data, check connection");
}else{
Serial.println("-sensor 1 working!");
}
break;
case 2:
checkHS1 = analogRead(A2);
delay(200);
checkHS2 = analogRead(A2);
resoult = checkHS1 - checkHS2;
Serial.println(abs(resoult));
Serial.println(checkHS1);
if(abs(resoult) > 300 || checkHS2 > 610){
sensorOn2 = 0;
Serial.println("-2: no consistent data, check connection");
}else{
Serial.println("-sensor 2 working!");
}
break;
}
}
}
void soilMoistureSensor(){
s = 0; //resetta la somma ogni volta che viene eseguita la lettura
for (int i=0; i<3; i++){
switch (i) {
case 0:
if(sensorOn0 == 1){
soilMoistureValue = analogRead(A0);
//Serial.println(soilMoistureValue);
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
Serial.println(soilmoisturepercent);
valoriSensoriUmidity[0] = soilmoisturepercent;
}
break;
case 1:
if(sensorOn1 == 1){
soilMoistureValue = analogRead(A1);
//Serial.println(soilMoistureValue);
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
Serial.println(soilmoisturepercent);
valoriSensoriUmidity[1] = soilmoisturepercent;
}
break;
case 2:
if(sensorOn2 == 1){
soilMoistureValue = analogRead(A2);
//Serial.println(soilMoistureValue);
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
Serial.println(soilmoisturepercent);
valoriSensoriUmidity[2] = soilmoisturepercent;
}
break;
}
}
for (int j=0; j< 3; j++){
s += valoriSensoriUmidity[j];
}
mediaValori = s / 3;
Serial.print("Soil Humidity: ");
Serial.print(mediaValori);
Serial.println("%");
}
void attivaPompa(){
digitalWrite(pinPompa, LOW);
Serial.println("-activating pump...");
delay(5000);
digitalWrite(pinPompa, HIGH);
Serial.println("-plants watered successfully.");
}
void printWifiStatus(){
// print the SSID of the network you're attached to:
Serial.print("SSID: FASTWEB-1-70E8EF-EXT ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void connectToWiFi(){
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (wifiStatus != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
wifiStatus = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to WiFi");
printWifiStatus();
}
void syncTimeFromNTP() {
// Check WiFi connection before attempting to update time
if (WiFi.status() != WL_CONNECTED) {
Serial.println("- WiFi not connected, skipping NTP sync");
return;
}
// Update time from NTP server
Serial.println("- Attempting to synchronize NTP time...");
timeClient.forceUpdate();
if (timeClient.forceUpdate() == 1) { // Ensure time was successfully updated
Serial.println("- NTP time synchronized successfully");
// Get the current date and time from an NTP server and convert
// it to UTC +2 by passing the time zone offset in hours.
// You may change the time zone offset to your local one.
auto timeZoneOffsetHours = 2;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
} else {
Serial.println("- Failed to synchronize NTP time");
}
}
void setup() {
Serial.begin(9600);
//roba per l'orologio
while (!Serial);
connectToWiFi();
RTC.begin();
Serial.println("\nStarting connection to server...");
timeClient.begin();
timeClient.update();
// Get the current date and time from an NTP server and convert
// it to UTC +2 by passing the time zone offset in hours.
// You may change the time zone offset to your local one.
auto timeZoneOffsetHours = 2;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
//altra roba
Serial.println(F("DHTxx test!"));
dht.begin();
matrix.begin();
pinMode(sensorStatusReset, INPUT);
pinMode(debugLed, OUTPUT);
pinMode(bottonePompa, INPUT);
pinMode(pinPompa, OUTPUT);
digitalWrite(pinPompa, HIGH); //la pompa è disattivata quando do 5v al relay
pinMode(pinLampada, OUTPUT);
pinMode(pinBottoneLampada, INPUT);
}
void loop() {
delay(2000);
// Fetch current time values
int currentHour = timeClient.getHours();
int currentMin = timeClient.getMinutes();
int currentSec = timeClient.getSeconds();
if(currentMin == 0 && currentSec < 3){
syncTimeFromNTP();
}
if(currentMin % 2 == 0 && currentSec < 3){
Serial.println("-syncronizing the clock...");
syncTimeFromNTP();
}
//soil moisture sensor error reset button
debugLedButton = digitalRead(sensorStatusReset);
if(debugLedButton == HIGH){
sensorReset = 1;
digitalWrite(debugLed, LOW);
Serial.println("-al sensors resetted succesfully");
}
if(sensorReset == 1){
Serial.println("-all sensor set to 1");
sensorOn0 = 1;
sensorOn1 = 1;
sensorOn2 = 1;
sensorReset = 0;
}
if(sensorOn0 == 1 & sensorOn1 == 1 & sensorOn2 == 1){
soilMoistureSensor();
}else {
digitalWrite(debugLed, HIGH);
Serial.println("-soil moisture sensors non working properly");
}
if(counterStatus == 100){
soilMoistureCheck();
}
counterStatus ++; //aggiunge uno al counter per capire quando eseguire il check
Serial.print("Counter status: ");
Serial.println(counterStatus);
if(currentHour > 5 && currentHour < 18){
if(counterPompa >= 100 && mediaValori < 80){
attivaPompa();
counterPompa = 0;
}
}
varBottonePompa = digitalRead(bottonePompa);
if(varBottonePompa == HIGH){
attivaPompa();
}
counterPompa ++;
Serial.print("Counter pompa: ");
Serial.println(counterPompa);
//roba per la luce
varBottoneLampada = digitalRead(pinBottoneLampada);
if(varBottoneLampada == HIGH){
digitalWrite(pinLampada, LOW);
if(switchLampada == false){
switchLampada = true;
Serial.println("-luce impostata su accensione manuale");
}else{
switchLampada = false;
Serial.println("-luce impostata su accensione automatica");
}
}
if(switchLampada == false){
if(currentHour > 4 && currentHour < 18){ //non riesco ad aggiungere 2 per aggiustare la time zone, quindi semplicemente porto 2 ore prima da qui
digitalWrite(pinLampada, HIGH);
}else{
digitalWrite(pinLampada, LOW);
}
}
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(false);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println(F("-failed to read from DHT sensor!"));
displayDigits(10,5,1);
displayDigits(10,9,1);
return;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, h);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(t, h, false);
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.print(F("% Temperature: "));
Serial.print(t);
Serial.print(F("°C "));
Serial.print(f);
Serial.print(F("°F Heat index: "));
Serial.print(hic);
Serial.print(F("°C "));
Serial.print(hif);
Serial.println(F("°F"));
int primaCifra = static_cast<int>(f) / 10; // Cast a int per ottenere solo la parte intera
int secondaCifra = static_cast<int>(f) % 10; // Utilizza l'operatore modulo per ottenere la cifra delle unità
Serial.print(currentHour);
Serial.print(", ");
Serial.print(currentMin);
Serial.print(", ");
Serial.println(currentSec);
if(currentHour > 4 && currentHour < 21){
displayDigits(primaCifra,5,1);
displayDigits(secondaCifra,9,1);
matrix.renderBitmap(Frame, 8, 12);
}
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println(String(currentTime));
}
Please I am desperate...