environmental monitoring with Guardian Smart Polling
Essentially, Guardian can Smart Poll any SNMP OID (v1, 2c, or 3). Which means you could create a Smart Polling strategy to monitor just about anything you want from the Guardian sensor - temperature, pressure, fan status, HVAC status, battery remaining power; the possibilities are limitless.
The steps outlined below are simply a proof-of-concept to demonstrate the capability.
Physical components you will need:
DS18B20 temperature sensor (1)
NodeMCU v1.0 (ESP-12E) (1)
RasberryPi 3B (1)
Jumper wires, male (3)
Small breadboard (1)
Software components you will need:
snmp (install on Raspberry Pi)
snmpd (install on Raspberry Pi)
snmp-mibs-downloader (Raspberry Pi)
lua (install on Raspberry Pi)
lua-socket (install on Raspberry Pi)
nodemcu firmware (install on NodeMCU)
esptool.py (install on host machine or Linux virtual image)
ESPlorer (install on host machine or Windows virtual image)
LUALoader (install on host machine or Windows virtual image)
Guardian v21.5 with Smart Polling
Build the circuit
You need to lay out the physical components on a breadboard and connect them with jumper wires. You'll end up with this:
Install required software on Rasberry Pi 3B
These components will allow you to run Lua scripts on the Raspberry Pi 3B and to allow the Guardian sensor to poll SNMP data on the Raspberry Pi.
sudo apt install lua5.1
sudo apt install lua-socket
sudo apt install snmp
sudo apt install snmpd
sudo apt install snmp-mibs-downlaoder
Clone nodemcu firmware into local repository on Linux host and build firmware with default configuration
You need to replace the default firmware that comes with the NodeMCU v.10 (ESP-12E) with alternate firmware that will allow you to run Lua scripts on the NodeMCU.
git clone --recurse-submodules https://github.com/nodemcu/nodemcu-firmware.git
cd nodemcu-firmware/
make
The build process will create two files in the bin/ directory. One is a boot loader (0x00000.bin) and the other is the firmware (0x10000.bin).
cd bin/
ls
0x00000.bin 0x10000.bin
Flash NodeMCU v1.0 (ESP-12E) with newly created firmware
Plug the NodeMCU v1.0 (ESP-12E) into your Linux host USB port and confirm that you see the Silicon Labs UART bridge connected.
lsusb
Bus 002 Device 006: ID 10c4:ea60 Silicon Labs CP210X UART Bridge
In order to use the new firmware you have to flash the NodeMCU v1.0 (ESP-12E). There are several ways to accomplish this, but I am familiar with the esptool.py method on the Linux host.
I recommend installing this tool from source which you can get from the Espressif github repository - https://github.com/espressif/esptool. Since this is a Python script, you will need Python installed on your Linux host.
On my Linux host --port is /dev/ttyUSB0. You will need to confirm this on yours. If you are not running as root (you shouldn't be) you will need to put yourself in the dialout group in order to access /dev/ttyUSB0, otherwise you will get a permissions error.
esptool.py --port /dev/ttyUSB0 write_flash 0x00000 0x00000.bin
esptool.py --port /dev/ttyUSB0 write_flash 0x10000 0x10000.bin
Create Lua script on Raspberry Pi 3
I modified a script I found online and named it temp_monitor.lua. Put this in your /home/pi/lua directory.
#!/usr/bin/lua
-- Setup UDP socket. Bind to localhost, port 9999
local socket = require "socket"
local udp = socket.udp()
udp:settimeout(0) -- indicates not to wait. If no data, return immediately
udp:setsockname('192.168.1.33', 9999)
local data = ''
local mac = ''
local msg_or_ip
local port_or_nil
local tempC = ''
local tempF = 0.0
print 'Beginning server loop'
while true do
data, msg_or_ip, port_or_nil = udp:receivefrom() -- receive UDP packet
if data then
mac, tempC = string.match(data, '(.+):(.+)')
tempF = (tonumber(tempC)/10000)*2 + 30
print('temp: ' .. tempF .. 'F')
os.execute('echo '..tempF..'>/tmp/'..mac)
elseif msg_or_ip ~= 'timeout' then
error("Unknown network error: "..tostring(msg))
end
socket.sleep(0.01) -- sleep .01 secs
end
Create Lua scripts for NodeMCU v1.0 (ESP-12E) and load them onto the newly flashed controller.
I also found some examples online and modified them for this part. You'll need two scripts:
init.lua - an init.lua script is a required file. Upon startup the firmware reads the filesystem and looks for this file which serves to execute other files on the file system:
--print("ESP8266 module start, please wait...")
function startup()
if abort == true then
print('startup aborted')
return
end
print('Starting xmitTemp')
dofile('xmitTemp.lua')
end
startup()
--
abort = false
print('Startup in 5 seconds')
local mytimer = tmr.create()
mytimer:register(5000,1, function (t)
mytimer:start()
end
)
xmitTemp.lua - this is the core program which will read the temp sensor, establish a wifi connection to your network and send the sensor data via UDP to the Raspberry Pi 3 running temp_monitor.lua.
You will need to change the SSID and PASSWORD values in your script to match your network parameters. You will also need to change the IP address in the script to point to the IP assigned to your Raspberry Pi 3.
function getTemp()
local addr = nil
local count = 0
local data = nil
local pin = 4 -- pin connected to DS18B20
local s = ''
-- setup gpio pin for oneWire access
ow.setup(pin)
-- do search until addr is returned
repeat
count = count + 1
addr = ow.reset_search(pin)
addr = ow.search(pin)
tmr.wdclr()
until((addr ~= nil) or (count > 100))
-- if addr was never returned, abort
if (addr == nil) then
print('DS18B20 not found')
return -999999
end
-- validate addr checksum
crc = ow.crc8(string.sub(addr,1,7))
if (crc ~= addr:byte(8)) then
print('DS18B20 Addr CRC failed');
return -999999
end
if not((addr:byte(1) == 0x10) or (addr:byte(1) == 0x28)) then
print('DS18B20 not found')
return -999999
end
ow.reset(pin) -- reset onewire interface
ow.select(pin, addr) -- select DS18B20
ow.write(pin, 0x44, 1) -- store temp in scratchpad
tmr.delay(1000000) -- wait 1 sec
present = ow.reset(pin) -- returns 1 if dev present
if present ~= 1 then
print('DS18B20 not present')
return -999999
end
ow.select(pin, addr) -- select DS18B20 again
ow.write(pin,0xBE,1) -- read scratchpad
-- rx data from DS18B20
data = nil
data = string.char(ow.read(pin))
for i = 1, 8 do
data = data .. string.char(ow.read(pin))
end
-- validate data checksum
crc = ow.crc8(string.sub(data,1,8))
if (crc ~= data:byte(9)) then
print('DS18B20 data CRC failed')
return -9999
end
-- compute and return temp as 99V9999 (V is implied decimal-a little COBOL there)
return (data:byte(1) + data:byte(2) * 256) * 625
end -- getTemp
function xmitTemp()
local temp = 0
temp = getTemp()
if temp == -999999 then
return
end
-- print("Setting socket...")
-- cu=net.createConnection(net.UDP)
-- cu:connect(9999,"192.168.1.33")
mac = wifi.sta.getmac()
cu:send(9999,'192.168.1.33',tostring(mac) .. ':' .. tostring(temp))
end -- xmitTemp
function initUDP()
print("Setting UDP port and ip to send to....")
--setup UDP port
cu=net.createUDPSocket()
end -- initUDP
function initWIFI()
print("Setting up wifi....")
--setup wifi
print(wifi.sta.getip())
wifi.setmode(wifi.STATION)
wifi.sta.config {ssid="SSID", pwd="PASSWORD"}
end -- initWIFI
initWIFI()
initUDP()
mytimer = tmr.create()
mytimer:register(10000, tmr.ALARM_AUTO, xmitTemp)
mytimer:start()
You will need to load each of these scripts onto your NodeMCU v1.0 (ESP-12E) using ESPlorer. Please consult the ESPlorer documentation on how to do this. This operation is fairly straightforward though.
As soon as you load these files, the NodeMCU v1.0 (ESP-12E) should begin transmitting data to the Raspberry Pi, therefore you should start the temp_monitor.lua script before loading these files.
If you make a mistake, and need to remove the files from the NodeMCU v1.0 (ESP-12E), you can format the flash filesystem from ESPlorer, or you could also use Lualoader to remove the individual files. Again, consult the documentation.
Start temp_monitor.lua on the Raspberry Pi 3 and observe incoming data from NodeMCU v1.0 (ESP-12E)
As soon as you start this script you should see data coming in. Additionally a file in the /tmp directory will be created and named using the MAC address of the NodeMCU v1.0 (ESP-12E).
pi@raspberry:~/lua $ ./temp_monitor.lua
Beginning server loop
temp: 79.625F
temp: 79.625F
temp: 79.625F
temp: 79.625F
cd /tmp
ls *:*
8c:ce:4e:e:e5:be
Modify snmpd configuration and restart snmpd
In order to read the data with the Guardian sensor you must configure and start snmpd on the Raspberry Pi 3B. We need to make a few modifications and test them.
The bulleted items denote what to add or comment out in snmpd.conf. Do not include the bullets in your configuration file
cd /etc/snmp
sudo vi /etc/snmmp/snmpd.conf
agentAddress udp:192.168.1.33:161 #Bind to Raspberry Pi address
rocommunity public
#view systemonly included .1.3.6.1.2.1.1
#view systemonly included .1.3.6.1.2.1.25.1
#rocommunity public localhost
rocommunity public 192.168.1.29 #Nozomi Guardian address
extend-sh tempSensor01 cat /tmp/8c:ce:4e:e2:e5:be; exit 35 #The MAC address of your NodeMCU v1.0 (ESP-12E)
service snmpd restart
Test the extension with snmpwalk and acquire OID with snmptranslate.
snmpget -v 2c -c public 192.168.1.33 'NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."tempSensor01"'
NET-SNMP-EXTEND-MIB::nsExtendOutput1Line."tempSensor01" = STRING: 75.6725
snmptranslate -On 'NET-SNMP-EXTEND-MIB:nsExtendOutput1Line."tempSensor01"'
.1.3.6.1.4.1.8072.1.3.2.3.1.1.12.116.101.109.112.83.101.110.115.111.114.48.49
Configure Guardian Smart Polling strategy.
Check Polled Nodes for incoming data