Help with code to activate relays

the programed timing doesnt seem to work i tried everything including AI...
if i controll the relays manualy by the webui everything works. the preprogramed hour/minute only works first time (turn on) the "ramp-up" "ramp-down" and "turn off" doesnt work what am i missing?

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

const char* ssid = "Gxxxx";
const char* password = "Gxxxxx";
const char* hostName = "t5";

IPAddress ip(192, 168, 1, 100); // Static IP address for Wemos Mini
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

ESP8266WebServer server(80);

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "194.58.203.148", 0, 60000); // Set timezone to UTC (0 seconds offset from UTC)

unsigned long relayStartTime[] = {0, 0, 0, 0, 0, 0, 0, 0}; // Array to store start time for each relay
bool relayAlreadyActivated[8] = {false, false, false, false, false, false, false, false};

String morningMessages[] = {
  "good morning actinic channel",
  "actinic 10%",
  "actinic 30%",
  "good morning blue+ channel",
  "blue+ 10%",
  "blue+ 30%",
  "good morning coral+ channel",
  "coral+ 10%",
  "coral+ 30%",
  "good morning other channel",
  "other 10%",
  "other 30%"
};

String eveningMessages[] = {
  "actinic 100%",
  "actinic 30%",
  "actinic 10%",
  "good night actinic channel",
  "blue+ 100%",
  "blue+ 30%",
  "blue+ 10%",
  "good night blue+ channel",
  "coral+ 100%",
  "coral+ 30%",
  "coral+ 10%",
  "good night coral+ channel",
  "other 100%",
  "other 30%",
  "other 10%",
  "good night other channel"
};

String serialData = ""; // Variable to store serial data

const unsigned long relayDurations[] = {
  500,   // Turn on relay 1 (500 ms)
  500,   // Turn on relay 2 (500 ms)
  500,   // Turn on relay 3 (500 ms)
  500,   // Turn on relay 4 (500 ms)
  3000,  // Ramp up relay 1 (3000 ms)
  3000,  // Ramp up relay 2 (3000 ms)
  3000,  // Ramp up relay 3 (3000 ms)
  3000,  // Ramp up relay 4 (3000 ms)
  3000,  // Ramp down relay 1 (3000 ms)
  3000,  // Ramp down relay 2 (3000 ms)
  3000,  // Ramp down relay 3 (3000 ms)
  3000,  // Ramp down relay 4 (3000 ms)
  500,   // Turn off relay 1 (500 ms)
  500,   // Turn off relay 2 (500 ms)
  500,   // Turn off relay 3 (500 ms)
  500    // Turn off relay 4 (500 ms)
};

void setup() {
  Serial.begin(115200); // Initialize serial communication
  pinMode(D5, OUTPUT);
  pinMode(D6, OUTPUT);
  pinMode(D7, OUTPUT);
  pinMode(D8, OUTPUT);

  digitalWrite(D5, LOW);
  digitalWrite(D6, LOW);
  digitalWrite(D7, LOW);
  digitalWrite(D8, LOW);

  WiFi.hostname(hostName); // Set the local domain

  WiFi.config(ip, gateway, subnet); // Set the static IP address
  WiFi.begin(ssid, password);

  Serial.println("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("Connected to WiFi");
  Serial.println(WiFi.localIP());

  Serial.println("Updating time from NTP server...");
  timeClient.begin(); // Start NTP client

  timeClient.setTimeOffset(3600); // Set timezone (1 hour in seconds for Europe, use -3600 for daylight saving time)

  server.on("/", handleRoot);
  server.on("/relay1", handleRelay1);
  server.on("/relay2", handleRelay2);
  server.on("/relay3", handleRelay3);
  server.on("/relay4", handleRelay4); // Endpoint for serial data
  server.on("/relay5", handleRelay5);
  server.on("/relay6", handleRelay6);
  server.on("/relay7", handleRelay7);
  server.on("/relay8", handleRelay8);
  server.begin();
}

void loop() {
  timeClient.update(); // Update current time
  server.handleClient();

  unsigned long currentTime = timeClient.getEpochTime(); // Get current time in seconds

  // Turn On
  activateRelayAt(1, 21, 20, morningMessages[0], currentTime);  // Adjust timings according to your desired timezone
  activateRelayAt(2, 21, 21, morningMessages[3], currentTime);
  activateRelayAt(3, 21, 22, morningMessages[6], currentTime);
  activateRelayAt(4, 21, 23, morningMessages[9], currentTime);
  // Ramp-up
  activateRelayAt(5, 21, 24, morningMessages[2], currentTime);  // Adjust timings according to your desired timezone
  activateRelayAt(6, 21, 25, morningMessages[5], currentTime);
  activateRelayAt(7, 21, 26, morningMessages[8], currentTime);
  activateRelayAt(8, 21, 27, morningMessages[11], currentTime);
  // Ramp-down
  activateRelayAt(9, 21, 28, eveningMessages[2], currentTime);  // Adjust timings according to your desired timezone
  activateRelayAt(10, 21, 29, eveningMessages[6], currentTime);
  activateRelayAt(11, 21, 30, eveningMessages[10], currentTime);
  activateRelayAt(12, 21, 31, eveningMessages[14], currentTime);
  // Turn Off
  activateRelayAt(13, 21, 32, eveningMessages[3], currentTime);  // Adjust timings according to your desired timezone
  activateRelayAt(14, 21, 33, eveningMessages[7], currentTime);
  activateRelayAt(15, 21, 34, eveningMessages[11], currentTime);
  activateRelayAt(16, 21, 35, eveningMessages[15], currentTime);
  delay(1000);
}

void handleRoot() {
  String content = "<h1 style=\"text-align:center;font-size:48px;\">Glenn's reef 5.0 T5 control</h1>";

  content += "<div style=\"text-align:center;font-size:32px;margin-bottom:20px;\">";

  // Display current time with larger digits
  content += "Current Time: <span id=\"current-time\"></span>";

  content += "</div>";

  content += "<div style=\"margin-bottom: 10px;text-align:center;\">";

  // Buttons to activate relays with improved appearance
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay1', 'Actinic On/Off')\">Actinic On/Off</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay2', 'Blue+ On/Off')\">Blue+ On/Off</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay3', 'Coral+ On/Off')\">Coral+ On/Off</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay4', 'Other On/Off')\">Other On/Off</button>";

  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay5', 'Actinic +/-')\">Actinic +/-</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay6', 'Blue+ +/-')\">Blue+ +/-</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay7', 'Coral+ +/-')\">Coral+ +/-</button>";
  content += "<button class=\"relayButton\" onclick=\"activateRelay('/relay8', 'Other +/-')\">Other +/-</button>";

  content += "</div>";

  // Add a div for the serial log
  content += "<div id=\"serialLog\" style=\"margin: 0 auto; width: 50%; height: 10em; overflow-y: scroll; border: 1px solid #ccc; padding: 10px;\"></div>";

  // CSS styles for buttons
  content += "<style>";
  content += ".relayButton {";
  content += "background-color: #4CAF50;"; /* Green color */
  content += "border: none;";
  content += "color: white;";
  content += "padding: 15px 32px;";
  content += "text-align: center;";
  content += "text-decoration: none;";
  content += "display: inline-block;";
  content += "font-size: 16px;";
  content += "margin: 4px 2px;";
  content += "cursor: pointer;";
  content += "}";
  content += "</style>";

  // JavaScript to handle button clicks and serial output, and update time every second
  content += "<script>";
  content += "function activateRelay(url, message) {";
  content += "var xhr = new XMLHttpRequest();";
  content += "xhr.open('GET', url, true);";
  content += "xhr.onload = function() {";
  content += "if(xhr.status == 200) { updateSerialOutput(new Date().toLocaleTimeString() + ' - ' + message); }";
  content += "};";
  content += "xhr.send();";
  content += "}";
  content += "function updateSerialOutput(data) {";
  content += "var serialLog = document.getElementById('serialLog');"; // Get the div element for the serial log
  content += "serialLog.innerHTML += '<pre>' + data + '</pre>';"; // Append the new data to the existing log with a line break
  content += "scrollToBottom(serialLog);"; // Scroll to the bottom of the serial log
  content += "}";
  content += "function updateCurrentTime() {";
  content += "var currentTimeElement = document.getElementById('current-time');";
  content += "currentTimeElement.innerText = new Date().toLocaleTimeString();"; // Update current time every second
  content += "}";
  content += "function scrollToBottom(element) {";
  content += "element.scrollTop = element.scrollHeight;"; // Scroll to the bottom of the element
  content += "}";
  content += "setInterval(updateCurrentTime, 1000);"; // Update current time every second
  content += "</script>";

  server.send(200, "text/html", content);
}

void handleRelay1() {
  digitalWrite(D5, HIGH);
  delay(relayDurations[0]);
  digitalWrite(D5, LOW);
  server.send(200, "text/plain", "Channel 1 activated");
}

void handleRelay2() {
  digitalWrite(D6, HIGH);
  delay(relayDurations[1]);
  digitalWrite(D6, LOW);
  server.send(200, "text/plain", "Channel 2 activated");
}

void handleRelay3() {
  digitalWrite(D7, HIGH);
  delay(relayDurations[2]);
  digitalWrite(D7, LOW);
  server.send(200, "text/plain", "Channel 3 activated");
}

void handleRelay4() {
  digitalWrite(D8, HIGH);
  delay(relayDurations[3]);
  digitalWrite(D8, LOW);
  server.send(200, "text/plain", "Channel 4 activated");
}

void handleRelay5() {
  digitalWrite(D5, HIGH);
  delay(relayDurations[4]);
  digitalWrite(D5, LOW);
  server.send(200, "text/plain", "Channel 1 dimmed activated");
}

void handleRelay6() {
  digitalWrite(D6, HIGH);
  delay(relayDurations[5]);
  digitalWrite(D6, LOW);
  server.send(200, "text/plain", "Channel 2 dimmed activated");
}

void handleRelay7() {
  digitalWrite(D7, HIGH);
  delay(relayDurations[6]);
  digitalWrite(D7, LOW);
  server.send(200, "text/plain", "Channel 3 dimmed activated");
}

void handleRelay8() {
  digitalWrite(D8, HIGH);
  delay(relayDurations[7]);
  digitalWrite(D8, LOW);
  server.send(200, "text/plain", "Channel 4 dimmed activated");
}

void activateRelayAt(int relayNumber, int targetHour, int targetMinute, String message, unsigned long currentTime) {
  // Check if it's the specified hour and minute and if the relay has not already been activated
  if (timeClient.getHours() == targetHour && timeClient.getMinutes() == targetMinute && !relayAlreadyActivated[relayNumber - 1]) {
    Serial.println("Activating relay " + String(relayNumber));
    digitalWrite(relayPinFromNumber(relayNumber), HIGH);
    delay(relayDurations[relayNumber - 1]); // Use relay duration to determine how long the relay should be active
    digitalWrite(relayPinFromNumber(relayNumber), LOW);
    Serial.println(message); // Print the message to the serial log for debugging
    server.send(200, "text/plain", message); // Send the message to the web interface

    // Mark the relay as activated for the current time
    relayAlreadyActivated[relayNumber - 1] = true;
  }
}

void updateSerialOutput(String data) {
  Serial.println(data);
  // Save the serial data
  serialData += data + "\n";
  // Send the serial data to the web interface
  server.send(200, "text/plain", data);
}

int relayPinFromNumber(int relayNumber) {
  switch(relayNumber) {
    case 1:
      return D5;
    case 2:
      return D6;
    case 3:
      return D7;
    case 4:
      return D8;
    default:
      return -1; // Invalid relay number
  }
}

Explain what you observe.

You have four stages:

  • Turn On
  • Ramp Up
  • Ramp Down
  • Turn Off

Here, you make sure that the relay is not activated twice in the same time slot (each time slot is 1 minute)

You have to de-activate all four relays before moving to the next stage to start fresh and let the if execute correctly

The relays is only active from 500ms to max 6000ms
And when it works it should be a couple of hours between light on, ramp up, ramp down and lights off...
The timers I set now is only for testing so I don't have to spend the day to watch the lights

In serial I get message that everything is working but the relays doesn't get activated... light on works tho... earlier the light of worked to but I messed it up😑

I see a several problems in your code...

You using 0.5 - 6 sec delays for relay durations, it can't work this way on ESP8266 and will incompatible with any asynchronous activity such as Web server.

The highest relay number, used in activateRelayAt() is 16, but your relayPinFromNumber() can handle only range from 1 to 4.

And further - you have a lot of duplicate code in the program, for example, eight almost identical handleRelayX functions. This is not an error, but it makes the program less intuitive and makes it harder to find errors.

The 500ms and 6000ms works from webinterface.
The purpose of the timing is that the relays controlls 4 Dali ballasts for t5 bulbs.
500ms to turn light on 6000ms to dim up to100%
there's probably a lot of errors as I'm no coder att all...

I guess my message did not go through.

In that if you are testing if it is time to activate the relay. So you compare the hour/minute, and as this comparison can happen multiple times in the same hour/minute, depending how fast the loop() executes, the relayAlreadyActivated variable is there to prevent multiple activations within the same hour/minute.

This has nothing to do with the next activation time in later stages.

My question to you is, did you even test what I suggested?

no i havent tested yet as i just now got home from work.

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