Tag Archives: dc

NodeMCU ESP8266 http relay control with 12v battery monitor and wifi configuration – Part 2

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 the guts of the how to set up a NodeMCU ESP8266 which provides a web interface for relay control, 12v battery monitor, and wifi configuration.

Some newbie hints on coding the NodeMCU ESP8266 with Lua scripts

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’t cause a kernel panic and leave you in an endless bootloop.

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.

Below is an example with the line calling the main.lua file to run commented out so I can just run it manually instead of automatically on startup:

Init.lua for testing

-- init.lua --

wifi.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.

--Set a static ip so its easy to access
cfg = {
    ip="192.168.1.175",
    netmask="255.255.255.0",
    gateway="192.168.1.1"
  }
wifi.sta.setip(cfg)

--Your router wifi network's SSID and password
wifi.sta.config("SSID","PASSWORD")
--Automatically connect to network after disconnection
wifi.sta.autoconnect(1)
print ("\r\n")
--Print network ip address on UART to confirm that network is connected
print(wifi.sta.getip())

-- run main --
-- dofile("main.lua") --

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!

The Hardware

My basic battery charger relay control and battery voltage monitor over http project involves just a few parts:

  1. A NodeMCU ESP8266 development board off ebay, or you can buy one from amazon here
  2. One (1) 110v-240v 30A 5v relay (to switch the power on or off to the battery charger)
  3. One (1) LED (visual indicator to show if charging or not – optional)
  4. Two (2) 1/4W resistors (I used a 1M ohm for R1 and a 330k ohm for R2 to make a voltage divider)
  5. One (1) Ceramic Disc .1uf 25v Capacitor (to normalize the voltage readings)

Wiring the NodeMCU to the hardware

Wiring is pretty straightforward: Im using the v0.9 NodeMCU development board but could only find the NodeMCU v1.0 image for the illustration below, but the pinout is pretty much the same. Just pay attention to the pin designations:

RIGHT Side of NODEmcu
D1 - relay in
D2 - relay in
D3 - LED +
GND - Relay Ground (if desired)
D5 - Switch (other side of switch pin is shorted to battery ground)
GND - LED Ground

LEFT side of NODEmcu
A0 - to middle of voltage divider
GND - Common Battery Ground (or relay ground)
5V - to relay 5V

 

nodemcu_schematic

nodemcu_schematic_zoom

Some hints on wiring:

  1. I’m powering the ESP8266 board with a USB power adapter so there isn’t any power source shown
  2. Remember that R1 is the resistor closest to positive and that R2 is the resistor closest to negative (ground).
  3. If you get a small ceramic disc capacitor, the leads are not polarized and can be connected whichever way.
  4. Dont forget to connect the NodeMCU board GND to Battery GND or the analog read values will be wrong.
  5. I know in the illustration above, the LED leads are reversed and I also didn’t add a resistor to the LED (but the LED seems to be fine).
  6. 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. But 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.

Calculating voltage divider values (the hardware side)

The ESP8266 Analog read pin (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, we 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.

Be aware that the higher the resistance of the resistors, the lower the readings you’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’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’m using). The reason that i’m using higher resistance value resistors is because i’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 µA.

To calculate the resistor values you will need for your application, head over to this great resource which teaches you the basics: https://learn.sparkfun.com/tutorials/voltage-dividers/ (There’s also a handy voltage divider calculator for you to use to determine your specific resistor values.)

If youre already overwhelmed, just keep in mind that the main 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.

voltagedivider

Two resistors with the correct resistance ratio will divide your input voltage

Finding your LSB to calibrate your voltage…WTF? – The software side

If you’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…its what I sounded like when trying to wrap my head around this analog read calibration concept.

Its simple once you get your head around it though.

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 in the range of 0-1024. This doesn’t help us much, so we just have to apply a little division to get real world values (the voltage level) from the 0-1024 reading.

mathtime

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 ‘READ DC VOLTAGE’ button on the battery charger control webpage.

Get the ADC value by clicking the READ DC VOLTAGE button on the battery charger control webpage

Get the ADC Value by clicking the READ DC VOLTAGE button on the battery charger control webpage

 

For example:

Multimeter reading  of battery = 12.56v
ADC Value reading from adc pin in ESPlorer console = 581
Math: 12.56/581 = LSB
LSB = 0.02161790

Now just use that LSB number to replace the LSB number in the main.lua script below and your voltage reading will be calibrated for our project!

The Code

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’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 everything work.

Download: (right click and save link as…)
INIT.LUA
MAIN.LUA

The battery charger control webpage

The battery charger control webpage

INIT.LUA – A description

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 “BatteryNode” with password of “password” which you can then connect to using a phone or computer. Once your device is connected to the “BatteryNode” 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 “BatteryNode” AP or you wont be able to navigate to the IP).

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 case sensitive. Weird hangups or kernel panics happen when you don’t enter the credentials exactly. If you enter in an SSID that does not exist, the unit will kernel panic and reboot.

Wifi configuration section

Wifi configuration section

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’ll be disconnected from the “BatteryNode” AP. It will also assign itself a static IP of 192.168.1.175

If you’re going to be using the ESP8266 unit on a different subnet than specified in the scripts, you’ll need to change the IP configuration in the init.lua script to match yours. You may also just comment out the lines below in order for the unit to get its IP address using DHCP.

init.lua

--Set static IP info with configuration above
	wifi.sta.setip(cfg)

AND

-- run main --
 
wifi.sta.setip(cfg)

Init.lua code

--Test wireless connection. If not connected to an access point, set itself as an AP so wifi can be configured with a browser

--Client static IP when connected to an access point
	cfg = {
		ip="192.168.1.175",
		netmask="255.255.255.0",
		gateway="192.168.1.1"
	}
	
--Static IP when in AP mode
	accessPointIpConfig = {}
	accessPointIpConfig.ip = "192.168.2.1"
	accessPointIpConfig.netmask = "255.255.255.0"
	accessPointIpConfig.gateway = "192.168.2.1"
	
--AP credentials	
	accessPointConfig = {}
	accessPointConfig.ssid = "BatteryNode"   -- Name of the SSID you want to create
	accessPointConfig.pwd = "password"    -- WiFi password - at least 8 characters or it screws up

function onboardserver()
print('Running Main Runtime')
dofile("main.lua")
end

print('Testing Wifi Connectivity')
print(wifi.getmode())

count=0

tmr.alarm(1,1000, 1, function() 
print('.')
 if wifi.sta.getip()==nil then 
		
		if count == 5 then
		print('Starting Main Runtime in 3 seconds')
		tmr.stop(1) 
				
				if(wifi.getmode() ~= 3) then
				print('changing wifi mode to stationAP')
				
				--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.

				wifi.setmode(wifi.STATIONAP)
				
				--Set AP mode with credentials above
				wifi.ap.config(accessPointConfig)
				wifi.ap.setip(accessPointIpConfig)
				
				--Print Status on console
				print('AP MAC: ',wifi.ap.getmac())
				print('SSID: ',accessPointConfig.ssid)
				print('PASS: ',accessPointConfig.pwd)
				print ('AP IP: ',wifi.ap.getip());
 
				end

		tmr.alarm(0,3000,0,onboardserver)
		else
		count = count + 1 
		end
 
 
 else 
 
 		if(wifi.getmode() ~= 1) then
		print('changing wifi mode to station only')
		wifi.setmode(wifi.STATION)

		--Set static IP info with configuration above
		wifi.sta.setip(cfg)

		wifi.sta.autoconnect(1)
				
		--Print network IP Info
		print("Connected as a station only")
		print('Client IP: ',wifi.sta.getip())
		print('Client MAC: ',wifi.sta.getmac())
		
 
 end
 tmr.stop(1)
 
 -- run main --
		
wifi.sta.setip(cfg)
--Print network IP Info
		print("Connected as a station only")
		print('Client IP: ',wifi.sta.getip())
		print('Client MAC: ',wifi.sta.getmac())
		
dofile("main.lua")

 end 
end)

MAIN.LUA – A description

Main.lua handles the main processing of commands, it sets up the pins, defines the variables, and serves the website. Remember the LSB value you calculated earlier? You’ll need to remember to replace the LSB value in the main.lua file with your own LSB for it to correctly show your voltage on the webpage.

The ESP8266 will remember the relay state indicated by “OFF” or “ON”

The battery charger control webpage

Relay Control buttons

The readings will also change color of the voltage reading based on the following table (I skipped the orange color so its just green, yellow, and red).

battery-state-of-charge

batterychargercontrol2

webpage voltage reading in green

Main.lua code

-- main.lua --

----------------------
-- Global Variables --
----------------------

-- DEBOUNCE FOR EMI WITH LARGE VOLTAGE USING WEB INTERFACE --
ignore = 0

-- RELAY PINS --
Relay1 = 1
Relay2 = 2

-- SWITCH PIN --
pin = 5

-- LED PIN --
led_pin = 3

-- ADC PIN AND DEFAULT VALUE --
adc_id = 0 
adc_value = 0

-- VOLTAGE MONITOR COLOR AND STATUS --
adc_color = "#FFFFFF"
status_relay = "OFF"
status_color = "#FFFFFF"

-- VOLTAGE MONITOR VARIABLES --
-- CALIBRATION: calibrate LSB by dividing voltage read by multimeter by adc_value
ad = 0
adt = 0
LSB = 0.02162348 

----------------
-- GPIO Setup --
----------------
print("Setting Up GPIO...")

-- SET GPIO PINS FOR RELAY --
gpio.mode(Relay1, gpio.OUTPUT)
gpio.write(Relay1, gpio.LOW);

gpio.mode(Relay2, gpio.OUTPUT)
gpio.write(Relay2, gpio.LOW);

-- SET GPIO FOR SWITCH PIN --

gpio.mode(pin, gpio.INT, gpio.PULLUP)

---------------
-- LED SETUP --
---------------
print("LED SETUP")

-- SET LED TO OFF --
gpio.mode(led_pin, gpio.OUTPUT)
gpio.write(led_pin, gpio.LOW);

-- Enable PWM output behavior on startup if desired --
-- pwm.setup(led_pin, 2, 800) -- 2Hz, 50% duty default
-- pwm.start(led_pin)


----------------------------------
-- SWITCH AND DEBOUNCE FUNCTION --
----------------------------------

function debounce (func)
    last = 0
    delay = 50000 -- 50ms * 1000 as tmr.now() has μs resolution

    return function (...)
        now = tmr.now()
        delta = now - last
        if delta < 0 then delta = delta + 2147483647 end; -- proposed because of delta rolling over, https://github.com/hackhitchin/esp8266-co-uk/issues/2
        if delta < delay then return end;

        last = now
        return func(...)
    end
end

function onChange ()
    print('The pin value has changed to '..gpio.read(pin))
	
	switchpin = (gpio.read(pin))
	
	--If switch is closed then Relays are ON
	if switchpin == 0 then
	
		pwm.setup(led_pin, 2, 512)
		pwm.start(led_pin)
		gpio.write(Relay1, gpio.HIGH)
		gpio.write(Relay2, gpio.HIGH)
		status_relay = "ON"
		status_color = "#00ff00"
		print("SWITCH ON")
	
		end
	
	--If switch is open then Relays are OFF but only if not turned on with web interface first
	if switchpin == 1 and ignore == 0 then
		
		gpio.write(Relay1, gpio.LOW)
		gpio.write(Relay2, gpio.LOW)
		pwm.stop(led_pin)
		status_relay = "OFF"
		status_color = "#ccccb3"
		print("SWITCH OFF")
		
	end
	
	--If switch is open and web interface turned on relays before, then do nothing
	if switchpin == 1 and ignore == 1 then
		print("EMI DEBOUNCE or WEB SWITCH ON")
		
	end
	
end

gpio.trig(pin, 'both', debounce(onChange))

----------------
-- Web Server --
----------------
print("Starting Web Server...")
-- Create a server object with 30 second timeout
srv = net.createServer(net.TCP, 30)
srv:listen(80, function(conn)

  conn:on("receive", function(sck, payload)
 
  
  -- another function
	function esp_update()
            mcu_do=string.sub(payload,postparse[2]+1,#payload)
						         
        -- Change color of Voltage according to voltage health table for 12v batteries --
		
            if mcu_do == "READ+DC+VOLTAGE" then
            	adc_value = adc.read(adc_id)
				
				-- Voltage conversion from ADC numbers to Voltage numbers --
					ad = adc_value*LSB
									
				-- Truncate the extra decimal values	
					adt = string.format("%02.2f",ad)
					print(adt)
            	
				-- If values are above 12.2v then show as GREEN
				if ad >= 12.2 then
					adc_color = "#00ff00"
					
				-- If values are below 12.2v and above 11.7v then show as YELLOW
				elseif ad >= 11.7 and ad < 12.2 then
					adc_color = "#ffcc00"
				
				--If values are below 11.7v then show as RED
				elseif ad < 11.7 then
					adc_color = "#b30000"
				end
				
								
				-- 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.
				if ad >= 13.3 and ad < 13.4 then
					adt = "Float Charging..."
					print("Float Charging...")
					
					elseif adc_value < 1023 then
		
					print("ADC Value   : ", adc_value)
					print("Real Voltage: ", ad)
					print("Adjusted Voltage: ", adt)
				end
							
			end
        
		-- If turn on web button is clicked
		if mcu_do == "TURN+ON" then
		
				-- Debounce EMI with web control (dont allow interrupt GPIO to turn off relays)--
				ignore = 1
				
				pwm.setup(led_pin, 2, 512)
				pwm.start(led_pin)
				gpio.write(Relay1, gpio.HIGH)
				gpio.write(Relay2, gpio.HIGH)
				status_relay = "ON"
				status_color = "#00ff00"
				print("RELAY ON")
		end
		
		--If turn off web button is clicked
		if mcu_do == "TURN+OFF" then
		
				-- Debounce EMI with web control (allow interrupt GPIO to turn off relays)--
				ignore = 0
				
            	gpio.write(Relay1, gpio.LOW)
				gpio.write(Relay2, gpio.LOW)
				pwm.stop(led_pin)
				status_relay = "OFF"
				status_color = "#ccccb3"
				print("RELAY OFF")				
		end
		
		if mcu_do == "CONFIGURE+WIFI" then
			
        ssid = string.sub(payload,string.find(payload,"ssid=")+5,
		string.find(payload,"&password")-1)
		pw = string.sub(payload,string.find(payload,"password=")+9,string.find(payload,"&mcu")-1)
		
			--If any wifi config fields are blank then ignore
		 	if ssid == "" or pw == "" then 
			print("Empty fields not applying wifi config")
			
			--If wifi config fields populated then attempt to connect to wifi
			elseif ssid ~= "" or ps ~= "" then
		
			print("Connecting to AP:",ssid)
		
			--Set ESP to station mode only and to disable the ESP in AP mode
			wifi.setmode(wifi.STATION)
		
			--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.
			wifi.sta.config(ssid,pw,1)
		
			--Restart ESP in case it hangs on re-connection. This will prevent MCU from being unreachable.
			node.restart()
		
			--After wireless is configured this sets up a static IP as configured in init.lua
			--wifi.sta.setip(cfg)
			
			end
			
			
		end
		
	end
		
            
        --Parse position POST value from header
		postparse={string.find(payload,"mcu_do=")}
		

        --If POST value exist, run the Functions above
        if postparse[2]~=nil then esp_update()end
  
  
	--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.
    local response = {}

    response[#response + 1] = '<html>\n'
    response[#response + 1] = '<center>\n'
    response[#response + 1] = '<head><meta content="text/html; charset=utf-8">\n'
	response[#response + 1] = '<title>Battery Charger Control</title></head>\n'
	response[#response + 1] = '<body><h1 style="font-family:verdana;">Battery Charger Control</h1>\n'
	response[#response + 1] = '<form action="" method="POST">\n'
	response[#response + 1] = '<table border=\"1\" width=\"400\" bordercolorlight=\"#000000\" bordercolordark=\"#008000\" height=\"137\"><tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" bgcolor=\"#339FFF\" align=\"center\"><b>'
	response[#response + 1] = '<font face=\"Verdana\" size=\"2\" color=\"#FFFF99\">BATTERY CHARGER:</font><p><font face=\"Verdana\" size=\"6\" color=\"'..status_color..'\">'..status_relay..'</font><p></b></td></tr>'
	response[#response + 1] = '<tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" align=\"center\"><p><input type="submit" name="mcu_do" value="TURN ON" style="height:100px; width:300px; font-size: 30px;"><p></b></font></a></td>'
	response[#response + 1] = '<tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" align=\"center\"><p><input type="submit" name="mcu_do" value="TURN OFF" style="height:100px; width:300px; font-size: 30px;"><p></b></font></td><font face=\"Verdana\"></b></font></td></tr></table>'
	response[#response + 1] = '<BR>'
	response[#response + 1] = '<table border=\"1\" width=\"400\" bordercolorlight=\"#000000\" bordercolordark=\"#008000\" height=\"137\"><tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" bgcolor=\"#339FFF\" align=\"center\"><b>'
	response[#response + 1] = '<font face=\"Verdana\" size=\"2\" color=\"#FFFF99\">BATTERY VOLTAGE:<p><font face=\"Verdana\" size=\"6\" color=\"'..adc_color..'">'..adt..'</font></b></td></tr>'
	response[#response + 1] = '<tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" align=\"center\"><p><input type="submit" name="mcu_do" value="READ DC VOLTAGE" style="height:100px; width:300px; font-size: 30px;"><p></b></font></form></td>'
	response[#response + 1] = '<table border=\"1\" width=\"400\" bordercolorlight=\"#000000\" bordercolordark=\"#008000\" height=\"137\"><tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" bgcolor=\"#339FFF\" align=\"center\"><b>'
	response[#response + 1] = '<font face=\"Verdana\" size=\"2\" color=\"#FFFF99\">WIFI CONFIG</b><br><font face=\"Verdana\" size=\"1\" color=\"#FFFF99\">NOTE: Characters are CASE SENSITIVE</font></td></tr>'
	
	response[#response + 1] = '<BR>'
	response[#response + 1] = '<tr><td style=\"border-style: solid; border-width: 1px\" width=\"91\" align=\"center\"><p><form action="" method="POST">'
	response[#response + 1] = '<font face=\"Verdana\" size=\"1\">SSID:</font>'
	response[#response + 1] = '<br>'
	response[#response + 1] = '<input type="text" name="ssid" id="inputtext">'
	response[#response + 1] = '<p>'
	response[#response + 1] = '<font face=\"Verdana\" size=\"1\">Password:</font>'
	response[#response + 1] = '<br>'
	response[#response + 1] = '<input type="text" name="password" id="inputtext">'
	response[#response + 1] = '<br>'
	response[#response + 1] = '<input type="submit" name="mcu_do" value="CONFIGURE WIFI" id="submit"><br><font face=\"Verdana\" size=\"1\">STATIC IP: 192.168.1.175</font></b></font></td>'
	response[#response + 1] = '</form>'
	response[#response + 1] = '</center>\n'
	response[#response + 1] = '</body></html>\n'
	
	     -- sends and removes the first element from the 'response' table
    local function send(sk)
      if #response > 0
        then sk:send(table.remove(response, 1))
      else
        sk:close()
        response = nil
      end
    end

    -- triggers the send() function again once the first chunk of data was sent
    sck:on("sent", send)

    send(sck)
  end)
end)

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.

Some final thoughts and credit where credit is due

I’m sure the scripts could be optimized and reduced in size, and I welcome any tweaks or comments to anything i’ve written above. What i’ve essentially done is taken some smoothly written code from all over the internet and adapted it for my 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’t have done this project without them.

TCP/IP Http server with NodeMCU:

Setting up an access point with the ESP8266 or connecting as a client automatically:

Voltage Divider info:

Read Part 1 on how to set up a NodeMCU ESP8266 which provides a web interface for relay control, 12v battery monitor, and wifi configuration.

NodeMCU ESP8266 http relay control with 12v battery monitor and wifi configuration – Part 1

PART 1. (looking for Part 2?)

ESP8266 internet stuff

The Esp8266 is an amazingly inexpensive wifi device which has all sorts of support from all sorts of IDE’s and Firmware. The problem is that the majority of ESP8266 information on the internet on how do to a simple thing such as control a relay using NodeMCU on a NodeMCU v0.9 development board and measure voltage with it is a little difficult to sort through. Sure, there’s tutorials using NodeMCU 0.9.5 or 0.9.6 on how to drive a relay, and a separate tutorial on how to create an easy http web page using 0.9.6, and even another tutorial on how to configure the ESP8266 as an access point…that’s not the issue. The problem (imho) is that the information takes days to sort through and figure out…especially if you’re a beginner in electronics like me because lots of the information isn’t that detailed, nor is it current for the ESP8266 NodeMCU development. Add to the problem the different versions and hardware differences of the ESP8266 whether be it an ESP-01 (which I have and absolutely hated), or an ESP8266 based development board (which is the best route for beginners like me) which one needs to take into account.

all_esp_modules1

So this is my attempt to help guide someone who is beginning to familiarize themselves with the ESP8266 in getting the ESP8266 working with NodeMCU (and LUA scripts).

What I wanted to accomplish with the ESP8266

My problem was simple. I have a boat up in Shasta that has an electric trolling motor, and this motor needs a 12v deep cycle battery to function during boating season. I probably take 5 trips up to Shasta during the year where each trip I would take the battery up, and bring it back down to the SF bay area so I could keep the battery charged and in good health. Lugging the battery back and forth is a hassle as the battery is heavy and bulky, and it uses up gas and space in my van. I really wished I didn’t have to keep taking that battery with me every trip and wanted to be able to set up a system where I could leave the battery plugged into the old 20amp charger I had been given, leave it in the garage, and monitor and control everything through the internet.

Enter the ESP8266 NodeMCU v0.9 development board

The ESP8266 is cheap. I mean dirt cheap. It has the ability to act as a wifi client, wifi access point, or both at the same time! It also has an embedded TCP/IP stack which allows it to run a simple http server and do all sorts of neat things with it. If one opts for the ESP8266 development boards, such as the nodemcu v0.9 or v.1.0, the additional GPIO/ADC/VDC/GND pins make the platform even more attractive. Because of these offerings, the ESP8266 based NodeMCU development board was the best solution for me.

I initially purchased an ESP8266-01 module but got tired of working with it because its two GPIO pins need additional hardware bits to make it not boot up in Flash mode, and the hassle of flashing, powering, and connecting the 3.3v serial lines made me want to bash that little module to pieces almost every time I worked with it.

In the end, I ordered one of the NodeMCU v0.9 boards off ebay for less than $5.  And that was the easiest part of the entire project.

nodemcu

Update the ESP8266 with the latest NodeMCU firmware

So now that you have the board in your hands, the first thing to do is get a current version of NodeMCU on it. DO NOT USE NodeMCU v.0.9.6 or lower based firmware. I’m warning you. Everywhere on the internet talks about v0.9.5 and v0.9.6 but its all old info. They are full of weird bugs, and those versions just don’t work very well. You also cant expect that a lua script written for those versions will work on newer firmware based on 1.4+, so you’ll end up rewriting your scripts…

Ill tell you a story…After a few days of coding (by which I mean cutting and pasting other peoples brilliant code into my own) I had a basic http server running a web page that would let me turn a relay on and off. It worked great on my local WIFI, but as soon as I wanted to VPN into my network and access the webpage, it wouldn’t work. Some googling led me to learn that it was a bug in the MTU size and that newer firmware from v1.4+ fixed it. Ok no problem I thought, ill just update the firmware. Easy right? NOPE. but keep reading and Ill guide you through it.

First thing you need to know is that new binaries aren’t pre-compiled for NodeMCU anymore, and although there’s a few ways to get the firmware, I found the easiest and most elegant solution is the NodeMCU custom builds site. This site compiles the firmware for your ESP8266 and allows you to download the binary to run the latest versions of NodeMCU on your ESP8266.

Compile the NodeMCU firmware

  1. Navigate to https://nodemcu-build.com/ then enter in your email information.
Enter in your email info as the download info for your firmware is emailed to you.

Enter in your email info as the download info for your firmware is emailed to you. Also, just use the master branch.

2. Next, just select the modules to include.

Select your options, for my project I needed: adc, file, gpio, net, node, pwm, tmr, uart, wifi.

Select your options. For my project I needed: adc, file, gpio, net, node, pwm, tmr, uart, wifi.

 3. Scroll down and click the ‘Start your Build’ button (I didn’t check any of the miscellaneous options).

Download the firmware

Once your build finishes, you’ll get an email with the download information. I used the float binary as I was going to be working with decimal numbers. Note: The Integer build is for projects which don’t really require working with decimal numbers. The integer version is smaller and will free up a little space on your ESP8266, but I didn’t have any issues with the Float binary and space requirements. Download and save to your computer.

After you get your firmware you’ll need an easy way to flash the firmware to the ESP8266 board.

Flash NodeMCU to your ESP8266 with ESP8266Flasher

What I have been using (and i’ve used almost all of the other tools) which works very well is the ESP8266Flasher tool.

Get it here: https://github.com/nodemcu/nodemcu-flasher and click the green ‘clone or download’ button on the right hand side of the screen. Download the Zip file and extract it somewhere.

  1. Connect your ESP8266 then run the ESP8266Flasher tool. It will look like this:

ESP8266Flasher

 

2. Specify the firmware and memory addresses.

Next you’ll need to configure the ESP8266Flasher to flash the file you just downloaded from the NodeMCU custom build link which was emailed to you. You will also need to flash an esp_init_data_default.bin file to the specific memory address shown below. The reason being is that with the newer ESP8266 firmware, the init data memory address locations change. So if you do not flash the esp_init_data_default.bin file to the correct address, the ESP8266 unit wont boot properly (ask me how I know this).

Download: esp_init_data_default.bin

 

pay attention to the memory addresses

pay attention to the memory addresses under the ‘config’ tab

Below is a table with other assorted memory address locations for different flash capacities in case you need them. The NodeMCU v0.9 has a 4096 capacity.

more addresses

3. Flash NodeMCU firmware on the ESP8266.

Finally, click back over to the Operation tab, select the com port your ESP8266 is on, and then click the Flash(F) button. At this point the unit will start flashing. Once its done there are still a few more steps to do to get the unit working correctly. But at least the firmware has been loaded onto the ESP8266. If the flash fails, dont worry, just can just reflash it again.

The awesome ESPlorer tool

Now that we’ve gotten the ESP8266 flashed with a current version of NodeMCU (v.1.5.4 at the time of this writing), we now need a different tool to upload lua scripts, test commands, see terminal output from the ESP8266, do other useful things such as format the file system, and run files located on the ESP8266.

esplorertool

 

Get Esplorer: http://esp8266.ru/esplorer/

Scroll to the bottom of the page and download the latest release. The software requires JAVA (SE version 7 and above) installed.

Once you have the software installed and running, the very first thing you need to do is format the ESP8266 file system, and we can do this with ESPlorer. Until you do, the unit will not run correctly and may display all sorts of weird gibberish on the screen.

To Format the file system on the ESP8266 follow these directions:

esplorerright

  1. Select the com port your ESP8266 is on.
  2. Click on the open Button to open a connection (choose 115200 baud)
  3. Click on any of the buttons Heap, Chip Info, Chip ID, or Flash ID to establish connection with the unit (once the red Reset button becomes clickable you know you are connected). If ESPlorer seems to not be able to connect to the MCU, press the reset button on the circuit board while the com port is still open. The unit should then respond to commands.
  4. Click on the format button. You will need to wait a bit for the terminal to tell you the format is complete as there is no status on the process during formatting. Be patient at this part.
  5. Once the format of the file system is complete, click the reset button and reboot the ESP8266.

The ESP8266 should now boot and show you the console output declaring the correct firmware that is loaded onto the unit. It may look something like this image below:

firmwareboot

Your ESP8266 is now running the latest NodeMCU firmware! Now we can finally start uploading lua scripts.

In order to upload lua scripts, you just need to follow steps 1-3 as listed above to establish a working connection to the ESP8266. Next, click the Upload button near the bottom middle of the screen. You’ll then get to browse and select a file to upload.

esplorerleft

What I have found is that uploading one file at a time works the best. I’ve had strange hangups when trying to upload more than one at a time.

filesystem

ESPlorer showing filesystem information and a clickable list of the .lua files on the right

Once you’ve uploaded a few files, you can just use ESPlorer to list the files, and click on them to run them. Follow the directions below to list and run a file on the ESP8266 file system using Esplorer:

  1. Establish an open connection to the unit (steps 1-3 written above)
  2. Click on the Reload button (a list of all files on the file system should appear under the Reload button).
  3. Click on a lua file button to run it.

You now know the basics of uploading and manually running lua scripts on the ESP8266 running NodeMCU v1.5.4!

Read Part 2 on how to set up a NodeMCU ESP8266 which provides a web interface for relay control, 12v battery monitor, and wifi configuration.