Newbie builds a Soil Moisture Sensor on NodeMCU (ESP8266)








My friend is now enjoying the sun and the ocean in Thailand. I gave him a lift to the airport recently and in exchange he gave me a box with electronic stuff, wires, resistors and LEDs.
The package included the NodeMCU board which is amazingly small. I first couldn’t believe that this is a “small computer” with the WiFi built-in.
To explain you how newbie I am, I spent ~3 hours trying to connect it to my Mac (OS X El Capitan Version 10.11.1) before I realized that MicroUSB cable should be a proper one – the one which doesn’t only charges some device but is intended for data transfer. I used a MicroUSB cable from a Nokia cellphone.
This is what you’ll need to start the development of your first NodeMCU app:
Step #1: Install the drivers and make sure that the device is connected to a Mac
Install the CP210x USB to UART Bridge VCP Drivers – https://www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx
Connect a NodeMCU to your Mac.
Run Terminal and execute the command:
1 | ls -l /dev/tty* |
Make sure that you see something like this in the output:
1 | /dev/tty.SLAB_USBtoUART |
If not, as mentioned above, make sure that you are using the correct cable.
Step #2: Setup esptool.py and burn the firmware on your NodeMCU
Information on esptool.py can be found here: https://nodemcu.readthedocs.org/en/dev/en/flash/#esptool
I hope you already have git on your Mac. If not, google on how to install git. When done:
1 2 | git clone https://github.com/themadinventor/esptool.git cd esptool |
To make sure it worked, run the following:
1 | python esptool.py -h |
You should see the output as below which is a help for esptool:
1 2 3 4 | usage: esptool [-h] [--port PORT] [--baud BAUD] {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,flash_id,read_flash,erase_flash} ... ... |
Now we need to download the latest firmware for NodeMCU from here: https://github.com/nodemcu/nodemcu-firmware/releases
I downloaded the float-version of the firmware to the folder with esptool.py.
To burn the firmware run the following with changing SERIAL_PORT_NAME on /dev/tty.SLAB_USBtoUART (or a value that you got on the steps above):
1 | python esptool.py -p SERIAL_PORT_NAME write_flash 0x00 nodemcu_float_0.9.6-dev_20150704.bin |
If successful, you should see something like this in your terminal:
1 2 3 4 | Connecting... Erasing flash... Writing at 0x0004d800... (100 %) Leaving... |
I used the following article to burn the firmware: https://learn.adafruit.com/building-and-running-micropython-on-the-esp8266/flash-firmware
Step #3: Programming a NodeMCU
Install ESPlorer from here: http://esp8266.ru/esplorer/
Make sure your NodeMCU is plugged in.
Run ESPlorer.jar from Finder (you will need a Java on your Mac, obviously).
Select in the connection dropdown box a serial connection to NodeMCU.
On the left side of the main window of the application type the following:
1 | print("Hello World") |
Click Save and name the file as init.lua.
Explorer should save the file, upload it to the NodeMCU and run it. You should see “Hello World” in the console.
Now you are ready to build meaningful applications for NodeMCU.
Step #4: My meaningful(?) application
In the box that my friend gave me, there was a moisture sensor. The idea for the first application was obvious. I decided to measure the moisture level of the soil in the tree pot.
I used the following moisture sensor for the application:
https://www.fasttech.com/product/1380900-fc-28-soil-humidity-detection-sensor-module
It has 4 pins:
- VCC external 3.3~5 V
- GND external GND
- DO small plate digital output interface (0 and 1)
- AO – analogue output
I connected VCC to 3,3V pin on NodeMCU, GND to GND and AO to AO, pretty straightforward.
I put the following code of a simple TCP server to init.la via ESPlorer: http://letsmakerobots.com/node/43835
You first need to specify your local WiFi connection details. Fill in the values with your local WiFi router details:
1 2 3 | -- Your Wifi connection data local SSID = "xxxxxxxx" local SSID_PASSWORD = "xxxxxxxx" |
BTW, I played quite for a while with the different wifi modes of NodeMCU (STATION, STATIONAP, etc.). Follow this link for docs on modes: http://nodemcu.readthedocs.org/en/newdocs/en/modules/wifi/
Now, substitute the following code:
1 2 3 4 5 6 7 8 9 10 11 12 | local function connect (conn, data) local query_data conn:on ("receive", function (cn, req_data) query_data = get_http_req (req_data) print (query_data["METHOD"] .. " " .. " " .. query_data["User-Agent"]) cn:send ("Hello World from ESP8266 and NodeMCU!!") -- Close the connection for the request cn:close ( ) end) end |
with this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | local function connect (conn, data) local query_data -- Start a simple http server conn:on ("receive", function (cn, req_data) query_data = get_http_req (req_data) -- send moisture value to a client moist_value=adc.read(0) conn:send("HTTP/1.1 200 OK \r\n\r\n".."<h1>Moisture now is: "..moist_value.."</h1>") end) conn:on("sent", function(conn) conn:close() end) end |
If you click “RST” button in ESPlorer two times, emulating button-down and button-up on a board, a NodeMCU will reset.
Initialisation process will run init.lua from a device.
You will something like this in the console:
1 2 3 4 5 | NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4 Waiting for Wifi connection ESP8266 mode is: 1 The module MAC address is: 5e:cf:7f:15:a2:fb Config done, IP is 192.168.1.98 |
If you navigate in a browser to http://192.168.1.98/ you’ll see the page with the message: Moisture now is: NNN
If you play with the sensor values you will be able to understand when the soil is wet or dry. Don’t be afraid to put the sensor “legs” in the glass with water to identify the extreme values.
I used an empty box from iPod player to pack everything together and connect to a tree pot.











Question,
i tried to connect my moister sensor to my es8266, like you mentioned..
> I connected VCC to 3,3V pin on NodeMCU, GND to GND and AO to AO, pretty straightforward.
But.. i always receive 65535 as value…
next thing is that on the picture your wireing doesnt look like that you connected A0 A0 … on the right side of the nodemcu dev board there is no A0… or am i wrong ?
-> http://www.cnx-software.com/wp-content/uploads/2015/04/NodeMCU_Pinout.png
Dom, thanks for the comment.
Please refer to the NodeMCU documentation which explains the ADC Module: https://nodemcu.readthedocs.io/en/dev/en/modules/adc/
“If the ESP8266 has been configured to use the ADC for sampling the external pin, this function will always return 65535. This is a hardware and/or SDK limitation.”
Could you please confirm you’ve burnt the firmware as explained in the post?
I think different firmware versions may be compiled with different ADC configurations. Please make sure you use nodemcu_float_0.9.6-dev_20150704.bin referred in this article.
And regarding the photo: indeed the wiring there is not correct. This photo was taken when playing with digital output of the module. To read analog values, yo obviously need to connect AO of the module to A0 of the ESP8266
i dont know.. i think iam stupid….
i setup an docker VM to compile the new build… according to this article
https://hub.docker.com/r/marcelstoer/nodemcu-build/
i fetched the git repo and changed the file in nodemcu-firmware/bin/include/user_config.h to
// Byte 107 of esp_init_data_default, only one of these 3 can be picked
//#define ESP_INIT_DATA_ENABLE_READVDD33
#define ESP_INIT_DATA_ENABLE_READADC
//#define ESP_INIT_DATA_FIXED_VDD33_VALUE 33
after saving i build the firmware …
then i burnd it with nodemcu-flasher to adress 0x000000
…always get 65535 as value with the following code..
function doRun()
moistValue=adc.read(0)
—sysVoltage=adc.readvdd33()
print(“————————-“)
–print(“sys voltage: “..sysVoltage)
print(“moist value: “..moistValue)
end
tmr.alarm(0, 1000, 1, function()
if (pcall(doRun) == false) then
print(“error occured … restart node”)
node.restart()
end
end)
Pingback: Publishing MQTT messages from a NodeMCU – Soil Moisture Sensor – IoTalot
Wrote a long reply, managed to close the tab and now its all gone. Well, in short;
Aren’t you afraid of damaging the analog pin? I’ve read it only works with 0-1 volts, and my moisture meter (same as yours it seems) sends a 3 volt signal in dry soil and lower in wet soil.
And, when i use the float-version (same as mentioned above) ESPlorer gets really sluggish when i open the com port, but when i used the integer version it seems to work fine. Whats the difference? (haven’t read much about the differences yet, a project for another day)
Aksel, indeed ESP8266 chip can measure analog voltages in 0V-1V range. However, if you use NodeMCU dev kit board also known as ESP-12, it has on-board voltage divider composed from 220k and 100k resistors, so you can measure voltages up to 3.3v directly. If you use any other board, it is likely that it does not have a voltage divider so you should add your own with parameters depending on desired voltage range. You can find schematics of NodeMCU devkit here https://github.com/nodemcu/nodemcu-devkit/blob/master/Documents/NODEMCU_DEVKIT_SCH.png.
And I do not notice any difference in performance of ESPlorer with int and float firmwares, so I only can guess it depends on your custom files and code.
Ah, a million thanks! Been fiddling with it for a couple of hours and could not understand the values i got when probing around.
First thanks for the code example, the project is great. Just to help others newer than me, if you are not seeing the correct values is because you have not a firmware compiled for use of ADC. My suggestion is go to this web page> http://nodemcu-build.com/index.php and build an custom firmware and make sure you select ADC from the list of extra modules to be include in the custom firmware.
Thanks again, great now lets play with it ..