Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- I have a LiftMaster Elite garage door opener which has a wall mount control. I decided to hookup a ESP8266 NodeMCU Web Server, to open or close my garage door using either my PC or my mobile phone.
- So I realized after I got this working, let's say my garage door is closed, and my web page control button, on my phone, reports that the garage door is closed "as it should", what happens if someone opens the garage door with the garage wall mount button, while I am away from home, and my mobile phone still registers that my garage door is closed?
- To solve this we need two reed switches, one for the door open position and one for the door closed position. The circuit I use has a 5v relay, with a signal pin, so after hooking up the relay "Common" and "NC" to the LiftMaster door control terminals, via the connectors on the side of the unit, I saw that when the garage door was either closing or opening, which takes approximately 12 seconds, the display on the wall mount switch, "which shows the time and temperature by default", would go out "time and temperature display would dissapear", during the 12 seconds ot the garage door motion, either closing or opening.
- I realized this was happening because the relay is acting as a "jumper wire" on the garage door terminals, and electricity takes the path of least resistance and bypasses the wall mount during the 12 second wire jump.
- THE CONFUSING PART OF THE RELAY! "SIGNAL WIRE LOW", Relay ON, "NORMALL OPEN" terminal is "ON", the green LED indicator is "ON", THE LOAD IS OFF, IF CONNECTED TO THE "NC" TERMINAL,
- "SIGNAL WIRE HIGH", Relay OFF, "NORMALLY CLOSED" terminal is "ON", THE LOAD IS ON, IF CONNECTED TO THE "NC" TERMINAL, green LED indicator is "OFF"
- Think about it. You have a 1 channel 5v relay control side, connected to an arduino, with 3.3v to the vcc of the relay control side, and the ground from the arduino connected to ground of the control side of the relay, and a signal wire as input from the arduino to the relay control side, "IN" pin.
- On the load side of the relay you have let's say 12v in the common terminal of the relay "which will power the load", and the "NC" terminal on the relay is connected to the loads positive terminal, the ground side of the load is connected to the power source ground.
- So let's say with a "LOW" "zero volts" signal wire the relay is actually on, the "NO" terminal has 12v, and the green LED indicator on the relay will be "ON". but that means the armature in the relay is being pulled to the Normally Open terminal in the relay "NO" but your load, is connected to the Normally Closed Terminal of the relay, so the load is off, not working. When the signal wire is "HIGH" the relay is actually "OFF", and the green LED turns "OFF", and the armature in the relay goes back to the "NC" terminal, in the relay, and the load turns "ON" and works.
- To test this with a dvom, you will see when the signal wire is "LOW", zero v,you will read 12v when you place the positive lead of the dvom on the "NO" terminal of the relay, and the negative lead of the dvom on the Negative power source, it reads 12v, If you now put the positive lead of the dvom on the "NC" terminal, you will read zero volts. When the signal wire goes to "HIGH" the reading from the negative power source to the "NC" terminal reads 12v and the load is "ON"
- Of course you could make the relay turn "ON" with a "HIGH" signal or "OFF" with a "LOW" signal, but here we are talking about the relay being "ON" with a "LOW" signal, where the relay is actually on, but the "NC" terminal is "OFF", has no connection to 12 volts.
- The confusing part of the relay with either a "LOW ZERO VOLT" or "HIGH 3.3 VOLT" signal wire. Remember when a relay signal wire is "HIGH" the relay is "OFF" and the armature is pulled to the normally closed terminal, and the green LED indicator is off.
- The 5v relay explained: When the relay signal pin is "LOW" the relay is "ON", and the green LED on the relay, is "ON" and the pole, or armature, in the relay, is pulled to the "normally open" "NO" terminal.
- When the signal wire is "HIGH" the relay is "OFF" and the pole, or armature, in the relay, is now back to the Normally Closed terminal "NC" and the green LED is "OFF", and the 12v power is now sent to the load, if your load is connected to the "NC" terminal.
- I noticed that the relay would sometimes stay "HIGH" or "OFF", after the garage door was either opened or closed, which means the pole or armature falls back to the "NC" terminal, and the green LED would be "OFF", and my wall mount button display would be out,this is not what we want. To solve this I had to turn the relay "ON", "LOW", in code, after the 12 seconds was up, and the pole or armature would fall back, to the "NO" terminal, and the green led would be "ON".
- digitalWrite (output5, LOW);//this insures we turn the relay off after an opening or closing of the garage door, output5 is the relay signal wire GPIO5, D1
- Also if you short the reed switch OPEN signal wires when the web button caption says CLOSED it will change the web button to OPEN and visa versa, on the reed switch CLOSE signal wires. This is to keep the states correct if someone presses the wall mount button when your phone state said CLOSED, and now the door is actually OPEN, the reed switches will update the state on your phone.
- */
- /*********
- Door opener
- https://forum.arduino.cc/t/garage-door-opener-with-esp8266-web-server/1154364/18
- *********/
- //DECLARATIONS
- //REMEMBER!, if the signal wire is "LOW", zero v, the relay is "ON", and the 'NO" terminal is "CLOSED" and has power, If the //signal wire is "HIGH", 3.3v the relay is "OFF", and the "NC" terminal has power.
- ///We are using the "NC" terminal on the relay in this script to power the load
- //THE CONFUSING PART OF THE 5V RELAY! "SIGNAL WIRE LOW", the Relay is "ON", "NORMALL OPEN" terminal is "ON", CLOSED, the //green LED indicator is "ON"
- //"SIGNAL WIRE HIGH", the is Relay OFF, "NORMALLY CLOSED" terminal is "ON", CLOSED, green LED indicator is "OFF"
- //The 5v relay explained: When the relay signal pin is "LOW" the relay is "ON", and the green LED on the relay, is "ON" and the pole, or armature in the relay, is pulled to the "normally open" "NO" terminal
- //when the signal wire is "HIGH" the relay is "OFF" and the pole or armature is back to the normally closed terminal "NC" and the green LED is "OFF", and power is sent to the load, if your load is connected
- //to the "NC" terminal.
- //CONST INT
- const int positionSwitchTop = 14; // Pin connected to Top reed switch
- const int positionSwitchBottom = 4; // Pin connected to Bottom reed switch
- const int LED_Reed_Switch_Indicator = 16; // Built in LED pin turns on when door is in motion, else it is off
- //INT
- int Bottom_Reed_Switch_Proximity = digitalRead(positionSwitchBottom); // Read the state of the bottom reed switch
- int Top_Reed_Switch_Proximity = digitalRead(positionSwitchTop); // Read the state of the top reed switch
- //BOOL
- bool The_Garage_Door_Is_Open = false;
- bool The_Garage_Door_Is_Closed = false;
- //LIBRARY
- // Load Wi-Fi library
- #include <ESP8266WiFi.h>
- #include <ESP8266WebServer.h>
- // Assign output variables to GPIO pins
- const uint8_t output5 = 5; // a output pin for door5
- //UNSIGNED LONG
- unsigned long lastTimeDoorWasActivated = 0; // times for millis()
- const unsigned long doorDelay = 12000; // 12 seconds approximate time for garage door to fully open or close
- //ENUM FSM
- // how long does it take to open/close the door - set to 18 seconds
- enum class State { OPENED,
- CLOSING,
- CLOSED,
- OPENING }; // due to naming conflicts you will need a scoped enumeration (enum class)
- // 0 1 2 3 // the compiler will assign numbers to the enumeration items
- State state5 = State::CLOSED; // state5 a variable to store the current state for output5 running State Closed first
- #if true // true for stspringer
- // Replace with your network credentials
- const char* ssid = "SECURE_10";
- const char* password = "DED4DD82CD";
- //My Add/ DEFINE STATIC IP 10.0.69.22 WORKING! https://www.youtube.com/watch?v=B9jJI7p2Gw4
- //STATIC IP ADDRESS
- //IPAddress local_IP(10, 0, 69, 22);//22 is the actual wireless ESP8266 in the garagedigitalWrite(relayPin, relayOnState);
- IPAddress local_IP(10, 0, 69, 19); // 19 for testing
- IPAddress gateway(10, 0, 69, 1);
- IPAddress subnet(255, 255, 255, 0);
- IPAddress primaryDNS(208, 67, 222, 222);
- IPAddress secondaryDNS(208, 67, 220, 220);
- #endif
- // Set web server port number to 80
- ESP8266WebServer server(80);
- // open door
- void doorOpen() {
- lastTimeDoorWasActivated = millis();
- digitalWrite(output5, HIGH); //the relay signal wire is HIGH, 3.3v,the relay is actually "OFF", the "NC" terminal is CLOSED, "ON", sending power to the load, the "NO" terminal is now "OPEN", the green LED indicator is "OFF"
- state5 = State::OPENING;
- Serial.println(F("state5 OPENING"));
- }
- // forced close
- void doorClose() {
- lastTimeDoorWasActivated = millis();
- digitalWrite(output5, HIGH); //the relay signal wire is HIGH, 3.3v,the relay is actually "OFF", the "NC" terminal is CLOSED, "ON", sending power to the load, the "NO" terminal is now "OPEN", the green LED indicator is "OFF"
- state5 = State::CLOSING; //running State Closed first
- Serial.println(F("state5 CLOSING"));
- }
- void runFSM() {
- //Check state5 here
- //if (digitalRead(positionSwitchBottom) == LOW && state5 != State::CLOSED) state5 = State::CLOSED;//My Edit if the door is CLOSED but state5 is OPENED set stae5 to CLOSED
- //if (digitalRead(positionSwitchTop) == LOW && state5 != State::OPENED) state5 = State::OPENED;//My Edit if the door is OPENED but state5 is CLOSED set stae5 to OPENED
- //My Add/EDIT check BOTTOM Reed Switch here
- if (digitalRead(positionSwitchBottom) == LOW && state5 != State::CLOSED) //bottom reed switch closing the circuit "ON", "LOW", initally when the BOTTOM reed switch is closed if the state on the web page is NOT CLOSED then make it CLOSED
- {
- state5 = State::CLOSED; //My Edit if the door is CLOSED but state5 is OPENED set state5 to CLOSED
- if (The_Garage_Door_Is_Closed) //YES THE GARAGE DOOR IS CLOSED
- {
- state5 = State::OPENING; //the garage door is CLOSED so OPEN it, call OPENING
- } else //THE GARAGE DOOR IS OPENED
- {
- state5 = State::CLOSED; //the garage door is OPENED so close it, call CLOSED
- }
- } else if (digitalRead(positionSwitchBottom) == LOW && state5 == State::OPENED) // the garage door is in the physical CLOSED position, but state5 is showing OPENED on the web page, so set state5 to CLOSED
- {
- state5 = State::CLOSED;
- }
- //check TOP Reed Switch here
- if (digitalRead(positionSwitchTop) == LOW && state5 != State::OPENED) //TOP reed switch closing the circuit "ON", "LOW", initally when the TOP reed switch is CLOSED if the state on the web page is NOT OPENED then make it OPENED
- {
- state5 = State::OPENED; //My Edit if the door is OPENED but state5 is CLOSED, set state5 to OPENED
- if (The_Garage_Door_Is_Open) //YES THE GARAGE DOOR IS OPENE
- {
- state5 = State::CLOSING; //the garage door is OPENED so CLOSE IT, call CLOSING
- } else //THE GARAGE DOOR IS CLOSED
- {
- state5 = State::OPENED; //the garage door CLOSED so OPEN it, CALL OPENED
- }
- } else if (digitalRead(positionSwitchTop) == LOW && state5 == State::CLOSED) // the garage door is in the physical OPENED position, but state5 is showing CLOSED on the web page, so set state5 to OPENED
- {
- state5 = State::OPENED;
- }
- switch (state5) { // state5 a variable to store the current state for output5
- case State::OPENED:
- // here you could read a hardware button
- The_Garage_Door_Is_Open = true;
- The_Garage_Door_Is_Closed = false;
- break;
- case State::CLOSING:
- if (millis() - lastTimeDoorWasActivated > doorDelay) //wait 12 seconds
- {
- //This triggers the 5v relay to turn ON and connect the load to the "NC" pin. The
- //LED will light up to indicate that the relay is ON. digitalWrite (output5, LOW);
- digitalWrite(output5, LOW);
- Serial.println(F("state5 CLOSED"));
- state5 = State::CLOSED; // state5 a variable to store the current state for output5
- }
- break;
- case State::CLOSED:
- // here you could read a hardware button
- The_Garage_Door_Is_Open = false;
- The_Garage_Door_Is_Closed = true;
- break;
- case State::OPENING:
- if (millis() - lastTimeDoorWasActivated > doorDelay) //wait 12 seconds
- {
- //This triggers the 5v relay to turn ON and connect the load to the "NC" pin. The
- //LED will light up to indicate that the relay is ON. digitalWrite (output5, LOW);
- digitalWrite(output5, LOW);
- Serial.println(F("state5 OPENED"));
- state5 = State::OPENED; // state5 a variable to store the current state for output5
- }
- break;
- } //switch state
- } //runFSM
- //SETUP
- void setup() {
- Serial.begin(115200);
- // Initialize the output variables as outputs
- //OUTPUT
- pinMode(output5, OUTPUT);
- pinMode(LED_Reed_Switch_Indicator, OUTPUT);
- //INPUT
- pinMode(positionSwitchTop, INPUT_PULLUP);
- pinMode(positionSwitchBottom, INPUT_PULLUP);
- digitalWrite(LED_Reed_Switch_Indicator, HIGH); //initially turn "OFF", HIGH, the LED_Reed_Switch_Indicator
- // Connect to Wi-Fi network with SSID and password
- Serial.print(F("Connecting to "));
- Serial.println(ssid);
- //My Add/ Define Static IP Setings working!
- if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
- Serial.println(F("STA Failed to configure"));
- }
- WiFi.begin(ssid, password);
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- Serial.println("");
- Serial.println(F("WiFi connected."));
- // Print local IP address and start web server
- Serial.println(F("IP address: "));
- Serial.println(WiFi.localIP());
- serverSetup(); //in TAB 2 server
- }
- void reedSwitchStatus() {
- ////////////////////////////////////////////////////////////////////////////////////////
- //BEGIN Bottom_Reed_Switch_Proximity
- ///////////////////////////////////////////////////////////////////////////////////////
- // If the pin reads low, the switch is closed.
- if (Bottom_Reed_Switch_Proximity = LOW) //Bottom_Reed_Switch_Proximity "reed Switch" is Closed IMPORTANT WATCH OUT FOR == ERROR HERE SHOULD BE =
- {
- Serial.println("Bottom Switch closed");
- } else //Bottom_Reed_Switch_Proximity "reed Switch" is Open, turn on the blue built in LED 16 when the garage door is in motion
- {
- if (state5 == State::OPENING) {
- digitalWrite(LED_Reed_Switch_Indicator, LOW); //tune "ON" the LED_Reed_Switch_Indicator
- } else if (state5 == State::OPENED) {
- digitalWrite(output5, LOW); //this insures we turn the relay "off" after an opening or closing of the garage door
- digitalWrite(positionSwitchBottom, HIGH);
- digitalWrite(LED_Reed_Switch_Indicator, HIGH); //tune "OFF" the LED_Reed_Switch_Indicator
- Serial.println("Bottom_Reed_Switch_Proximity opened");
- }
- } //if Bottom
- ////////////////////////////////////////////////////////////////////////////////////////
- //BEGIN Top_Reed_Switch_Proximity
- ///////////////////////////////////////////////////////////////////////////////////////
- // If the pin reads low, the switch is closed.
- if (Top_Reed_Switch_Proximity = LOW) //Top_Reed_Switch_Proximity "reed Switch" is Closed IMPORTANT WATCH OUT FOR == ERROR HERE SHOULD BE =
- {
- Serial.println("Top Switch closed");
- } else // Top_Reed_Switch_Proximity "reed Switch" is Open, turn on the blue built in LED 16 when the garage door is in motion
- {
- if (state5 == State::CLOSING) {
- digitalWrite(LED_Reed_Switch_Indicator, LOW); //tune "ON" the LED_Reed_Switch_Indicator
- } else if (state5 == State::CLOSED) {
- digitalWrite(output5, LOW); //this insures we turn the relay off after an opening or closing of the garage door
- digitalWrite(positionSwitchTop, HIGH);
- digitalWrite(LED_Reed_Switch_Indicator, HIGH); //tune "OFF" the LED_Reed_Switch_Indicator
- Serial.println("Top_Reed_Switch_Proximity opened");
- }
- } //if Top
- } //reedSwitch
- void loop() {
- server.handleClient(); // call the webserver
- reedSwitchStatus();
- runFSM();
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////
- //BEGIN SERVER TAB 2 UPDATE using "fetchAPI/JavaScript" 08_18_2023
- ////////////////////////////////////////////////////////////////////////////////////////////////
- /*
- Webserver Parts
- Update page with FetchAPI & JavaScript
- button sends request to a dedicated resource to process commands
- */
- // we need the button text in the page and in the JSON, hence a global structure to avoid duplicated code.
- struct Stateinfo {
- const char caption[42]; // text/caption for the button
- const char style[10]; // the CSS class (button, button2)
- };
- // the order must fit to the order of the states in the enumeration
- Stateinfo stateinfo[4] {
- {"The Garage Door is Open", "button2"}, // green - button2
- {"Please wait... The Garage Door is Closing", "button"}, // red - button
- {"The Garage Door is Closed", "button"}, // red - button
- {"Please wait... The Garage Door is opening", "button2"} // green - button2
- };
- // call this function in setup()
- void serverSetup() {
- server.on("/", handlePage); // the home page
- server.on("/j.js", handleJs); // javscript based on fetch API to update the page
- server.on("/json", handleJson); // send data in JSON format
- server.on("/cmd", handleCmd); // process commands
- server.begin();
- }
- // the main handle for the page
- void handlePage() {
- //Serial.println(F(" D8 handle page"));
- String message;
- message.reserve(1000);
- // Display the HTML web page
- message += F("<!DOCTYPE html>\n"
- "<html lang=\"en\">\n" // define the language of the content
- "<head>\n"
- "<title>John's Garage Door Opener</title>\n" // mostly displayed on the title bar of the browser tab
- "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n" // set the viewport for mobile devices
- "<link rel=\"icon\" href=\"data:,\">\n" // avoid loading of favicon.ico
- "<script src='j.js'></script>\n" // include the JavaScript
- "<style>\n" // inline style (or include a CSS)
- "html {font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n"
- "button, input[type=submit], .button {border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 20px; margin: 2px; cursor: pointer;}\n"
- ".button {background-color: #FF0000;}\n"
- ".button2 {background-color: #195B6A;}\n"
- "</style>\n"
- "</head>\n"
- "<body>\n"
- "<h1>John's Garage Door Opener</h1>\n");
- // Display current state of output5
- message += F("<p>GPIO 5 - State<span id=\"output5\">");
- message += digitalRead(output5);
- message += F("</span></p>\n");
- // Display a form with one command button (=submit)
- Serial.println(stateinfo[(int)state5].caption);
- message += F("<form action=\"/cmd\" method=\"POST\"><button id=\"button5\" name=\"button5\" class=\"");
- message += stateinfo[(int)state5].style; // access the index based on the integer value of state5
- message += F("\">");
- message += stateinfo[(int)state5].caption;
- message += F("</button></form>\n");
- // just for debugging - you will see 0, 1, 2, 3 as numeric representation of state5
- message += F("<p>global state5=<span id=\"state5\">"); message += (int)state5; message += F("</span></p>\n");
- message += F("<p>FetchAPI</p>\n");
- message += F("</body>\n");
- message += F("</html>");
- server.send(200, "text/html", message);
- //Serial.print(F("handle page message length=")); Serial.println(message.length());
- }
- // process incomming commands LOGIC HERE button5 pressed if state5 == State :: OPENED doorClose()
- void handleCmd() {
- if (server.hasArg("button5")) {
- if (state5 == State::OPENED) doorClose();
- else if (state5 == State::CLOSED) doorOpen();
- else Serial.println(F("D81 pressed cmd button in a state where no action is defined"));
- }
- handlePage(); // as HTML output we return the start page to the browser
- }
- // Output: send data to browser as JSON
- // after amodification always check if JSON is still valid. Just call the JSON (json) in your webbrowser and check.
- void handleJson() {
- String message = "";
- message.reserve(1000);
- message = F(" {\"ss\":"); // Start of JSON and the first object "ss": with the actual runtime in seconds
- message += millis() / 1000;
- message += F(",\"output5\":"); message += digitalRead(output5);
- message += F(",\"state5\":"); message += (int)state5;
- message += F(",\"style5\":\""); message += stateinfo[(int)state5].style; message += F("\""); // access the index based on the integer value of state5. Its text therefore the content must be enclosed in "
- message += F(",\"caption5\":\""); message += stateinfo[(int)state5].caption; message += F("\"");
- message += (F("}")); // End of JSON
- server.send(200, "application/json", message); // set MIME type https://www.ietf.org/rfc/rfc4627.txt
- //Serial.print(F("handleJson message length=")); Serial.println(message.length());
- }
- // Output: a fetch API / JavaScript
- // a function in the JavaScript uses the fetchAPI to request a JSON file from the webserver.
- // The JavaScript process the JSON file and updates the values on the page
- void handleJs() {
- String message;
- message.reserve(1000);
- message += F("const url ='json';\n"
- "function renew(){\n"
- " document.getElementById('state5').style.color = 'blue';\n" // if the timer starts the request, this field gets blue
- " fetch(url)\n" // Call the fetch function passing the url of the API as a parameter
- " .then(response => {return response.json();})\n"
- " .then(jo => {\n"
- " for (var i in jo)\n"
- " {\n"
- " if (document.getElementById(i)) document.getElementById(i).innerHTML = jo[i];\n" // as long as the JSON name fits to the HTML id, the value will be replaced
- " }\n"
- // add other fields here (e.g. the delivered JSON name doesn't fit to the html id
- " document.getElementById('button5').innerHTML = jo['caption5'];\n"
- " document.getElementById('button5').className = jo['style5'];\n"
- " document.getElementById('state5').style.color = '';\n" // if everything was ok, the field will get the default color again
- " })\n"
- " .catch(function() {\n" // this is where you run code if the server returns any errors
- " document.getElementById('state5').style.color = 'red';\n" // indicator that something went wrong
- " });\n"
- "}\n"
- "document.addEventListener('DOMContentLoaded', renew, setInterval(renew, 1000));\n"); // call JSON every n milliseconds
- server.send(200, "text/javascript", message);
- //Serial.print(F("handleJs message length=")); Serial.println(message.length());
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////
- //END SERVER TAB 2 UPDATE 08_18_2023
- ////////////////////////////////////////////////////////////////////////////////////////////////
Advertisement
Add Comment
Please, Sign In to add comment