Controllo a distanza di Timed Relè con Arduino UNO
Questo progetto consente di controllare in remoto, con una scheda Arduino UNO e miuPanel, fino a cinque relè temporizzati con ritardo programmabile individualmente. Il ritardo può essere programmato attraverso l’interfaccia grafica. Un pulsante dedicato permette di forzare il passaggio immediato in qualsiasi momento.
Hardware
- Arduino UNO
- Modulo ESP-01 WiFi (con µPanel Firmware)
- Adattatore per Breadboard ADP-01
- Breadboard
- Modulo Relè
Si prega di notare che per la programmazione di Arduino Uno, la linea RxD (filo blu) deve essere scollegato dal modulo WiFi
(Se si configura il progetto per il controllo di più di 1 relè, collegare il 2° al pin 9, il 3° al PIN 10, e così via …)
Definizione μPanel
La definizione del pannello include un header con una casella di testo per l’impostazione del ritardo e una serie di canali identici. Ogni canale contiene gli elementi per il controllo di un relè, da sinistra a destra:
- Un LED tndo verde/bianco che rappresenta lo stato attuale del relè
- Un LED a freccia verde/grigio che può essere cliccato (quando verde) per forzare immediatamente il relè
- Un indicatore di tempo che mostra il ritardo impostato o il conto alla rovescia
- Un interruttore che può essere usato per avviare l’interruttore in ritardo Un pulsante che può essere utilizzato per modificare il ritardo di un canale in base al valore scritto nella casella di modifica
La definizione HTML del pannello è molto breve e consiste in tre elementi:
1) Lo sfondo del desktop e il pannello di intestazione:
D!g11;{%100,10!222^{%95|<Tfi#666:Powered by miuPanel;|>{>T:Set delay [s] ;E0%10:60;}}}
2) La definizione di macro per la creazione di di un canale relè (con un parametro per il nome del canale). Si prega di notare che la cella contenitore della freccia LED ha l’evento click allegato (. Evento) utilizzato per catturare clic sulla freccia. Si noti inoltre che la funzione di auto-indicizzazione viene utilizzato per assegnare automaticamente ID a: il LED rotondo, l’evento click della cella che contiene la freccia del LED, la freccia del LED, il messaggio per il conto alla rovescia, lo switch, e il pulsante SET .
K1:/5{%90<T:?;}{!88F,33D-r20p10%90|L??1N:0;|.??L??M:0:1.817,1.818;|>%18{^b>M??:;}|^W??B:0;|B??:SET;}$
3) La macro usata per creare i canali relè:
J1(Relay A)J1(Relay B)
Arduino Code
/************************************************************************ * Remote Control of Timed Relay with Arduino UNO and miuPanel * * www.miuPanel.com * * support@miuPanel.com * *************************************************************************/ // Change the following defines to change the number of Relays (Max 5) and the used Pins #define NumberOfRelays 2 // Max allowed channels 5 (It will be more with the new App release) #define FirstRelayPIN 8 // The Arduino PIN number of the first Relay // Connect the 1st relay to Arduino digital output 8 // Connect the 2nd relay to Arduino digital output 9 // ... // Connect the 5th relay to Arduino digital output 12 char RelayState[NumberOfRelays]; // Current state of the Relays (0 Open, 1 Closed) int RelayDelay_s[NumberOfRelays]; // Current delay in seconds set for each relay char RelayToChange[NumberOfRelays]; // Relay is counting down (0 = no, 1 = yes) long RelayCommandTime[NumberOfRelays]; // Time of commanded switch in ms for each relay const String RelayNames[NumberOfRelays] = {"Relay A","Relay B"}; // Set here names you like for each relay int EditedDelay = 60; // Current value to appear in the edit box String Msg; // Variable to contain the message sent by the miuPanel Module void InitVars(void) // Initialize all the program variables { // Setup all relay channels variables for(int n=0; n<NumberOfRelays; n++) { RelayState[n] = 0; // Set all relays open RelayDelay_s[n] = 10; // Set all delays to 10 s RelayToChange[n] = 0; // Set all relays steady RelayCommandTime[n] = 0; // Clear all time array } } void setup() { Serial.begin(57600); // Initialise serial delay(3000); // let miuPanel start InitVars(); // Initialise program variables Serial.println(""); // Dismiss partial sent messages Serial.println("$PING 200"); // Enable real-time communication // Begin Panel Definition with background image Serial.print("$P:D!g11;"); // Define panel header Serial.print("{%100,10!222^{%95|<Tfi#666:Powered by miuPanel;|>{>T:Set delay [s] ;E0%10:"+String(EditedDelay)+";}}}"); // Define Macro for creating the relay channel Serial.print("K1:/5{%90<T:?;}{!88F,33D-r20p10%90|L??1N:0;|.??L??M:0:1.817,1.818;|>%18{^b>M??:;}|^W??B:0;|B??:SET;}$"); // Create each Relay channel using the macro for(int n=0; n< NumberOfRelays; n++) Serial.print("J1("+RelayNames[n]+")"); // End the Panel definition command Serial.println(""); // Configure Arduino PINS and open all relays for(int n=0; n<NumberOfRelays; n++) {SetRelayState(n,0); pinMode(n+FirstRelayPIN, OUTPUT);} // Update panel showing the delay of each relay for(int n=0; n< NumberOfRelays; n++) ShowSetDelay(n); } /***************************************************** * This function waits a data message from the uPanel * * Input: timeout_ms time to wait for message * -1 for forever * Return: 0 = Timeout, 1 = Message received ******************************************************/ int WaitMessage(int timeout_ms) { int c; // the received byte unsigned long entrytime = millis(); // Read the time at the function entry static char KeepBuffer = 0; // This tells if we have a partial message in the buffer if (!KeepBuffer) Msg = ""; // If Keepbuffer is false than clear the old message KeepBuffer = 0; // in any case set now the keep buffer to false do { while ((c = Serial.read()) > '\n') Msg += (char) c; // Read incoming chars, if any, until new line if (c == '\n') // is message complete? { if (Msg.substring(0,1).equals("#")) return 1; // if it is a data message return 1 Msg = ""; // otherwise, wait for another one } } while ((timeout_ms < 0) || (millis()-entrytime < timeout_ms)); // has max time passed? KeepBuffer = 1; // Keep the partial buffer content return 0; // if time passed, return 0 } /***************************************************** * This function sets relay pin state and panel LED. * N is the number of relay and s is the state to set ******************************************************/ void SetRelayState(int n, int s) { if (s) // If s is not 0, we close the relay { RelayState[n] = 1; // Remeber that the ralay is now closed Serial.println("#L"+String(n*2)+"1"); // Turn ON the LED on the panel (we have 2 LEDs for each relay) digitalWrite(n+FirstRelayPIN,0); // Close the relay } else // otherwise, if s is 0, we open the relay { RelayState[n] = 0; // Remember that the relay is now open Serial.println("#L"+String(n*2)+"0"); // Turn ON the LED on the panel (we have 2 LEDs for each relay) digitalWrite(n+FirstRelayPIN,1); // Open the relay } } /***************************************************** * This function toggles the Relay state. * N is the relay number ******************************************************/ void ChangeRelayState(int n) { SetRelayState(n, RelayState[n]^1); } /***************************************************** * This function starts the countdouwn for a relays * m is the message of the clicked Switch on the panel ******************************************************/ void ProgramRelayState(String m) { int RelayNumber = m.substring(2,3).toInt(); // Read the clicked Switch number int RelayState = m.substring(3,4).toInt(); // Read the new switch state if (RelayNumber >= NumberOfRelays) return; // Exit if the relay does not exist RelayToChange[RelayNumber] = 1; // Start the count-down Serial.println("#L"+String(RelayNumber*2+1)+"1"); // Make the arrow GREEN on the panel RelayCommandTime[RelayNumber] = millis(); // Save the current time of command SetRelayState(RelayNumber, !RelayState); // Make sure the relay is in the other state } /***************************************************** * This function processes the event generated when * the user click on the Arraw of a relay channel ******************************************************/ void ProcessEvent(String s) { int RelayNumber = s.substring(6,7).toInt(); // Read the clicked Arraw number if (RelayNumber >= NumberOfRelays) return; // Exit if the relay does not exist if (!RelayToChange[RelayNumber]) return; // Exit if the relay is not in count-down // Change the time of command in order to make it expired. This will trigger the switch RelayCommandTime[RelayNumber] = millis() - (long)RelayDelay_s[RelayNumber]*1000; } /***************************************************** * This function processes the message generated when * the user change the content of the edit box ******************************************************/ void ProcessEdit(String s) { int NewDelay = s.substring(4).toInt(); // Read the value into the edit box EditedDelay = NewDelay; // Save the new value } /***************************************************** * This function processes the message generated when * the user click on a SET button ******************************************************/ void ProcessSet(String s) { int RelayNumber = s.substring(2,3).toInt(); // Read the button number if (RelayNumber >= NumberOfRelays) return; // Exit if the relay does not exist RelayDelay_s[RelayNumber] = EditedDelay; // Change the delay value of this relay ShowSetDelay(RelayNumber); // Update its value on the panel } void ShowSetDelay(int n) // Update the delay value of Relay number N { Serial.println("#M"+String(n)+String(RelayDelay_s[n])+" s"); } void loop() { long Now; // Used to read the current time unsigned long DeltaTime; // Used to compute time difference if (WaitMessage(500)) // Wait for a miuPanel message, but no longer than 0.5 s { if (Msg.substring(0,2).equals("#W")) ProgramRelayState(Msg); // a Switch clicked? if (Msg.substring(0,6).equals("#.EVT:")) ProcessEvent(Msg); // an Arrow clicked? if (Msg.substring(0,2).equals("#E")) ProcessEdit(Msg); // the Edit box changed? if (Msg.substring(0,2).equals("#B")) ProcessSet(Msg); // a SET button pushed? } Now = millis(); // Read the current time for(int n=0; n<NumberOfRelays; n++) // Process each relay channel { if (RelayToChange[n]) // is this relay in count-down state? if yes: { // DeltaTime = Now - RelayCommandTime[n]; // compute the passed time since command if (DeltaTime >= (long)RelayDelay_s[n]*1000) // is this passed time greater than the set delay? { // if yes: ShowSetDelay(n); // show the set initial delay time on the panel RelayToChange[n] = 0; // remember that this relay no more counts-down Serial.println("#L"+String(n*2+1)+"0"); // Make its Arrow grey ChangeRelayState(n); // Switch the Relay state } else // if it's not time yet to switch { // then show del remaining time on panel Serial.println("#M"+String(n)+String(RelayDelay_s[n] - DeltaTime/1000)+" s"); } } } }