{"id":1043,"date":"2016-09-29T19:46:07","date_gmt":"2016-09-30T03:46:07","guid":{"rendered":"http:\/\/www.adrianandgenese.com\/blogger\/?p=1043"},"modified":"2016-10-03T08:32:28","modified_gmt":"2016-10-03T16:32:28","slug":"nodemcu-esp8266-http-relay-control-with-12v-battery-monitor-and-wifi-configuration-part-2","status":"publish","type":"post","link":"https:\/\/www.adrianandgenese.com\/blogger\/2016\/09\/29\/nodemcu-esp8266-http-relay-control-with-12v-battery-monitor-and-wifi-configuration-part-2\/","title":{"rendered":"NodeMCU ESP8266 http relay control with 12v battery monitor and wifi configuration &#8211; Part 2"},"content":{"rendered":"<h3>Part 2. (looking for <a href=\"http:\/\/www.adrianandgenese.com\/blogger\/2016\/09\/07\/nodemcu-esp8266-http-relay-control-with-12v-battery-monitor-and-wifi-configuration\/\">Part 1<\/a>?)<\/h3>\n<p>In our part 1 of this article we learned how to take a stock nodemcu esp8266 and flash it with the latest version of nodemcu. We also learned how to send and run files onto the unit using ESPlorer. In this final part 2, we will finally get to the guts of the how to set up a\u00c2\u00a0NodeMCU ESP8266 which provides a web interface for relay control, 12v battery monitor, and wifi configuration.<\/p>\n<h3>Some newbie hints on coding the NodeMCU ESP8266 with Lua scripts<\/h3>\n<p>NodeMCU default behavior loads the init.lua script on boot. When beginning to code and test out its functionality, its a good idea to just load your setup parameters in the init.lua script and for the init.lua script to call another lua file to run the bulk of the code. This lets you comment out the auto loading of the secondary lua script and lets you load it manually using the ESPlorer tool until you are certain the code doesn&#8217;t cause a kernel panic and leave you in an endless bootloop.<\/p>\n<p>I ran into an issue where I didnt do this, and my ESP8266 bootlooped. I then needed to reflash the unit with a lower version of firmware, then reflash the unit with the newer firmware in order to wipe out its filesystem contents which contained the crappy code. What a waste of time.<\/p>\n<p>Below\u00c2\u00a0is an example with the\u00c2\u00a0line calling the\u00c2\u00a0main.lua file to run commented out so I can just run it manually instead of automatically on startup:<\/p>\n<p>Init.lua for testing<\/p>\n<pre class=\"wrap:true lang:lua decode:true\" title=\"init.lua testing\">-- init.lua --\r\n\r\nwifi.setmode(wifi.STATION) --Set network mode to station to connect it to wifi router. You can also set it to AP to make it a access point allowing connection from other wifi devices.\r\n\r\n--Set a static ip so its easy to access\r\ncfg = {\r\n    ip=\"192.168.1.175\",\r\n    netmask=\"255.255.255.0\",\r\n    gateway=\"192.168.1.1\"\r\n  }\r\nwifi.sta.setip(cfg)\r\n\r\n--Your router wifi network's SSID and password\r\nwifi.sta.config(\"SSID\",\"PASSWORD\")\r\n--Automatically connect to network after disconnection\r\nwifi.sta.autoconnect(1)\r\nprint (\"\\r\\n\")\r\n--Print network ip address on UART to confirm that network is connected\r\nprint(wifi.sta.getip())\r\n\r\n-- run main --\r\n-- dofile(\"main.lua\") --<\/pre>\n<p>OK back to the topic at hand which was creating a wifi connected battery charger which can also allow me to monitor the battery voltage on my deep cycle battery left in Shasta. Whew!<\/p>\n<h3>The\u00c2\u00a0Hardware<\/h3>\n<p>My basic battery charger relay control and battery voltage monitor over http project involves just a few parts:<\/p>\n<ol>\n<li>A NodeMCU ESP8266 development board off ebay, or you can buy one from <a href=\"https:\/\/www.amazon.com\/gp\/product\/B010O1G1ES\/ref=as_li_tl?ie=UTF8&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B010O1G1ES&amp;linkCode=as2&amp;tag=realjuic-20&amp;linkId=3b0a5434c9193cd0fd77000397317f76\" target=\"_blank\">amazon here<\/a><\/li>\n<li>One (1) 110v-240v 30A 5v relay (to switch the power on or off to the battery charger)<\/li>\n<li>One (1)\u00c2\u00a0LED (visual indicator to show if charging or not &#8211; optional)<\/li>\n<li>Two (2) 1\/4W resistors (I used a 1M ohm for R1 and a 330k ohm for R2 to make a voltage divider)<\/li>\n<li>One (1) Ceramic Disc .1uf 25v Capacitor (to normalize the voltage readings)<\/li>\n<\/ol>\n<h3>Wiring the NodeMCU to the hardware<\/h3>\n<p>Wiring is pretty straightforward: Im using the v0.9 NodeMCU development board but\u00c2\u00a0could only find the NodeMCU v1.0 image\u00c2\u00a0for the illustration below, but the pinout is pretty much the same. Just pay attention to the pin designations:<\/p>\n<pre class=\"lang:default decode:true\" title=\"Pin Assignments\">RIGHT Side of NODEmcu\r\nD1 - relay in\r\nD2 - relay in\r\nD3 - LED +\r\nGND - Relay Ground (if desired)\r\nD5 - Switch (other side of switch pin is shorted to battery ground)\r\nGND - LED Ground\r\n\r\nLEFT side of NODEmcu\r\nA0 - to middle of voltage divider\r\nGND - Common Battery Ground (or relay ground)\r\n5V - to relay 5V<\/pre>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-1046\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?resize=625%2C387&#038;ssl=1\" alt=\"nodemcu_schematic\" width=\"625\" height=\"387\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?resize=744%2C461&amp;ssl=1 744w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?resize=420%2C260&amp;ssl=1 420w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?resize=768%2C476&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?resize=624%2C387&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic.jpg?w=905&amp;ssl=1 905w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic_zoom.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1047\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic_zoom.jpg?resize=451%2C284&#038;ssl=1\" alt=\"nodemcu_schematic_zoom\" width=\"451\" height=\"284\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic_zoom.jpg?w=451&amp;ssl=1 451w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/nodemcu_schematic_zoom.jpg?resize=420%2C264&amp;ssl=1 420w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>Some hints on wiring:<\/p>\n<ol>\n<li>I&#8217;m powering the ESP8266 board with a USB\u00c2\u00a0power adapter so there isn&#8217;t any power source shown<\/li>\n<li>Remember that R1 is the resistor closest to positive and that R2 is the resistor closest to negative (ground).<\/li>\n<li>If you get a small ceramic disc capacitor, the leads are not polarized and can be connected whichever way.<\/li>\n<li>Dont forget to connect the NodeMCU board GND to Battery GND or the analog read values will be wrong.<\/li>\n<li>I know in the\u00c2\u00a0illustration above, the LED leads are reversed and I also didn&#8217;t add a resistor to the LED (but the LED seems to be fine).<\/li>\n<li>I didnt show how to connect the relay to the power switching of the battery charger as your needs will be a little different from mine.\u00c2\u00a0But I am using one relay to control the AC input into the charger, and the other relay to disconnect the positive battery lead from charger to battery so the charger will not inadvertently drain the battery when left connected.<\/li>\n<\/ol>\n<h3>Calculating voltage divider values (the hardware side)<\/h3>\n<p>The ESP8266\u00c2\u00a0Analog read\u00c2\u00a0pin (A0) on the NodeMCU development board has a voltage maximum of 3.1v. If using a bare ESP8266 module (such as an ESP-12) it is a voltage maximum of 1 volt. Since were using the development board,\u00c2\u00a0we will be finding resistor values to divide the 12-15v coming from the deep cycle battery into a reading the analog pin can sample, anything under 3.1v.<\/p>\n<p>Be aware that the higher the resistance of the resistors, the lower the readings\u00c2\u00a0you&#8217;ll end up seeing at the analog pin in the ESPlorer console. If you choose a ratio of 10k ohms and a 3300 ohm resistor , then you&#8217;ll see a higher analog dc read value on the pin vs using a 1M ohm and a 330k ohm resistor (which is what i&#8217;m using). The reason that i&#8217;m using higher resistance value resistors is because i&#8217;m trying to minimize current drain when the circuit is left connected. If I am understanding this correctly, using this resistor combination only draws about 6\u00c2\u00a0\u00c2\u00b5A.<\/p>\n<p>To calculate the resistor values you will need for your application, head over to this great resource\u00c2\u00a0which teaches you the basics:\u00c2\u00a0<a href=\"https:\/\/learn.sparkfun.com\/tutorials\/voltage-dividers\/\" target=\"_blank\">https:\/\/learn.sparkfun.com\/tutorials\/voltage-dividers\/<\/a>\u00c2\u00a0(There&#8217;s also a handy voltage divider calculator for you to use to determine your specific resistor values.)<\/p>\n<p>If youre already overwhelmed, just keep in mind that the\u00c2\u00a0main idea is to divide the large 12-15v of the battery into a smaller voltage we can sample with the analog read pin on the NodeMCU board. Once the big (12-15v) voltage is divided and within the range the ESP8266 can coherently sample (below 3.1v), we just need to configure the software side of things to make everything work.<\/p>\n<div id=\"attachment_1027\" style=\"width: 394px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/voltagedivider.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1027\" class=\"wp-image-1027 size-full\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/voltagedivider.jpg?resize=384%2C242&#038;ssl=1\" alt=\"voltagedivider\" width=\"384\" height=\"242\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/voltagedivider.jpg?w=384&amp;ssl=1 384w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/voltagedivider.jpg?resize=300%2C189&amp;ssl=1 300w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1027\" class=\"wp-caption-text\">Two resistors with the correct resistance ratio will divide your input voltage<\/p><\/div>\n<h3>Finding your LSB to calibrate your voltage&#8230;WTF? &#8211; The software side<\/h3>\n<p>If you&#8217;re like me and this is your first electronics project requiring software and hardware all working together, the above heading will probably sound like you&#8230;its what I sounded like when trying to wrap my head around this analog read calibration concept.<\/p>\n<p>Its simple once you get your head around it though.<\/p>\n<p>Once we have our voltage divider working as it should, it will bring the voltage down to a level our analog pin can read (from 0-3.1v). However, the values shown by the console output wont display the voltage of the battery as we recognize it, but will instead show values\u00c2\u00a0in the range of 0-1024. This doesn&#8217;t help us much,\u00c2\u00a0so we just have to apply a little division to get real world values (the voltage level) from the 0-1024 reading.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-1028\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg?resize=300%2C135&#038;ssl=1\" alt=\"mathtime\" width=\"300\" height=\"135\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg?resize=300%2C135&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg?resize=768%2C345&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg?resize=1024%2C460&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/mathtime.jpg?w=1160&amp;ssl=1 1160w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>In this case, we test the battery with a calibrated and known working multi-meter to get the current voltage of the battery, then do some division with the the ADC Value reading we get in the console when you click on the &#8216;READ\u00c2\u00a0DC VOLTAGE&#8217; button on the battery charger control webpage.<\/p>\n<div id=\"attachment_1030\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/adcvalue.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1030\" class=\"size-medium wp-image-1030\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/adcvalue.jpg?resize=300%2C83&#038;ssl=1\" alt=\"Get the ADC value by clicking the READ DC VOLTAGE button on the battery charger control webpage\" width=\"300\" height=\"83\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/adcvalue.jpg?resize=300%2C83&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/adcvalue.jpg?w=368&amp;ssl=1 368w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1030\" class=\"wp-caption-text\">Get the ADC Value by clicking the READ DC VOLTAGE button on the battery charger control webpage<\/p><\/div>\n<p>&nbsp;<\/p>\n<p>For example:<\/p>\n<p>Multimeter reading \u00c2\u00a0of battery = 12.56v<br \/>\nADC Value reading from adc pin in ESPlorer console = 581<br \/>\nMath: 12.56\/581 = LSB<br \/>\nLSB = 0.02161790<\/p>\n<p>Now just use\u00c2\u00a0that LSB number to replace the LSB number in the main.lua script below and your voltage reading will be calibrated for our project!<\/p>\n<h3>The Code<\/h3>\n<p>Now that we have the ESP8266 running a current version of NodeMCU and are able to control it with ESPlorer, we can finally get to the fun stuff, running scripts! I&#8217;ve provided the code snippets below to peruse, but you can also just download the init.lua and main.lua files below to upload to your NodeMCU unit immediately. Both these scripts combined produce the webpage shown below and make\u00c2\u00a0everything work.<\/p>\n<p><strong>Download: (right click and save link as&#8230;)<\/strong><br \/>\n<a href=\"http:\/\/www.adrianandgenese.com\/files\/esp\/init.lua\">INIT.LUA<\/a><br \/>\n<a href=\"http:\/\/www.adrianandgenese.com\/files\/esp\/main.lua\">MAIN.LUA<\/a><\/p>\n<div id=\"attachment_1008\" style=\"width: 309px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1008\" class=\"size-full wp-image-1008\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol.jpg?resize=299%2C494&#038;ssl=1\" alt=\"The battery charger control webpage\" width=\"299\" height=\"494\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol.jpg?w=299&amp;ssl=1 299w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol.jpg?resize=182%2C300&amp;ssl=1 182w\" sizes=\"auto, (max-width: 299px) 100vw, 299px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1008\" class=\"wp-caption-text\">The battery charger control webpage<\/p><\/div>\n<h3>INIT.LUA &#8211; A description<\/h3>\n<p>The init.lua file in my project does all the wireless heavy lifting. If the unit is powered on and does not establish a connection to an access point, it will then configure itself as an access point with SSID of\u00c2\u00a0&#8220;BatteryNode&#8221; with password of &#8220;password&#8221; which you can then connect to using a phone or computer. Once your device is connected to the &#8220;BatteryNode&#8221; access point, you then navigate using your web browser to 192.168.2.1 to bring up the battery charger control webpage (make sure you turn off mobile data if the phone does not detect an internet connection using the &#8220;BatteryNode&#8221;\u00c2\u00a0AP or you wont be able to navigate to the IP).<\/p>\n<p>After the webpage loads, at the bottom of the screen is a section to enter the SSID and password of the access point you want the NodeMCU battery charger unit to connect to. Be aware that the information you enter is\u00c2\u00a0case sensitive. Weird hangups or kernel panics happen when you don&#8217;t enter the credentials exactly. If you enter in an SSID that does not exist, the unit will kernel panic and reboot.<\/p>\n<div id=\"attachment_1009\" style=\"width: 421px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol3.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1009\" class=\"size-full wp-image-1009\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol3.jpg?resize=411%2C187&#038;ssl=1\" alt=\"Wifi configuration section\" width=\"411\" height=\"187\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol3.jpg?w=411&amp;ssl=1 411w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol3.jpg?resize=300%2C136&amp;ssl=1 300w\" sizes=\"auto, (max-width: 411px) 100vw, 411px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1009\" class=\"wp-caption-text\">Wifi configuration section<\/p><\/div>\n<p>Once the unit connects to the access point you specified, it will then configure itself as a regular wireless client instead of an access point and you&#8217;ll be disconnected from the &#8220;BatteryNode&#8221; AP. It will also assign itself a static IP of 192.168.1.175<\/p>\n<p>If you&#8217;re going to be using the ESP8266 unit on a different subnet than specified in the scripts, you&#8217;ll need to change the IP configuration in the init.lua script to match yours. You may also just\u00c2\u00a0comment out the lines below in order for the unit to get its IP address using DHCP.<\/p>\n<pre class=\"wrap:true lang:lua decode:true \" title=\"init.lua\">init.lua\r\n\r\n--Set static IP info with configuration above\r\n\twifi.sta.setip(cfg)\r\n\r\nAND\r\n\r\n-- run main --\r\n \r\nwifi.sta.setip(cfg)\r\n\r\n<\/pre>\n<p>Init.lua code<\/p>\n<pre class=\"wrap:true lang:lua decode:true\" title=\"init.lua\">--Test wireless connection. If not connected to an access point, set itself as an AP so wifi can be configured with a browser\r\n\r\n--Client static IP when connected to an access point\r\n\tcfg = {\r\n\t\tip=\"192.168.1.175\",\r\n\t\tnetmask=\"255.255.255.0\",\r\n\t\tgateway=\"192.168.1.1\"\r\n\t}\r\n\t\r\n--Static IP when in AP mode\r\n\taccessPointIpConfig = {}\r\n\taccessPointIpConfig.ip = \"192.168.2.1\"\r\n\taccessPointIpConfig.netmask = \"255.255.255.0\"\r\n\taccessPointIpConfig.gateway = \"192.168.2.1\"\r\n\t\r\n--AP credentials\t\r\n\taccessPointConfig = {}\r\n\taccessPointConfig.ssid = \"BatteryNode\"   -- Name of the SSID you want to create\r\n\taccessPointConfig.pwd = \"password\"    -- WiFi password - at least 8 characters or it screws up\r\n\r\nfunction onboardserver()\r\nprint('Running Main Runtime')\r\ndofile(\"main.lua\")\r\nend\r\n\r\nprint('Testing Wifi Connectivity')\r\nprint(wifi.getmode())\r\n\r\ncount=0\r\n\r\ntmr.alarm(1,1000, 1, function() \r\nprint('.')\r\n if wifi.sta.getip()==nil then \r\n\t\t\r\n\t\tif count == 5 then\r\n\t\tprint('Starting Main Runtime in 3 seconds')\r\n\t\ttmr.stop(1) \r\n\t\t\t\t\r\n\t\t\t\tif(wifi.getmode() ~= 3) then\r\n\t\t\t\tprint('changing wifi mode to stationAP')\r\n\t\t\t\t\r\n\t\t\t\t--NOTE: If using a mobile phone you may need to disable data when connecting to the AP IP set above as it may try to connect over the data connection instead of through WIFI if the phone detects no internet access when connected to the AP.\r\n\r\n\t\t\t\twifi.setmode(wifi.STATIONAP)\r\n\t\t\t\t\r\n\t\t\t\t--Set AP mode with credentials above\r\n\t\t\t\twifi.ap.config(accessPointConfig)\r\n\t\t\t\twifi.ap.setip(accessPointIpConfig)\r\n\t\t\t\t\r\n\t\t\t\t--Print Status on console\r\n\t\t\t\tprint('AP MAC: ',wifi.ap.getmac())\r\n\t\t\t\tprint('SSID: ',accessPointConfig.ssid)\r\n\t\t\t\tprint('PASS: ',accessPointConfig.pwd)\r\n\t\t\t\tprint ('AP IP: ',wifi.ap.getip());\r\n \r\n\t\t\t\tend\r\n\r\n\t\ttmr.alarm(0,3000,0,onboardserver)\r\n\t\telse\r\n\t\tcount = count + 1 \r\n\t\tend\r\n \r\n \r\n else \r\n \r\n \t\tif(wifi.getmode() ~= 1) then\r\n\t\tprint('changing wifi mode to station only')\r\n\t\twifi.setmode(wifi.STATION)\r\n\r\n\t\t--Set static IP info with configuration above\r\n\t\twifi.sta.setip(cfg)\r\n\r\n\t\twifi.sta.autoconnect(1)\r\n\t\t\t\t\r\n\t\t--Print network IP Info\r\n\t\tprint(\"Connected as a station only\")\r\n\t\tprint('Client IP: ',wifi.sta.getip())\r\n\t\tprint('Client MAC: ',wifi.sta.getmac())\r\n\t\t\r\n \r\n end\r\n tmr.stop(1)\r\n \r\n -- run main --\r\n\t\t\r\nwifi.sta.setip(cfg)\r\n--Print network IP Info\r\n\t\tprint(\"Connected as a station only\")\r\n\t\tprint('Client IP: ',wifi.sta.getip())\r\n\t\tprint('Client MAC: ',wifi.sta.getmac())\r\n\t\t\r\ndofile(\"main.lua\")\r\n\r\n end \r\nend)\r\n\r\n<\/pre>\n<h3>MAIN.LUA &#8211; A description<\/h3>\n<p>Main.lua handles the main\u00c2\u00a0processing of commands, it sets up the pins, defines the variables, and serves the website. Remember the LSB value you calculated earlier? You&#8217;ll need to remember to replace\u00c2\u00a0the LSB value in the main.lua file with your own LSB for it to correctly show your voltage on the webpage.<\/p>\n<p>The ESP8266 will remember the relay state indicated by &#8220;OFF&#8221; or &#8220;ON&#8221;<\/p>\n<div id=\"attachment_1007\" style=\"width: 456px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol1.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1007\" class=\"size-full wp-image-1007\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol1.jpg?resize=446%2C362&#038;ssl=1\" alt=\"The battery charger control webpage\" width=\"446\" height=\"362\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol1.jpg?w=446&amp;ssl=1 446w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol1.jpg?resize=300%2C243&amp;ssl=1 300w\" sizes=\"auto, (max-width: 446px) 100vw, 446px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1007\" class=\"wp-caption-text\">Relay Control buttons<\/p><\/div>\n<p>The readings\u00c2\u00a0will also change color of the voltage reading based on\u00c2\u00a0the following table (I skipped the orange color so its just green, yellow, and red).<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/Battery-State-Of-Charge.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1010\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/Battery-State-Of-Charge.jpg?resize=417%2C506&#038;ssl=1\" alt=\"battery-state-of-charge\" width=\"417\" height=\"506\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/Battery-State-Of-Charge.jpg?w=417&amp;ssl=1 417w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/Battery-State-Of-Charge.jpg?resize=247%2C300&amp;ssl=1 247w\" sizes=\"auto, (max-width: 417px) 100vw, 417px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<div id=\"attachment_1012\" style=\"width: 418px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol2-1.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1012\" class=\"wp-image-1012 size-full\" src=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol2-1.jpg?resize=408%2C195&#038;ssl=1\" alt=\"batterychargercontrol2\" width=\"408\" height=\"195\" srcset=\"https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol2-1.jpg?w=408&amp;ssl=1 408w, https:\/\/i0.wp.com\/www.adrianandgenese.com\/blogger\/wp-content\/uploads\/2016\/09\/batterychargercontrol2-1.jpg?resize=300%2C143&amp;ssl=1 300w\" sizes=\"auto, (max-width: 408px) 100vw, 408px\" data-recalc-dims=\"1\" \/><\/a><p id=\"caption-attachment-1012\" class=\"wp-caption-text\">webpage voltage reading in green<\/p><\/div>\n<p>Main.lua code<\/p>\n<pre class=\"wrap:true lang:lua decode:true\" title=\"Main.lua\">-- main.lua --\r\n\r\n----------------------\r\n-- Global Variables --\r\n----------------------\r\n\r\n-- DEBOUNCE FOR EMI WITH LARGE VOLTAGE USING WEB INTERFACE --\r\nignore = 0\r\n\r\n-- RELAY PINS --\r\nRelay1 = 1\r\nRelay2 = 2\r\n\r\n-- SWITCH PIN --\r\npin = 5\r\n\r\n-- LED PIN --\r\nled_pin = 3\r\n\r\n-- ADC PIN AND DEFAULT VALUE --\r\nadc_id = 0 \r\nadc_value = 0\r\n\r\n-- VOLTAGE MONITOR COLOR AND STATUS --\r\nadc_color = \"#FFFFFF\"\r\nstatus_relay = \"OFF\"\r\nstatus_color = \"#FFFFFF\"\r\n\r\n-- VOLTAGE MONITOR VARIABLES --\r\n-- CALIBRATION: calibrate LSB by dividing voltage read by multimeter by adc_value\r\nad = 0\r\nadt = 0\r\nLSB = 0.02162348 \r\n\r\n----------------\r\n-- GPIO Setup --\r\n----------------\r\nprint(\"Setting Up GPIO...\")\r\n\r\n-- SET GPIO PINS FOR RELAY --\r\ngpio.mode(Relay1, gpio.OUTPUT)\r\ngpio.write(Relay1, gpio.LOW);\r\n\r\ngpio.mode(Relay2, gpio.OUTPUT)\r\ngpio.write(Relay2, gpio.LOW);\r\n\r\n-- SET GPIO FOR SWITCH PIN --\r\n\r\ngpio.mode(pin, gpio.INT, gpio.PULLUP)\r\n\r\n---------------\r\n-- LED SETUP --\r\n---------------\r\nprint(\"LED SETUP\")\r\n\r\n-- SET LED TO OFF --\r\ngpio.mode(led_pin, gpio.OUTPUT)\r\ngpio.write(led_pin, gpio.LOW);\r\n\r\n-- Enable PWM output behavior on startup if desired --\r\n-- pwm.setup(led_pin, 2, 800) -- 2Hz, 50% duty default\r\n-- pwm.start(led_pin)\r\n\r\n\r\n----------------------------------\r\n-- SWITCH AND DEBOUNCE FUNCTION --\r\n----------------------------------\r\n\r\nfunction debounce (func)\r\n    last = 0\r\n    delay = 50000 -- 50ms * 1000 as tmr.now() has \u00ce\u00bcs resolution\r\n\r\n    return function (...)\r\n        now = tmr.now()\r\n        delta = now - last\r\n        if delta &lt; 0 then delta = delta + 2147483647 end; -- proposed because of delta rolling over, https:\/\/github.com\/hackhitchin\/esp8266-co-uk\/issues\/2\r\n        if delta &lt; delay then return end;\r\n\r\n        last = now\r\n        return func(...)\r\n    end\r\nend\r\n\r\nfunction onChange ()\r\n    print('The pin value has changed to '..gpio.read(pin))\r\n\t\r\n\tswitchpin = (gpio.read(pin))\r\n\t\r\n\t--If switch is closed then Relays are ON\r\n\tif switchpin == 0 then\r\n\t\r\n\t\tpwm.setup(led_pin, 2, 512)\r\n\t\tpwm.start(led_pin)\r\n\t\tgpio.write(Relay1, gpio.HIGH)\r\n\t\tgpio.write(Relay2, gpio.HIGH)\r\n\t\tstatus_relay = \"ON\"\r\n\t\tstatus_color = \"#00ff00\"\r\n\t\tprint(\"SWITCH ON\")\r\n\t\r\n\t\tend\r\n\t\r\n\t--If switch is open then Relays are OFF but only if not turned on with web interface first\r\n\tif switchpin == 1 and ignore == 0 then\r\n\t\t\r\n\t\tgpio.write(Relay1, gpio.LOW)\r\n\t\tgpio.write(Relay2, gpio.LOW)\r\n\t\tpwm.stop(led_pin)\r\n\t\tstatus_relay = \"OFF\"\r\n\t\tstatus_color = \"#ccccb3\"\r\n\t\tprint(\"SWITCH OFF\")\r\n\t\t\r\n\tend\r\n\t\r\n\t--If switch is open and web interface turned on relays before, then do nothing\r\n\tif switchpin == 1 and ignore == 1 then\r\n\t\tprint(\"EMI DEBOUNCE or WEB SWITCH ON\")\r\n\t\t\r\n\tend\r\n\t\r\nend\r\n\r\ngpio.trig(pin, 'both', debounce(onChange))\r\n\r\n----------------\r\n-- Web Server --\r\n----------------\r\nprint(\"Starting Web Server...\")\r\n-- Create a server object with 30 second timeout\r\nsrv = net.createServer(net.TCP, 30)\r\nsrv:listen(80, function(conn)\r\n\r\n  conn:on(\"receive\", function(sck, payload)\r\n \r\n  \r\n  -- another function\r\n\tfunction esp_update()\r\n            mcu_do=string.sub(payload,postparse[2]+1,#payload)\r\n\t\t\t\t\t\t         \r\n        -- Change color of Voltage according to voltage health table for 12v batteries --\r\n\t\t\r\n            if mcu_do == \"READ+DC+VOLTAGE\" then\r\n            \tadc_value = adc.read(adc_id)\r\n\t\t\t\t\r\n\t\t\t\t-- Voltage conversion from ADC numbers to Voltage numbers --\r\n\t\t\t\t\tad = adc_value*LSB\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t-- Truncate the extra decimal values\t\r\n\t\t\t\t\tadt = string.format(\"%02.2f\",ad)\r\n\t\t\t\t\tprint(adt)\r\n            \t\r\n\t\t\t\t-- If values are above 12.2v then show as GREEN\r\n\t\t\t\tif ad &gt;= 12.2 then\r\n\t\t\t\t\tadc_color = \"#00ff00\"\r\n\t\t\t\t\t\r\n\t\t\t\t-- If values are below 12.2v and above 11.7v then show as YELLOW\r\n\t\t\t\telseif ad &gt;= 11.7 and ad &lt; 12.2 then\r\n\t\t\t\t\tadc_color = \"#ffcc00\"\r\n\t\t\t\t\r\n\t\t\t\t--If values are below 11.7v then show as RED\r\n\t\t\t\telseif ad &lt; 11.7 then\r\n\t\t\t\t\tadc_color = \"#b30000\"\r\n\t\t\t\tend\r\n\t\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t-- The battery charger I use maintains the battery voltage at 13.3v - 13.4v, this is the float charge. Therefore print float charging... instead of voltage level.\r\n\t\t\t\tif ad &gt;= 13.3 and ad &lt; 13.4 then\r\n\t\t\t\t\tadt = \"Float Charging...\"\r\n\t\t\t\t\tprint(\"Float Charging...\")\r\n\t\t\t\t\t\r\n\t\t\t\t\telseif adc_value &lt; 1023 then\r\n\t\t\r\n\t\t\t\t\tprint(\"ADC Value   : \", adc_value)\r\n\t\t\t\t\tprint(\"Real Voltage: \", ad)\r\n\t\t\t\t\tprint(\"Adjusted Voltage: \", adt)\r\n\t\t\t\tend\r\n\t\t\t\t\t\t\t\r\n\t\t\tend\r\n        \r\n\t\t-- If turn on web button is clicked\r\n\t\tif mcu_do == \"TURN+ON\" then\r\n\t\t\r\n\t\t\t\t-- Debounce EMI with web control (dont allow interrupt GPIO to turn off relays)--\r\n\t\t\t\tignore = 1\r\n\t\t\t\t\r\n\t\t\t\tpwm.setup(led_pin, 2, 512)\r\n\t\t\t\tpwm.start(led_pin)\r\n\t\t\t\tgpio.write(Relay1, gpio.HIGH)\r\n\t\t\t\tgpio.write(Relay2, gpio.HIGH)\r\n\t\t\t\tstatus_relay = \"ON\"\r\n\t\t\t\tstatus_color = \"#00ff00\"\r\n\t\t\t\tprint(\"RELAY ON\")\r\n\t\tend\r\n\t\t\r\n\t\t--If turn off web button is clicked\r\n\t\tif mcu_do == \"TURN+OFF\" then\r\n\t\t\r\n\t\t\t\t-- Debounce EMI with web control (allow interrupt GPIO to turn off relays)--\r\n\t\t\t\tignore = 0\r\n\t\t\t\t\r\n            \tgpio.write(Relay1, gpio.LOW)\r\n\t\t\t\tgpio.write(Relay2, gpio.LOW)\r\n\t\t\t\tpwm.stop(led_pin)\r\n\t\t\t\tstatus_relay = \"OFF\"\r\n\t\t\t\tstatus_color = \"#ccccb3\"\r\n\t\t\t\tprint(\"RELAY OFF\")\t\t\t\t\r\n\t\tend\r\n\t\t\r\n\t\tif mcu_do == \"CONFIGURE+WIFI\" then\r\n\t\t\t\r\n        ssid = string.sub(payload,string.find(payload,\"ssid=\")+5,\r\n\t\tstring.find(payload,\"&amp;password\")-1)\r\n\t\tpw = string.sub(payload,string.find(payload,\"password=\")+9,string.find(payload,\"&amp;mcu\")-1)\r\n\t\t\r\n\t\t\t--If any wifi config fields are blank then ignore\r\n\t\t \tif ssid == \"\" or pw == \"\" then \r\n\t\t\tprint(\"Empty fields not applying wifi config\")\r\n\t\t\t\r\n\t\t\t--If wifi config fields populated then attempt to connect to wifi\r\n\t\t\telseif ssid ~= \"\" or ps ~= \"\" then\r\n\t\t\r\n\t\t\tprint(\"Connecting to AP:\",ssid)\r\n\t\t\r\n\t\t\t--Set ESP to station mode only and to disable the ESP in AP mode\r\n\t\t\twifi.setmode(wifi.STATION)\r\n\t\t\r\n\t\t\t--SSID and PW are case sensitive. If wireless info is not entered case sensitive the ESP will hang up. If the SSID and encryption is incorrect, the ESP will Kernel Panic and just reboot.\r\n\t\t\twifi.sta.config(ssid,pw,1)\r\n\t\t\r\n\t\t\t--Restart ESP in case it hangs on re-connection. This will prevent MCU from being unreachable.\r\n\t\t\tnode.restart()\r\n\t\t\r\n\t\t\t--After wireless is configured this sets up a static IP as configured in init.lua\r\n\t\t\t--wifi.sta.setip(cfg)\r\n\t\t\t\r\n\t\t\tend\r\n\t\t\t\r\n\t\t\t\r\n\t\tend\r\n\t\t\r\n\tend\r\n\t\t\r\n            \r\n        --Parse position POST value from header\r\n\t\tpostparse={string.find(payload,\"mcu_do=\")}\r\n\t\t\r\n\r\n        --If POST value exist, run the Functions above\r\n        if postparse[2]~=nil then esp_update()end\r\n  \r\n  \r\n\t--New NodeMCU 1.5.4+ firmware fails on older NodeMCU v.9.x multiple send commands, so needed to do a new method to send.\r\n    local response = {}\r\n\r\n    response[#response + 1] = '&lt;html&gt;\\n'\r\n    response[#response + 1] = '&lt;center&gt;\\n'\r\n    response[#response + 1] = '&lt;head&gt;&lt;meta content=\"text\/html; charset=utf-8\"&gt;\\n'\r\n\tresponse[#response + 1] = '&lt;title&gt;Battery Charger Control&lt;\/title&gt;&lt;\/head&gt;\\n'\r\n\tresponse[#response + 1] = '&lt;body&gt;&lt;h1 style=\"font-family:verdana;\"&gt;Battery Charger Control&lt;\/h1&gt;\\n'\r\n\tresponse[#response + 1] = '&lt;form action=\"\" method=\"POST\"&gt;\\n'\r\n\tresponse[#response + 1] = '&lt;table border=\\\"1\\\" width=\\\"400\\\" bordercolorlight=\\\"#000000\\\" bordercolordark=\\\"#008000\\\" height=\\\"137\\\"&gt;&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" bgcolor=\\\"#339FFF\\\" align=\\\"center\\\"&gt;&lt;b&gt;'\r\n\tresponse[#response + 1] = '&lt;font face=\\\"Verdana\\\" size=\\\"2\\\" color=\\\"#FFFF99\\\"&gt;BATTERY CHARGER:&lt;\/font&gt;&lt;p&gt;&lt;font face=\\\"Verdana\\\" size=\\\"6\\\" color=\\\"'..status_color..'\\\"&gt;'..status_relay..'&lt;\/font&gt;&lt;p&gt;&lt;\/b&gt;&lt;\/td&gt;&lt;\/tr&gt;'\r\n\tresponse[#response + 1] = '&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" align=\\\"center\\\"&gt;&lt;p&gt;&lt;input type=\"submit\" name=\"mcu_do\" value=\"TURN ON\" style=\"height:100px; width:300px; font-size: 30px;\"&gt;&lt;p&gt;&lt;\/b&gt;&lt;\/font&gt;&lt;\/a&gt;&lt;\/td&gt;'\r\n\tresponse[#response + 1] = '&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" align=\\\"center\\\"&gt;&lt;p&gt;&lt;input type=\"submit\" name=\"mcu_do\" value=\"TURN OFF\" style=\"height:100px; width:300px; font-size: 30px;\"&gt;&lt;p&gt;&lt;\/b&gt;&lt;\/font&gt;&lt;\/td&gt;&lt;font face=\\\"Verdana\\\"&gt;&lt;\/b&gt;&lt;\/font&gt;&lt;\/td&gt;&lt;\/tr&gt;&lt;\/table&gt;'\r\n\tresponse[#response + 1] = '&lt;BR&gt;'\r\n\tresponse[#response + 1] = '&lt;table border=\\\"1\\\" width=\\\"400\\\" bordercolorlight=\\\"#000000\\\" bordercolordark=\\\"#008000\\\" height=\\\"137\\\"&gt;&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" bgcolor=\\\"#339FFF\\\" align=\\\"center\\\"&gt;&lt;b&gt;'\r\n\tresponse[#response + 1] = '&lt;font face=\\\"Verdana\\\" size=\\\"2\\\" color=\\\"#FFFF99\\\"&gt;BATTERY VOLTAGE:&lt;p&gt;&lt;font face=\\\"Verdana\\\" size=\\\"6\\\" color=\\\"'..adc_color..'\"&gt;'..adt..'&lt;\/font&gt;&lt;\/b&gt;&lt;\/td&gt;&lt;\/tr&gt;'\r\n\tresponse[#response + 1] = '&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" align=\\\"center\\\"&gt;&lt;p&gt;&lt;input type=\"submit\" name=\"mcu_do\" value=\"READ DC VOLTAGE\" style=\"height:100px; width:300px; font-size: 30px;\"&gt;&lt;p&gt;&lt;\/b&gt;&lt;\/font&gt;&lt;\/form&gt;&lt;\/td&gt;'\r\n\tresponse[#response + 1] = '&lt;table border=\\\"1\\\" width=\\\"400\\\" bordercolorlight=\\\"#000000\\\" bordercolordark=\\\"#008000\\\" height=\\\"137\\\"&gt;&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" bgcolor=\\\"#339FFF\\\" align=\\\"center\\\"&gt;&lt;b&gt;'\r\n\tresponse[#response + 1] = '&lt;font face=\\\"Verdana\\\" size=\\\"2\\\" color=\\\"#FFFF99\\\"&gt;WIFI CONFIG&lt;\/b&gt;&lt;br&gt;&lt;font face=\\\"Verdana\\\" size=\\\"1\\\" color=\\\"#FFFF99\\\"&gt;NOTE: Characters are CASE SENSITIVE&lt;\/font&gt;&lt;\/td&gt;&lt;\/tr&gt;'\r\n\t\r\n\tresponse[#response + 1] = '&lt;BR&gt;'\r\n\tresponse[#response + 1] = '&lt;tr&gt;&lt;td style=\\\"border-style: solid; border-width: 1px\\\" width=\\\"91\\\" align=\\\"center\\\"&gt;&lt;p&gt;&lt;form action=\"\" method=\"POST\"&gt;'\r\n\tresponse[#response + 1] = '&lt;font face=\\\"Verdana\\\" size=\\\"1\\\"&gt;SSID:&lt;\/font&gt;'\r\n\tresponse[#response + 1] = '&lt;br&gt;'\r\n\tresponse[#response + 1] = '&lt;input type=\"text\" name=\"ssid\" id=\"inputtext\"&gt;'\r\n\tresponse[#response + 1] = '&lt;p&gt;'\r\n\tresponse[#response + 1] = '&lt;font face=\\\"Verdana\\\" size=\\\"1\\\"&gt;Password:&lt;\/font&gt;'\r\n\tresponse[#response + 1] = '&lt;br&gt;'\r\n\tresponse[#response + 1] = '&lt;input type=\"text\" name=\"password\" id=\"inputtext\"&gt;'\r\n\tresponse[#response + 1] = '&lt;br&gt;'\r\n\tresponse[#response + 1] = '&lt;input type=\"submit\" name=\"mcu_do\" value=\"CONFIGURE WIFI\" id=\"submit\"&gt;&lt;br&gt;&lt;font face=\\\"Verdana\\\" size=\\\"1\\\"&gt;STATIC IP: 192.168.1.175&lt;\/font&gt;&lt;\/b&gt;&lt;\/font&gt;&lt;\/td&gt;'\r\n\tresponse[#response + 1] = '&lt;\/form&gt;'\r\n\tresponse[#response + 1] = '&lt;\/center&gt;\\n'\r\n\tresponse[#response + 1] = '&lt;\/body&gt;&lt;\/html&gt;\\n'\r\n\t\r\n\t     -- sends and removes the first element from the 'response' table\r\n    local function send(sk)\r\n      if #response &gt; 0\r\n        then sk:send(table.remove(response, 1))\r\n      else\r\n        sk:close()\r\n        response = nil\r\n      end\r\n    end\r\n\r\n    -- triggers the send() function again once the first chunk of data was sent\r\n    sck:on(\"sent\", send)\r\n\r\n    send(sck)\r\n  end)\r\nend)<\/pre>\n<p>There you have it, a guide which should allow you to have a fully functioning ESP8266 webserver which allows you to control a relay (which controls a battery charger), monitor the voltage of a 12v battery, and configure the wireless settings without needing to upload any new lua scripts. This was tested on a NodeMCU development board v0.9 with NodeMCU version 1.5.4.1.<\/p>\n<h3>Some final thoughts and credit where credit is due<\/h3>\n<p>I&#8217;m sure the scripts could be optimized and reduced in size, and I welcome any tweaks or comments to anything i&#8217;ve written\u00c2\u00a0above. What i&#8217;ve essentially done is taken some smoothly written code from all over the internet and adapted it for\u00c2\u00a0my purposes. Below is a list of the resources I used to help build this project. They were the few articles that were written in a way where I could understand and also adapt for my own use. I couldn&#8217;t have done this project without them.<\/p>\n<h3>TCP\/IP Http server with NodeMCU:<\/h3>\n<ul>\n<li><a href=\"http:\/\/www.allaboutcircuits.com\/projects\/how-to-make-an-interactive-tcp-server-nodemcu-on-the-esp8266\/\" target=\"_blank\">http:\/\/www.allaboutcircuits.com\/projects\/how-to-make-an-interactive-tcp-server-nodemcu-on-the-esp8266\/<\/a> (note that this link was written for NodeMCU firmware v0.9 and needed to be rewritten using the info from the next link below for firmware 1.5.4)<\/li>\n<li><a href=\"https:\/\/nodemcu.readthedocs.io\/en\/dev\/en\/modules\/net\/#netsocketsend\" target=\"_blank\">https:\/\/nodemcu.readthedocs.io\/en\/dev\/en\/modules\/net\/#netsocketsend<\/a><\/li>\n<\/ul>\n<h3>Setting up an access point with the ESP8266 or connecting as a client automatically:<\/h3>\n<ul>\n<li><a href=\"http:\/\/www.heliansys.com\/blog\/2015\/12\/20\/provisioning-the-esp8266-onto-a-wifi-network-via-mobile-phone\/\" target=\"_blank\">http:\/\/www.heliansys.com\/blog\/2015\/12\/20\/provisioning-the-esp8266-onto-a-wifi-network-via-mobile-phone\/<\/a><\/li>\n<\/ul>\n<h3>Voltage Divider info:<\/h3>\n<ul>\n<li><a href=\"https:\/\/learn.sparkfun.com\/tutorials\/voltage-dividers\/all?print=1\" target=\"_blank\">https:\/\/learn.sparkfun.com\/tutorials\/voltage-dividers\/all?print=1<\/a><\/li>\n<li><a href=\"https:\/\/startingelectronics.org\/articles\/arduino\/measuring-voltage-with-arduino\/\" target=\"_blank\">https:\/\/startingelectronics.org\/articles\/arduino\/measuring-voltage-with-arduino\/<\/a><\/li>\n<li><a href=\"http:\/\/www.esp8266-projects.com\/2016\/08\/esp8266-internal-adc-2-easy-way-example.html\" target=\"_blank\">http:\/\/www.esp8266-projects.com\/2016\/08\/esp8266-internal-adc-2-easy-way-example.html<\/a><\/li>\n<li><a href=\"http:\/\/jeelabs.org\/2013\/05\/16\/measuring-the-battery-without-draining-it\/index.html\" target=\"_blank\">http:\/\/jeelabs.org\/2013\/05\/16\/measuring-the-battery-without-draining-it\/index.html<\/a><\/li>\n<\/ul>\n<p><a href=\"http:\/\/www.adrianandgenese.com\/blogger\/2016\/09\/07\/nodemcu-esp8266-http-relay-control-with-12v-battery-monitor-and-wifi-configuration\/\">Read Part 1\u00c2\u00a0on how to set up a NodeMCU ESP8266 which provides a web interface for relay control, 12v battery monitor, and wifi configuration<\/a>.<\/p>\n<div id=\"wp_fb_like_button\" style=\"margin:5px 0;float:none;height:100px;\"><script src=\"https:\/\/connect.facebook.net\/en_US\/all.js#xfbml=1\"><\/script><fb:like href=\"https:\/\/www.adrianandgenese.com\/blogger\/2016\/09\/29\/nodemcu-esp8266-http-relay-control-with-12v-battery-monitor-and-wifi-configuration-part-2\/\" send=\"true\" layout=\"standard\" width=\"450\" show_faces=\"true\" font=\"arial\" action=\"like\" colorscheme=\"light\"><\/fb:like><\/div>","protected":false},"excerpt":{"rendered":"<p>Part 2. (looking for Part 1?) In our part 1 of this article we learned how to take a stock nodemcu esp8266 and flash it with the latest version of nodemcu. We also learned how to send and run files onto the unit using ESPlorer. In this final part 2, we will finally get to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[25,20],"tags":[204,208,206,205,23,216,207,202,212,22,209,201,203,213,211,210,214,215],"class_list":["post-1043","post","type-post","status-publish","format-standard","hentry","category-computers","category-hack","tag-12v","tag-12v-deep-cycle","tag-adc","tag-analog-read","tag-battery","tag-configure-wifi-using-browser","tag-dc","tag-esp8266","tag-http","tag-led","tag-monitoring","tag-nodemcu","tag-relay","tag-tcp-server","tag-webpage","tag-webserver","tag-wifi-access-point","tag-wifi-client"],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/preRH-gP","_links":{"self":[{"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/posts\/1043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/comments?post=1043"}],"version-history":[{"count":5,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/posts\/1043\/revisions"}],"predecessor-version":[{"id":1054,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/posts\/1043\/revisions\/1054"}],"wp:attachment":[{"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/media?parent=1043"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/categories?post=1043"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.adrianandgenese.com\/blogger\/wp-json\/wp\/v2\/tags?post=1043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}