My first $5 IoT implementation (with ESP8266)


#1

Hi,

I’d like to make a cheap demo for IoT, using Exosite services. This message is the kick-off, currenty I have only plans.

Hardware:

Currently, the selected HW cost is upper $5, but using more simple ESP8266 will decrease the cost under $5.

Software:

  • NodeMCU.

Using LUA looks like the most simple solution. Maybe a custom C code will be more optimal in the future.

Communication protocol:

  • Simple UDP API of Exosite.

It looks like it is the most simple alternative. SNMP is also a simple and well-known protocol, but I cannot find it in the API docs.


#2

Hey there @pgillich! That sounds like a fun project. I’ve actually got a few of those NodeMCU boards sitting on my desk waiting to play with them, so I’d be interested to see what you come up with.

I definitely agree that Lua is going to be a really good place to start to help you get up and running quickly.

You definitely can use the UDP API to write your data to the platform, and it might be the quickest way to go, but looking at the docs it looks like they support doing some really basic HTTP requests and they even have a seemingly full featured CoAP client library. So if you get your UDP-based app up and running and want a bit more reliability I’d suggest switching over to CoAP. (Although I can’t actually find real docs for the CoAP library to see if it is full featured, this is just based on looking at the the example.)

And, you’re right, we don’t support SNMP, it’s not really a protocol that you would probably want to use in an application like this. Plus as far as I know most ISPs filter that kind of traffic out since there isn’t much reason for legitimate SNMP traffic to be going over the internet.

Definitely keep us up to date on your progress! I’m looking forward to hearing more! :smile:


#3

Hi Patrick!
Thanks for the positive answer, later than I expected, I made the the first version :slight_smile:


#4

Well, the first trial is a little bit different than I planned. But more simple (built-in USB-serial, USB power).

Used HW:

  • NodeMCU (new), $6.14
  • DHT22, $3.3
    It’s not the cheapest, but simple as possible, see a picture:

The SW is also simple as possible: LUA. The components are:

The LUA source code:

-- WiFi config
WIFI_SSID = "<SSID>"
WIFI_PASSWORD = "<wep-password>"

-- Sensor config
DHT_PIN = 4
DHT_GP = 60

-- Exosite config
EXOSITE_UDP_IP = "52.8.0.240"
EXOSITE_UDP_PORT = 18494
EXOSITE_CIK = "<DEVICE_CIK>"

print("Init WiFi")
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID,WIFI_PASSWORD)
wifi.sta.connect()
print("Connecting WiFi...")

exositeUdpConn = net.createConnection(net.UDP, 0)

function sendToExosite()
    print("Read sensor...")
    status,temp,humi,temp_decimial,humi_decimial = dht.readxx(DHT_PIN)
    if( status == dht.OK ) then
        udpBody = "&t=" .. temp .. "." .. temp_decimial .. "&rH=" .. humi .. "." .. humi_decimial
        print(udpBody)
        print("Sending...")
        exositeUdpConn:send("cik=" .. EXOSITE_CIK .. udpBody)
    else
        print(status)
    end
end

tmr.alarm(0, 1000, 1, function()
    t = tmr.now() 
    ip = wifi.sta.getip()
    print("@" .. t .. " " .. (ip or "nil") )
    if( ip ) then
        tmr.stop(0)

        exositeUdpConn:connect(EXOSITE_UDP_PORT, EXOSITE_UDP_IP)
        
        tmr.alarm(1, DHT_GP*1000, 1, sendToExosite )
    end
end )

The current cost is ~$10, but it can be $5, using ESP-01 ($2.65) + DHT11 ($1.35) + 3.3V power supply ($1).


#5

Finally, here is a smaller variant (ESP-01 + DHT22 + 3.3V power supply):

Here is a chart about one day:


#6

I’ve moved the sensor to another ESP8266 board (AI-Thinker):

It has a light sensor, so I’ve included it’s data. Another custom firmware must be flashed (dev, +DHT, +ADC, integer arithmetic). Here is a chart example, without converting the raw value to candela:

Extended LUA source code by handling the light sensor:

-- WiFi config
WIFI_SSID = "<SSID>"
WIFI_PASSWORD = "<wep-password>"

-- Sensor config
DHT_PIN = 4
DHT_GP = 60
gpio.mode(4, gpio.INPUT)

-- Exosite config
EXOSITE_UDP_IP = "52.8.0.240"
EXOSITE_UDP_PORT = 18494
EXOSITE_CIK = "<DEVICE_CIK>"

print("Init WiFi")
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID,WIFI_PASSWORD)
wifi.sta.connect()
print("Connecting WiFi...")

exositeUdpConn = net.createConnection(net.UDP, 0)
exositeUdpConn:on("sent", function(sck) print("...Sent") end )

gpio.mode(6, gpio.OUTPUT)
gpio.write(6, gpio.LOW)
gpio.mode(7, gpio.OUTPUT)
gpio.write(7, gpio.LOW)
gpio.mode(8, gpio.OUTPUT)
gpio.write(8, gpio.LOW)

function sendToExosite()
	wifi.sleeptype(wifi.NONE_SLEEP)
	
	print("Read sensors...")
	udpBody = ""
	
	status,temp,humi,temp_decimial,humi_decimial = dht.readxx(DHT_PIN)
	if( status == dht.OK ) then
		udpBody = udpBody .. "t=" .. temp .. "." .. temp_decimial .. "&rH=" .. humi .. "." .. humi_decimial .. "&"
	else
		print("NO DHT: " .. status)
	end

	light = adc.read(0)
	if( light == nil ) then
		print("NO LIGTH")
	else
		udpBody = udpBody .. "light=" .. light .. "&"
	end

	udpBody = udpBody .. "heap=" .. node.heap() .. "&uptime=" .. (tmr.now()/1000000)  .. "&"

	if( string.len(udpBody) > 0 ) then
		print(udpBody)
		print("Sending...")
		exositeUdpConn:send(udpBody .. "cik=" .. EXOSITE_CIK)
	else
		print("NO SENSOR DATA!")
	end

	wifi.sleeptype(wifi.MODEM_SLEEP)
end

tmr.alarm(0, 1000, 1, function()
	t = tmr.now() 
	ip = wifi.sta.getip()
	print("@" .. t .. " " .. (ip or "nil") )
	if( ip ) then
		tmr.stop(0)

		exositeUdpConn:connect(EXOSITE_UDP_PORT, EXOSITE_UDP_IP)
		
		tmr.alarm(1, DHT_GP*1000, 1, sendToExosite )
	end
end )

#7

During flashing the non-NodeMCU ESPs (ESP-01, AI-Thinker), I faced to an annoying problem: flashing was failed at ~8-11%. I spent hours to find the solution: the package size sending over the serial port must be shorter. There is only one solution: the source code of the flasher must be patched manually. The step-by-step solution is described here: http://www.esp8266.com/viewtopic.php?p=16082#p16082 .
It works on my computer (Windows 7, 64-bit).


#8

I’ve applied a pressure sensor to AI-Thinker, see:


The power supply is an unused 5V mobile phone charger (Samsung).
BMP058 uses I2C, so a new firmware had to be built with I2C support. Source code must be supplemented by the I2C sensor handling and pressure conversion equations. NodeMCU firmware has BMP library, but it didn’t work, instead, I’m using it’s source code.
An I2C scanner was useful to detect the I2C configuration, which is already added to NodeMCU.
The source code with comments was too long for LUA compiler, so I removed them.:

WIFI_SSID = "<SSID>"
WIFI_PASSWORD = "<WEP_PASSWORD>"
DHT_PIN = 4
DHT_GP = 60
gpio.mode(4, gpio.INPUT)
EXOSITE_UDP_IP = "52.8.0.240"
EXOSITE_UDP_PORT = 18494
EXOSITE_CIK = "<CIK>"
bmp085_sda = 2
bmp085_scl = 1
bmp085_id=0
oss = 1
CO = {}

function init_leds()
	gpio.mode(0, gpio.OUTPUT)
	gpio.write(0, gpio.HIGH)

	gpio.mode(3, gpio.OUTPUT)
	gpio.write(3, gpio.HIGH)

	gpio.mode(5, gpio.OUTPUT)
	gpio.write(5, gpio.HIGH)

	gpio.mode(6, gpio.OUTPUT)
	gpio.write(6, gpio.LOW)

	gpio.mode(7, gpio.OUTPUT)
	gpio.write(7, gpio.LOW)
	
	gpio.mode(8, gpio.OUTPUT)
	gpio.write(8, gpio.LOW)
end

function bmp085_read_reg(dev_addr, reg_addr)
  i2c.start(bmp085_id)
  i2c.address(bmp085_id, dev_addr ,i2c.TRANSMITTER)
  i2c.write(bmp085_id,reg_addr)
  i2c.stop(bmp085_id)
  i2c.start(bmp085_id)
  i2c.address(bmp085_id, dev_addr,i2c.RECEIVER)
  local c=i2c.read(bmp085_id,1)
  i2c.stop(bmp085_id)
  return c
end   

function bmp085_write_reg(dev_addr, reg_addr, reg_val)
  i2c.start(bmp085_id)
  i2c.address(bmp085_id, dev_addr, i2c.TRANSMITTER)
  i2c.write(bmp085_id, reg_addr)
  i2c.write(bmp085_id, reg_val)
  i2c.stop(bmp085_id)
end

function bmp085_getShort(reg_addr, signed)
  local tH = string.byte(bmp085_read_reg(0x77, reg_addr))
  local tL = string.byte(bmp085_read_reg(0x77, (reg_addr + 1)))
  local temp = tH*256 + tL
  if (temp > 32767) and (signed == true) then 
	temp = temp - 65536
  end
  return temp
end    

function bmp085_init(d, l)      
  if (d ~= nil) and (l ~= nil) and (d >= 0) and (d <= 11) and (l >= 0) and ( l <= 11) and (d ~= l) then
	sda = d
	scl = l 
  else 
	print("iic config failed!") return nil
  end
	print("init done")
	i2c.setup(bmp085_id, sda, scl, i2c.SLOW) 
	CO.AC1 = bmp085_getShort(0xAA, true)
	CO.AC2 = bmp085_getShort(0xAC, true)
	CO.AC3 = bmp085_getShort(0xAE, true)
	CO.AC4 = bmp085_getShort(0xB0)         
	CO.AC5 = bmp085_getShort(0xB2)
	CO.AC6 = bmp085_getShort(0xB4)
	CO.B1  = bmp085_getShort(0xB6, true)
	CO.B2  = bmp085_getShort(0xB8, true)
	CO.MB  = bmp085_getShort(0xBA, true)
	CO.MC  = bmp085_getShort(0xBC, true)
	CO.MD  = bmp085_getShort(0xBE, true)      
end

function bmp085_getUT(num_10x)
  bmp085_write_reg(0x77, 0xF4, 0x2E);
  tmr.delay(10000);
  local temp = bmp085_getShort(0xF6)
  local X1 = (temp - CO.AC6) * CO.AC5 / 32768
  local X2 = CO.MC * 2048/(X1 + CO.MD)
  local r = (X2 + X1 + 8)/16 
  if(num_10x == true) then 
	return r
  else 
	return ((r/10).."."..(r%10))
  end
end

function bmp085_getUP_raw(oss)
  local os = 0
  if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
	os = oss
  end
  local ov = os * 64
  bmp085_write_reg(0x77, 0xF4, (0x34 + ov));
  tmr.delay(30000); 
  local MSB = string.byte(bmp085_read_reg(0x77, 0xF6))
  local LSB = string.byte(bmp085_read_reg(0x77, 0xF7))
  local XLSB = string.byte(bmp085_read_reg(0x77, 0xF8))
  local up_raw = (MSB*65536 + LSB *256 + XLSB)/2^(8 - os)
  return up_raw
end

function bmp085_getUP(oss)
  local os = 0
  if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
	os = oss
  end
  local raw = bmp085_getUP_raw(os)
  local B5 = bmp085_getUT(true) * 16 - 8;
  local B6 = B5 - 4000
  local X1 = CO.B2 * (B6 * B6 /4096)/2048
  local X2 = CO.AC2 * B6 / 2048
  local X3 = X1 + X2
  local B3 = ((CO.AC1*4 + X3)*2^os + 2)/4
  X1 = CO.AC3 * B6 /8192
  X2 = (CO.B1 * (B6 * B6 / 4096))/65536
  X3 = (X1 + X2 + 2)/4
  local B4 = CO.AC4 * (X3 + 32768) / 32768
  local B7 = (raw -B3) * (50000/2^os)
  local p = B7/B4 * 2
  X1 = (p/256)^2
  X1 = (X1 *3038)/65536
  X2 = (-7357 *p)/65536
  p = p +(X1 + X2 + 3791)/16
  return p
end

function bmp085_getAL_cm(oss)
  return (bmp085_getUP(oss) - 101325)*843/100
end

init_leds()
print("Init BMP")
bmp085_init(bmp085_sda, bmp085_scl)

print("Init WiFi")
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID,WIFI_PASSWORD)
wifi.sta.connect()
print("Connecting WiFi...")

exositeUdpConn = net.createConnection(net.UDP, 0)

function sendToExosite()
--    wifi.sleeptype(wifi.NONE_SLEEP)
	
	print("Read sensors...")
	udpBody = ""
	
	status,temp,humi,temp_decimial,humi_decimial = dht.readxx(DHT_PIN)
	if( status == dht.OK ) then
		udpBody = udpBody .. "t=" .. temp .. "." .. temp_decimial .. "&rH=" .. humi .. "." .. humi_decimial .. "&"
	else
		print("NO DHT: " .. status)
	end

	p = bmp085_getUP(oss)
	t2 = bmp085_getUT(oss)
	alt = bmp085_getAL_cm(oss)

	udpBody = udpBody .. "p=" .. p .. "&t2=" .. t2 .. "&alt=" .. alt .. "&" 

	light = adc.read(0)
	if( light == nil ) then
		print("NO LIGTH")
	else
		udpBody = udpBody .. "light=" .. light .. "&"
	end

	tmr_now = tmr.now()
	udpBody = udpBody .. "heap=" .. node.heap() .. "&uptime=" .. (tmr_now/1000000)  .. "&"

	if( string.len(udpBody) > 0 ) then
		print(udpBody)
		print("Sending...")
		exositeUdpConn:send(udpBody .. "cik=" .. EXOSITE_CIK)
	end

--    wifi.sleeptype(wifi.MODEM_SLEEP)
end

function wait_wifi()
	ip = wifi.sta.getip()
	print( (ip or "nil") )
	if( ip ) then
		tmr.stop(0)

		exositeUdpConn:connect(EXOSITE_UDP_PORT, EXOSITE_UDP_IP)
		
		tmr.alarm(1, DHT_GP*1000, 1, sendToExosite )
	end
end

tmr.alarm(0, 1000, 1, wait_wifi ) 

#9

Time has come to summary this small project. Several use cases were investigated, let’s see, can the cheapest be under $5:

  • ESP-01: $2.60
  • DHT-11: $1.00
  • LD1117V33 + capacitors: $1.00
  • cables, small breadboard: $0.40
  • 5V power supply: $0.00 (old mobile phone charger)

The LD1117V33 circle has not been presented yet, so I made an example:

The final conclusion: yes, it’s possible to make an IoT device for $5.

A summary can be seen on Prezi.


Some comment about ESP-01:

ESP-01 has only 2 GPIOs, but GPIO00 is reserved for flashing. Even though NodeMCU has limited support for using GPIO00, there are some examples, which uses it, see some I2C examples:

But a NodeMCU or any other ESP-12-based harware has better chances for extending.


#10

This is great! Thanks so much for sharing @pgillich!

I’m going to have to find some time to put together one of these myself!


#11

Hi Patrick,

Good luck! Only the first step is hard: ordering on the ebay.

Peter


#12

The development board was tested behind a firewall, which disabled the UDP communication. I had to change the code to use HTTP POST. The code survives the WiFi lost. An AI-Thinker board was used, so the green and red led indicated the HTTP POST result.

WIFI_SSID="<SSID>"
WIFI_PASSWORD="<WEP_PASSWORD>"
DHT_PIN=4
DHT_GP=10
gpio.mode(4,gpio.INPUT)
EXOSITE_IP="52.8.0.240"
EXOSITE_PORT=80
EXOSITE_CIK="<CIK>"
bmp085_sda=2
bmp085_scl=1
bmp085_id=0
oss=1
CO={}

function init_leds()
 gpio.mode(0,gpio.OUTPUT)
 gpio.write(0,gpio.HIGH)
 gpio.mode(3,gpio.OUTPUT)
 gpio.write(3,gpio.HIGH)
 gpio.mode(5,gpio.OUTPUT)
 gpio.write(5,gpio.HIGH)
 gpio.mode(6,gpio.OUTPUT)
 gpio.write(6,gpio.LOW)
 gpio.mode(7,gpio.OUTPUT)
 gpio.write(7,gpio.LOW)
 gpio.mode(8,gpio.OUTPUT)
 gpio.write(8,gpio.LOW)
end

function bmp085_read_reg(dev_addr,reg_addr)
 i2c.start(bmp085_id)
 i2c.address(bmp085_id,dev_addr ,i2c.TRANSMITTER)
 i2c.write(bmp085_id,reg_addr)
 i2c.stop(bmp085_id)
 i2c.start(bmp085_id)
 i2c.address(bmp085_id,dev_addr,i2c.RECEIVER)
 local c=i2c.read(bmp085_id,1)
 i2c.stop(bmp085_id)
 return c
end   

function bmp085_write_reg(dev_addr,reg_addr,reg_val)
 i2c.start(bmp085_id)
 i2c.address(bmp085_id,dev_addr,i2c.TRANSMITTER)
 i2c.write(bmp085_id,reg_addr)
 i2c.write(bmp085_id,reg_val)
 i2c.stop(bmp085_id)
end

function bmp085_getShort(reg_addr,signed)
 local tH=string.byte(bmp085_read_reg(0x77,reg_addr))
 local tL=string.byte(bmp085_read_reg(0x77,(reg_addr + 1)))
 local temp=tH*256 + tL
 if (temp > 32767) and (signed == true) then 
  temp=temp - 65536
 end
 return temp
end 

function bmp085_init(d,l)      
 if (d ~= nil) and (l ~= nil) and (d >= 0) and (d <= 11) and (l >= 0) and (l <= 11) and (d ~= l) then
  sda=d
  scl=l 
 else 
  print("i2c config failed!") return nil
 end
  print("i2c init done")
  i2c.setup(bmp085_id,sda,scl,i2c.SLOW) 
  CO.AC1=bmp085_getShort(0xAA,true)
  CO.AC2=bmp085_getShort(0xAC,true)
  CO.AC3=bmp085_getShort(0xAE,true)
  CO.AC4=bmp085_getShort(0xB0)         
  CO.AC5=bmp085_getShort(0xB2)
  CO.AC6=bmp085_getShort(0xB4)
  CO.B1 =bmp085_getShort(0xB6,true)
  CO.B2 =bmp085_getShort(0xB8,true)
  CO.MB =bmp085_getShort(0xBA,true)
  CO.MC =bmp085_getShort(0xBC,true)
  CO.MD =bmp085_getShort(0xBE,true)      
end

function bmp085_getUT(num_10x)
 bmp085_write_reg(0x77,0xF4,0x2E);
 tmr.delay(10000);
 local temp=bmp085_getShort(0xF6)
 local X1=(temp - CO.AC6) * CO.AC5 / 32768
 local X2=CO.MC * 2048/(X1 + CO.MD)
 local r=(X2 + X1 + 8)/16 
 if(num_10x == true) then 
  return r
 else 
  return ((r/10).."."..(r%10))
 end
end

function bmp085_getUP_raw(oss)
 local os=0
 if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
  os=oss
 end
 local ov=os * 64
 bmp085_write_reg(0x77,0xF4,(0x34 + ov));
 tmr.delay(30000); 
 local MSB=string.byte(bmp085_read_reg(0x77,0xF6))
 local LSB=string.byte(bmp085_read_reg(0x77,0xF7))
 local XLSB=string.byte(bmp085_read_reg(0x77,0xF8))
 local up_raw=(MSB*65536 + LSB *256 + XLSB)/2^(8 - os)
 return up_raw
end

function bmp085_getUP(oss)
 local os=0
 if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
  os=oss
 end
 local raw=bmp085_getUP_raw(os)
 local B5=bmp085_getUT(true) * 16 - 8;
 local B6=B5 - 4000
 local X1=CO.B2 * (B6 * B6 /4096)/2048
 local X2=CO.AC2 * B6 / 2048
 local X3=X1 + X2
 local B3=((CO.AC1*4 + X3)*2^os + 2)/4
 X1=CO.AC3 * B6 /8192
 X2=(CO.B1 * (B6 * B6 / 4096))/65536
 X3=(X1 + X2 + 2)/4
 local B4=CO.AC4 * (X3 + 32768) / 32768
 local B7=(raw -B3) * (50000/2^os)
 local p=B7/B4 * 2
 X1=(p/256)^2
 X1=(X1 *3038)/65536
 X2=(-7357 *p)/65536
 p=p +(X1 + X2 + 3791)/16
 return p
end

function bmp085_getAL_cm(oss)
 return (bmp085_getUP(oss) - 101325)*843/100+10000
end

init_leds()
print("Init BMP")
bmp085_init(bmp085_sda,bmp085_scl)

print("Init WiFi: "..WIFI_SSID)
wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID,WIFI_PASSWORD)
wifi.sta.connect()
print("Connecting WiFi...")

payload=""
exositeConn=nil
function printReceivedPayload(conn,payload) 
 print(" RECV: "..string.sub(payload,1,13))
 gpio.write(6,gpio.HIGH)
 conn:close()
end
function printSent(conn) print(" SENT") end
function printConnection(conn) 
 print(" CONN")
 conn:send(payload)
end
function printReconnection(conn) print(" RECON") end
function printDisconnection(conn)
 print(" DISCON")
 conn:close()
 exositeConn=nil
end

function sendToExosite()
 print("Read sensors...")
 local body=""
 status,temp,humi,temp_decimial,humi_decimial=dht.readxx(DHT_PIN)
 if(status == dht.OK) then
  body=body.."t="..temp.."."..temp_decimial.."&rH="..humi.."."..humi_decimial.."&"
 else
  print("NO DHT: "..status)
 end
 local p=bmp085_getUP(oss)
 local t2=bmp085_getUT(oss)
 local alt=bmp085_getAL_cm(oss)
 body=body.."p="..p.."&t2="..t2.."&alt="..alt.."&" 
 local light=adc.read(0)
 if(light == nil) then
  print("NO LIGTH")
 else
  body=body.."light="..light.."&"
 end
 local tmr_now=tmr.now()
 body=body.."heap="..node.heap().."&uptime="..(tmr_now/1000000).."&"
 local bodyLen=string.len(body)
 print(body)
 payload="POST /onep:v1/stack/alias HTTP/1.1\r\n"
  .."Host: "..EXOSITE_IP.."\r\n"
  .."X-Exosite-CIK: "..EXOSITE_CIK.."\r\n"
  .."Content-Length: "..bodyLen.."\r\n"
  .."Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n\r\n"
  ..body
 local ip=wifi.sta.getip()
 gpio.write(6,gpio.LOW)
 if(ip == nil) then
  gpio.write(8,gpio.HIGH)
  print("NO IP")
 else
  gpio.write(8,gpio.LOW)
  print(" FROM: "..ip)
  exositeConn=net.createConnection(net.TCP,0)
  exositeConn:on("receive",printReceivedPayload)
  exositeConn:on("sent",printSent)
  exositeConn:on("connection",printConnection)
  exositeConn:on("reconnection",printReconnection)
  exositeConn:on("disconnection",printDisconnection)
  exositeConn:connect(EXOSITE_PORT,EXOSITE_IP)
 end
end

function wait_wifi()
 local ip=wifi.sta.getip()
 print((ip or "nil"))
 if(ip) then
  tmr.stop(0)
  tmr.alarm(1,DHT_GP*1000,1,sendToExosite)
 end
end

tmr.alarm(0,1000,1,wait_wifi)

#13

Hi Peter,
Did you ever try a setup were you use the ESP 01 as an Exosite communication system only and then using an Arduino (UNO, MEGA or MINI) for all the I/O signal processing etc. stuff. I love the ESP 01 but run fast into the I/O limitations but think the ESP 01 would make a great generic interface with Exosite. ???