stspringer

John's Garage Door Opener with two reed switches

Sep 7th, 2023 (edited)
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.12 KB | None | 0 0
  1. Latest Working Script, John's Garage Door Opener, using the NORMALLY OPEN, "NO" Terminal on the relay, and two reed switches
  2.  
  3. /*********
  4. Door opener
  5. https://forum.arduino.cc/t/garage-door-opener-with-esp8266-web-server/1154364/18
  6. *********/
  7.  
  8. //DECLARATIONS
  9. //Written by and edited by, John James Guarnieri 09_05_2023
  10.  
  11. //Credits noiasca Arduino Forum
  12.  
  13. //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.
  14. //We are using the "NO" terminal on the relay in this script to power the load
  15. //THE CONFUSING PART OF THE 5V RELAY! "SIGNAL WIRE HIGH", Relay OFF, "NORMALL OPEN" terminal is "OFF", the green LED indicator is "OFF"
  16. //"SIGNAL WIRE HIGH", Relay OFF, "NORMALLY CLOSED" terminal is "ON", green LED indicator is "OFF"
  17.  
  18. //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
  19. //when the signal wire is "HIGH" the relay is "OFF" and the pole or armature is back to the nDED4DD82CDormally closed terminal "NC" and the green LED is "OFF", and power is sent to the load, if your load is connected
  20. //to the "NC" terminal.
  21.  
  22. //CONST INT
  23. const int positionSwitchTop = 14; // Pin connected to Top reed switch
  24. const int positionSwitchBottom = 4; // Pin connected to Bottom reed switch
  25. const int LED_Reed_Switch_Indicator = 16; // Built in LED pin turns on when door is in motion, else it is off
  26.  
  27. //INT
  28. int Bottom_Reed_Switch_Proximity = digitalRead(positionSwitchBottom); // Read the state of the bottom reed switch
  29. int Top_Reed_Switch_Proximity = digitalRead(positionSwitchTop); // Read the state of the top reed switch
  30.  
  31.  
  32. //BOOL
  33. bool The_Garage_Door_Is_Open = false;
  34. bool The_Garage_Door_Is_Closed = false;
  35.  
  36. //LIBRARY
  37. // Load Wi-Fi library
  38. #include <ESP8266WiFi.h>
  39. #include <ESP8266WebServer.h>
  40.  
  41. // Assign output variables to GPIO pins
  42. const uint8_t output5 = 5; // a output pin for door5
  43.  
  44. //UNSIGNED LONG
  45. unsigned long lastTimeDoorWasActivated = 0; // times for millis()
  46. const unsigned long doorDelay = 12000; // 12 seconds approximate time for garage door to fully open or close
  47.  
  48.  
  49. //ENUM FSM
  50. // how long does it take to open/close the door - set to 12 seconds
  51. enum class State { OPENED,
  52. CLOSING,
  53. CLOSED,
  54. OPENING }; // due to naming conflicts you will need a scoped enumeration (enum class)
  55. // 0 1 2 3 // the compiler will assign numbers to the enumeration items
  56.  
  57.  
  58. State state5 = State::CLOSED; // state5 a variable to store the current state for output5 running State Closed first
  59.  
  60. #if true // true for stspringer
  61. // Replace with your network credentials
  62. const char* ssid = "XXX, XXX, XXX,XXX";
  63. const char* password = "XXX, XXX, XXX,XXX";
  64. //My Add/ DEFINE STATIC IP 10.0.69.22 WORKING! https://www.youtube.com/watch?v=B9jJI7p2Gw4
  65.  
  66. //STATIC IP ADDRESS
  67.  
  68. //IPAddress local_IP(10, 0, 69, 22);//22 is the actual wireless ESP8266 in the garagedigitalWrite(relayPin, relayOnState);
  69. IPAddress local_IP(XXX, XXX, XXX,XXX); // 19 for testing
  70. IPAddress gateway(XXX, XXX, XXX,XXX);
  71. IPAddress subnet(XXX, XXX, XXX,XXX);
  72. IPAddress primaryDNS(208, 67, 222, 222);
  73. IPAddress secondaryDNS(208, 67, 220, 220);
  74. #endif
  75.  
  76.  
  77. // Set web server port number to 80
  78. ESP8266WebServer server(80);
  79.  
  80. // open door
  81. void doorOpen() {
  82. lastTimeDoorWasActivated = millis();
  83. digitalWrite(output5, LOW); //the relay signal wire is LOW, zerov the "NO" terminal is now "closed", working, sending power to the load the green LED indicator is "ON"
  84. state5 = State::OPENING;
  85. Serial.println(F("state5 OPENING"));
  86. }
  87.  
  88. // forced close
  89. void doorClose() {
  90. lastTimeDoorWasActivated = millis();
  91. digitalWrite(output5, LOW); //the relay signal wire is LOW, zerov the "NO" terminal is now "closed", working, sending power to the load the green LED indicator is "ON"
  92. state5 = State::CLOSING; //running State Closed first
  93. Serial.println(F("state5 CLOSING"));
  94. }
  95.  
  96. void runFSM() {
  97. //Check state5 here
  98. //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
  99. //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
  100.  
  101. //My Add/EDIT check BOTTOM Reed Switch here
  102. 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
  103. {
  104. state5 = State::CLOSED; //My Edit if the door is CLOSED but state5 is OPENED set state5 to CLOSED
  105.  
  106. if (The_Garage_Door_Is_Closed) //YES THE GARAGE DOOR IS CLOSED
  107. {
  108. state5 = State::OPENING; //the garage door is CLOSED so OPEN it, call OPENING
  109. } else //THE GARAGE DOOR IS OPENED
  110. {
  111. state5 = State::CLOSED; //the garage door is OPENED so close it, call CLOSED
  112. }
  113. } 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
  114. {
  115. state5 = State::CLOSED;
  116. }
  117.  
  118.  
  119. //check TOP Reed Switch here
  120. 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
  121. {
  122. state5 = State::OPENED; //My Edit if the door is OPENED but state5 is CLOSED, set state5 to OPENED
  123.  
  124. if (The_Garage_Door_Is_Open) //YES THE GARAGE DOOR IS OPENE
  125. {
  126. state5 = State::CLOSING; //the garage door is OPENED so CLOSE IT, call CLOSING
  127. } else //THE GARAGE DOOR IS CLOSED
  128. {
  129. state5 = State::OPENED; //the garage door CLOSED so OPEN it, CALL OPENED
  130. }
  131. } 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
  132. {
  133. state5 = State::OPENED;
  134. }
  135.  
  136. switch (state5) // state5 a variable to store the current state for output5
  137. {
  138. case State::OPENED:
  139. // here you could read a hardware button
  140. The_Garage_Door_Is_Open = true;
  141. The_Garage_Door_Is_Closed = false;
  142.  
  143. break;
  144. case State::CLOSING:
  145. if (millis() - lastTimeDoorWasActivated > doorDelay) //wait 12 seconds
  146. {
  147. //This triggers the 5v relay to turn "OFF" after 12 seconds.
  148. digitalWrite(output5, HIGH); //the relay signal wire is "HIGH" 3.3v, & "OFF" "NO" "Normally Open is "Open", zero volts" "NC" has 12v from power supply
  149. Serial.println(F("state5 CLOSED"));
  150. state5 = State::CLOSED; // state5 a variable to store the current state for output5
  151. }
  152. break;
  153. case State::CLOSED:
  154. // here you could read a hardware button
  155. The_Garage_Door_Is_Open = false;
  156. The_Garage_Door_Is_Closed = true;
  157.  
  158. break;
  159. case State::OPENING:
  160. if (millis() - lastTimeDoorWasActivated > doorDelay) //wait 12 seconds
  161. {
  162. //This triggers the 5v relay to turn "OFF" after 12 seconds.
  163. digitalWrite(output5, HIGH); //the relay signal wire is "HIGH" 3.3v, & "OFF" "NO" "Normally Open is "Open", zero volts" "NC" has 12v from power supply
  164. Serial.println(F("state5 OPENED"));
  165. state5 = State::OPENED; // state5 a variable to store the current state for output5
  166. }
  167. break;
  168. } //switch state
  169.  
  170. } //runFSM
  171.  
  172.  
  173. //SETUP
  174. void setup() {
  175. Serial.begin(115200);
  176. // Initialize the output variables as outputs
  177.  
  178. //OUTPUT
  179. pinMode(output5, OUTPUT);
  180. pinMode(LED_Reed_Switch_Indicator, OUTPUT);
  181.  
  182. //INPUT
  183. pinMode(positionSwitchTop, INPUT_PULLUP);
  184. pinMode(positionSwitchBottom, INPUT_PULLUP);
  185.  
  186. digitalWrite(LED_Reed_Switch_Indicator, HIGH); //initially turn "OFF", HIGH, the LED_Reed_Switch_Indicator
  187.  
  188. // Connect to Wi-Fi network with SSID and password
  189. Serial.print(F("Connecting to "));
  190. Serial.println(ssid);
  191.  
  192. //My Add/ Define Static IP Setings working!
  193. if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
  194. Serial.println(F("STA Failed to configure"));
  195. }
  196.  
  197. WiFi.begin(ssid, password);
  198. while (WiFi.status() != WL_CONNECTED) {
  199. delay(500);
  200. Serial.print(".");
  201. }
  202. Serial.println("");
  203. Serial.println(F("WiFi connected."));
  204. // Print local IP address and start web server
  205. Serial.println(F("IP address: "));
  206. Serial.println(WiFi.localIP());
  207.  
  208. serverSetup(); //in TAB 2 server
  209. }
  210.  
  211. void reedSwitchStatus() {
  212.  
  213. ////////////////////////////////////////////////////////////////////////////////////////
  214. //BEGIN Bottom_Reed_Switch_Proximity
  215. ///////////////////////////////////////////////////////////////////////////////////////
  216.  
  217. // If the pin reads low, the switch is closed.
  218. if (Bottom_Reed_Switch_Proximity = LOW) //Bottom_Reed_Switch_Proximity "reed Switch" is Closed IMPORTANT WATCH OUT FOR == ERROR HERE SHOULD BE =
  219. {
  220. Serial.println("Bottom Switch closed");
  221. } else //Bottom_Reed_Switch_Proximity "reed Switch" is Open, turn on the blue built in LED 16 when the garage door is in motion
  222. {
  223. if (state5 == State::OPENING) {
  224. digitalWrite(LED_Reed_Switch_Indicator, LOW); //tune "ON" the LED_Reed_Switch_Indicator
  225. } else if (state5 == State::OPENED) {
  226. digitalWrite(output5, HIGH); //this insures we turn the relay signal wire "off" after an opening or closing of the garage door
  227. digitalWrite(positionSwitchBottom, HIGH); //reed switch open
  228. digitalWrite(LED_Reed_Switch_Indicator, HIGH); //tune "OFF" the LED_Reed_Switch_Indicator
  229. Serial.println("Bottom_Reed_Switch_Proximity opened");
  230. }
  231.  
  232. } //if Bottom
  233.  
  234. ////////////////////////////////////////////////////////////////////////////////////////
  235. //BEGIN Top_Reed_Switch_Proximity
  236. ///////////////////////////////////////////////////////////////////////////////////////
  237.  
  238. // If the pin reads low, the switch is closed.
  239. if (Top_Reed_Switch_Proximity = LOW) //Top_Reed_Switch_Proximity "reed Switch" is Closed IMPORTANT WATCH OUT FOR == ERROR HERE SHOULD BE =
  240. {
  241. Serial.println("Top Switch closed");
  242. } else // Top_Reed_Switch_Proximity "reed Switch" is Open, turn on the blue built in LED 16 when the garage door is in motion
  243. {
  244. if (state5 == State::CLOSING) {
  245. digitalWrite(LED_Reed_Switch_Indicator, LOW); //tune "ON" the LED_Reed_Switch_Indicator
  246. } else if (state5 == State::CLOSED) {
  247. digitalWrite(output5, HIGH); //this insures we turn the relay signal wire off after an opening or closing of the garage door
  248. digitalWrite(positionSwitchTop, HIGH); //reed switch open
  249. digitalWrite(LED_Reed_Switch_Indicator, HIGH); //tune "OFF" the LED_Reed_Switch_Indicator
  250. Serial.println("Top_Reed_Switch_Proximity opened");
  251. }
  252.  
  253. } //if Top
  254.  
  255. } //reedSwitch
  256.  
  257. void loop() {
  258. server.handleClient(); // call the webserver
  259. reedSwitchStatus();
  260. runFSM();
  261. }
  262.  
  263.  
  264.  
  265. /////////////////////////////////////////////////////////////////////////////////////////////////
  266. //BEGIN SERVER TAB 2 UPDATE using "fetchAPI/JavaScript" 08_18_2023
  267. ////////////////////////////////////////////////////////////////////////////////////////////////
  268.  
  269. /*
  270. Webserver Parts
  271. Update page with FetchAPI & JavaScript
  272. button sends request to a dedicated resource to process commands
  273. */
  274.  
  275. // we need the button text in the page and in the JSON, hence a global structure to avoid duplicated code.
  276. struct Stateinfo {
  277. const char caption[42]; // text/caption for the button
  278. const char style[10]; // the CSS class (button, button2)
  279. };
  280.  
  281. // the order must fit to the order of the states in the enumeration
  282. Stateinfo stateinfo[4] {
  283. {"The Garage Door is Open", "button2"}, // green - button2
  284. {"Please wait... The Garage Door is Closing", "button"}, // red - button
  285. {"The Garage Door is Closed", "button"}, // red - button
  286. {"Please wait... The Garage Door is opening", "button2"} // green - button2
  287. };
  288.  
  289. // call this function in setup()
  290. void serverSetup() {
  291. server.on("/", handlePage); // the home page
  292. server.on("/j.js", handleJs); // javscript based on fetch API to update the page
  293. server.on("/json", handleJson); // send data in JSON format
  294. server.on("/cmd", handleCmd); // process commands
  295. server.begin();
  296. }
  297.  
  298. // the main handle for the page
  299. void handlePage() {
  300. //Serial.println(F(" D8 handle page"));
  301. String message;
  302. message.reserve(1000);
  303.  
  304. // Display the HTML web page
  305. message += F("<!DOCTYPE html>\n"
  306. "<html lang=\"en\">\n" // define the language of the content
  307. "<head>\n"
  308. "<title>John's Garage Door Opener</title>\n" // mostly displayed on the title bar of the browser tab
  309. "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n" // set the viewport for mobile devices
  310. "<link rel=\"icon\" href=\"data:,\">\n" // avoid loading of favicon.ico
  311. "<script src='j.js'></script>\n" // include the JavaScript
  312. "<style>\n" // inline style (or include a CSS)
  313. "html {font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n"
  314. "button, input[type=submit], .button {border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 20px; margin: 2px; cursor: pointer;}\n"
  315. ".button {background-color: #FF0000;}\n"
  316. ".button2 {background-color: #195B6A;}\n"
  317. "</style>\n"
  318. "</head>\n"
  319. "<body>\n"
  320. "<h1>John's Garage Door Opener</h1>\n");
  321.  
  322. // Display current state of output5
  323. message += F("<p>GPIO 5 - State<span id=\"output5\">");
  324. message += digitalRead(output5);
  325. message += F("</span></p>\n");
  326. // Display a form with one command button (=submit)
  327. Serial.println(stateinfo[(int)state5].caption);
  328. message += F("<form action=\"/cmd\" method=\"POST\"><button id=\"button5\" name=\"button5\" class=\"");
  329. message += stateinfo[(int)state5].style; // access the index based on the integer value of state5
  330. message += F("\">");
  331. message += stateinfo[(int)state5].caption;
  332. message += F("</button></form>\n");
  333.  
  334. // just for debugging - you will see 0, 1, 2, 3 as numeric representation of state5
  335. message += F("<p>global state5=<span id=\"state5\">"); message += (int)state5; message += F("</span></p>\n");
  336. message += F("<p>FetchAPI</p>\n");
  337. message += F("</body>\n");
  338. message += F("</html>");
  339.  
  340. server.send(200, "text/html", message);
  341. //Serial.print(F("handle page message length=")); Serial.println(message.length());
  342. }
  343.  
  344. // process incomming commands LOGIC HERE button5 pressed if state5 == State :: OPENED doorClose()
  345. void handleCmd() {
  346. if (server.hasArg("button5")) {
  347. if (state5 == State::OPENED) doorClose();
  348. else if (state5 == State::CLOSED) doorOpen();
  349. else Serial.println(F("D81 pressed cmd button in a state where no action is defined"));
  350. }
  351. handlePage(); // as HTML output we return the start page to the browser
  352. }
  353.  
  354. // Output: send data to browser as JSON
  355. // after amodification always check if JSON is still valid. Just call the JSON (json) in your webbrowser and check.
  356. void handleJson() {
  357. String message = "";
  358. message.reserve(1000);
  359. message = F(" {\"ss\":"); // Start of JSON and the first object "ss": with the actual runtime in seconds
  360. message += millis() / 1000;
  361.  
  362. message += F(",\"output5\":"); message += digitalRead(output5);
  363.  
  364. message += F(",\"state5\":"); message += (int)state5;
  365.  
  366. 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 "
  367.  
  368. message += F(",\"caption5\":\""); message += stateinfo[(int)state5].caption; message += F("\"");
  369.  
  370. message += (F("}")); // End of JSON
  371. server.send(200, "application/json", message); // set MIME type https://www.ietf.org/rfc/rfc4627.txt
  372. //Serial.print(F("handleJson message length=")); Serial.println(message.length());
  373. }
  374.  
  375. // Output: a fetch API / JavaScript
  376. // a function in the JavaScript uses the fetchAPI to request a JSON file from the webserver.
  377. // The JavaScript process the JSON file and updates the values on the page
  378. void handleJs() {
  379. String message;
  380. message.reserve(1000);
  381. message += F("const url ='json';\n"
  382. "function renew(){\n"
  383. " document.getElementById('state5').style.color = 'blue';\n" // if the timer starts the request, this field gets blue
  384. " fetch(url)\n" // Call the fetch function passing the url of the API as a parameter
  385. " .then(response => {return response.json();})\n"
  386. " .then(jo => {\n"
  387. " for (var i in jo)\n"
  388. " {\n"
  389. " 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
  390. " }\n"
  391. // add other fields here (e.g. the delivered JSON name doesn't fit to the html id
  392. " document.getElementById('button5').innerHTML = jo['caption5'];\n"
  393. " document.getElementById('button5').className = jo['style5'];\n"
  394. " document.getElementById('state5').style.color = '';\n" // if everything was ok, the field will get the default color again
  395. " })\n"
  396. " .catch(function() {\n" // this is where you run code if the server returns any errors
  397. " document.getElementById('state5').style.color = 'red';\n" // indicator that something went wrong
  398. " });\n"
  399. "}\n"
  400. "document.addEventListener('DOMContentLoaded', renew, setInterval(renew, 1000));\n"); // call JSON every n milliseconds
  401.  
  402. server.send(200, "text/javascript", message);
  403. //Serial.print(F("handleJs message length=")); Serial.println(message.length());
  404. }
  405. //
  406. /////////////////////////////////////////////////////////////////////////////////////////////////
  407. //END SERVER TAB 2 UPDATE 08_18_2023
  408. ////////////////////////////////////////////////////////////////////////////////////////////////
  409.  
Advertisement
Add Comment
Please, Sign In to add comment