Showing posts with label IoT. Show all posts
Showing posts with label IoT. Show all posts

Thursday, 8 February 2018

The all-you-can-possibly-want ESP8266 dev board


All-in-one ESP8266 module

I did a very simple 5-minute example project with this board. The video will be available shortly.
The video is available here now!

Overview

The somewhat unwieldly name "Wemos® D1 Esp-Wroom-02 Motherboard ESP8266 Mini-WiFi NodeMCU Module ESP 8266+18650 Battery+0.96 OLED" betrays a very complete ESP8266 development module, that boasts a load of features:
  • USB2Serial bridge (Silicon Labs CP210x USB to UART Bridge)
    If your PC does not automatically detect the driver, you find it here.
  • Power switch
  • LiIon charge circuit
  • 18650 battery holder
    Beware: the holder is too short for my favourite protected 18650 cells. These INR cells should fit instead.
  • "Wemos" labelled ESP-12F ESP8266 module. It does not look like a WROOM-02, though.
  • SSD1306 OLED display
  • 4-way + push "joystick"

Bells and whistles
The Wemos product page does not list a module like that, so it might not be their product at all.
The advertised product name:
Wemos D1 Esp-Wroom-02 Motherboard ESP8266 Mini-WiFi NodeMCU Module ESP 8266+18650 Battery+0.96 OLED does not really fit in quite a few respects.
Leave a note in the comments, if you know more about that.

OLED details

The OLD display is white-ish in colour. It works with the usual SSD1306 library. The protocol is I2C.

No surprises here.

The PIN assignment is:
  • SDA=GPIO 5
  • SCL=GPIO 4 
The I2C Address ist 0x3c, as it is common for these modules.

4-way switch

To interact with the module, this is super handy.
The Pin assignment is:
  • UP = GPIO 12  (=D6)
  • DOWN = GPIO 13 (=D7)
  • LEFT = GPIO 0 (=D3, FLASH)
  • RIGHT = RESET (!)
  • SELECT = GPIO 14 (=D5)
The RIGHT pin is a bit of a questionable choice. Then again the module does not have a dedicated reset button.

Caveats

I could not get the module to power up without a battery inserted.
People have reported that some components heat up when charging the batteries. I haven't noticed that yet.

IDE selection

I use the Arduino IDE on Windows whenever possible and the bare bones Espressif build environment on Linux whenever necessary.
  • Set-up of the Arduino IDE for ESP8266 ist >>here<<
  • For the Linux build environment, see >>here<<
In the Arduino IDE, I used "WeMos D1" as board type. and 4M (3M SPIFFS) for this module and did not have any issues with it.

UPDATE 2022:

The module does not seem to be available any more. This might be a suitable replacement. Although I don't have one at this time.


Sunday, 2 April 2017

Web-enable the Tivoli model One with style

Turn your Tivoli Audio Model One into a web radio with Onion.io's Omega2


EDIT: you can now have a look at the build here on youtube.

Model One downsides

My Model One suffers from a few shortcomings:
  • interference from the switching power supplies of the kitchen lights
  • FM reception limited to local stations
  • AM unuseable because of interference
  • no short- or longwave reception
This particular Model One is the old version without the individual AUX setting. So with a plug in the AUX input, AM/FM reception is impossible.

So what I need is an underpiece to match the style of the Model One that provides reception of all my favourite stations, both domestic and foreign.


Underpiece design idea

Onion.io Omega2

When I was contacted by Randolf from Onion.IO, if I wanted to have a go at the Onion2, this looked like the ideal system to upgrade my Model One:

  • below 1 W power consumption (including USB audio dongle)
  • GPIOs easily accessible with the expansion dock (also has a serial-usb bridge and power regulator)
  • supported usb audio dongle available
  • all packages required for my project already available

Easy as Pi

I work with linux systems for a living and have quite a few RaspberryPis scattered around the house. I have also done projects with OpenWRT systems, so getting the Omega2 to work was an easy task. It is also extremely well documented.

Test setup


How it works

I designed the underpiece to have six pushbuttons. Each one connects one of the GPIO pins to the 3V3 rail.

The resistors are a bit of an afterthought. Still simple enough.



The command:
gpioctl dirin 1
sets GPIO #1 as an input. It's state can be queried with:

root@Omega-8D3B:/etc# gpioctl get 1
Using gpio pin 1.
Pin 1 is LOW
root@Omega-8D3B:/etc#

If scripted, this output needs a bit of tidying. I couldn't figure out where to get the value from the sysfs. If anyone knows, please let me know.

The only additional piece of software needed is mpg123 simply installed by:

opkg install mpg123

(You might need to run opkg update first)

On a microcontroller, reacting to the push of a button would normally be a job for an interrupt. The following script works without that. At the cost that the button has to be pressed for up to a second.

So when I momentarily connect any of the GPIOs (with the exception of GPIO6) to 3.3V, the script starts mpg123 with the appropriate stream URL.

The "radio.sh" script to be placed in /usr/bin

 #!/bin/ash

        gpioctl dirin 0
        gpioctl dirin 1
        gpioctl dirin 2
        gpioctl dirin 3
        gpioctl dirin 6
        gpioctl dirin 7
        gpioctl dirin 8
        gpioctl dirin 9


         COUNTER=0
         while [  $COUNTER -lt 100 ]; do
        #     echo The counter is $COUNTER
        #     let COUNTER=COUNTER+1


BUTTON0=$(gpioctl get 0 | grep Pin | cut -b 10)
BUTTON1=$(gpioctl get 1 | grep Pin | cut -b 10)
BUTTON2=$(gpioctl get 2 | grep Pin | cut -b 10)
BUTTON3=$(gpioctl get 3 | grep Pin | cut -b 10)
#BUTTON6=$(gpioctl get 6 | grep Pin | cut -b 10)
BUTTON7=$(gpioctl get 7 | grep Pin | cut -b 10)
BUTTON8=$(gpioctl get 8 | grep Pin | cut -b 10)
BUTTON9=$(gpioctl get 9 | grep Pin | cut -b 10)


if [ $BUTTON0 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo BBC 1
mpg123 http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p &
            fi


if [ $BUTTON1 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo BBC-World
mpg123 http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws &
            fi



if [ $BUTTON2 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo France inter
mpg123 http://direct.franceinter.fr/live/franceinter-midfi.mp3 &
            fi

#world: http://bbcwssc.ic.llnwd.net/stream/bbcwssc_mp1_ws-einws

if [ $BUTTON3 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo SWR3
mpg123 http://swr-mp3-m-swr3.akacast.akamaistream.net/7/720/137136/v1/gnl.akacast.akamaistream.net/swr-mp3-m-swr3 &
            fi


#if [ $BUTTON6 = 'H' ]; then
#killall mpg123
#               echo starting radio mode
#               echo D-Radio
#mpg123 http://stream.dradio.de/7/249/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dlf_m &
#            fi


if [ $BUTTON9 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo D-Radio Kultur
mpg123 http://stream.dradio.de/7/530/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dkultur_m &
            fi


if [ $BUTTON8 = 'H' ]; then
killall mpg123
               echo starting radio mode
                echo D-Radio Wissen
mpg123 http://stream.dradio.de/7/698/142684/v1/gnl.akacast.akamaistream.net/dradio_mp3_dwissen_s &
            fi


        sleep 1
         done


The script is called from the file /etc/rc.local, so it starts when the Omega2 reboots:

 # Put your custom commands here that should be executed once  
 # the system init finished. By default this file does nothing.  
 /usr/bin/radio.sh & > /dev/null  
 exit 0  





Wednesday, 6 July 2016

GMail notifier with ESP8266 / NodeMCU


A while back I investigated the use of NodeMCU with GMail. One result was this script to send mails over GMail. The other aspect I initially didn't fully investigate was the atom feed offered by GMail.
Looks like we have unread mail
If you haven't watched the video yet, here it is.

In the code below, I use that feed to retrieve the number of unread elements from the inbox.
Apart from the Lua code, you also need to place the two files with the mailbox icons on NodeMCU's file system:

Mailoff-file: here
Mailon-file: here

That is what it looks like in action:



I recommend "esplorer" to copy the files to the ESP8266 module.

 -- ESP8266 NodeMCU  
 -- GMail Notifier  
 -- 2016/07 Andy Reischle  
 -- www.AReResearch.net  
 -- Graphics handling and conversion  
 -- adapted from Daniel Eichhorns blog  
 -- http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html  
 --  
 -- To see this script in action, see:  
 -- https://youtu.be/IVxJosLZCXs  
 wifi.setmode(wifi.STATION)  
 wifi.sta.config("YOUR-SSID","YOUR-WIFIPASS")  
 wifi.sta.connect()  
 -- setup I2c and connect display  
 function init_i2c_display()  
    -- SDA and SCL can be assigned freely to available GPIOs  
    sda = 5 -- GPIO14  
    scl = 6 -- GPIO12  
    sla = 0x3c  
    i2c.setup(0, sda, scl, i2c.SLOW)  
    disp = u8g.ssd1306_128x64_i2c(sla)  
 end  
 function xbm_picture()  
    disp:setFont(u8g.font_6x10)  
    disp:drawStr( 0, 62, "Google Mail Notifier")  
    disp:drawXBM( 10, 5, 32, 32, xbm_data )  
    disp:drawStr (65,30, unread .. " unread")  
 end  
 function bitmap_mailon(delay)  
    file.open("mailon", "r")  
    xbm_data = file.read()  
    file.close()  
    disp:firstPage()  
    repeat  
       xbm_picture()  
    until disp:nextPage() == false  
    tmr.wdclr()  
 end  
 function bitmap_mailoff(delay)  
    file.open("mailoff", "r")  
    xbm_data = file.read()  
    file.close()  
    disp:firstPage()  
    repeat  
       xbm_picture()  
    until disp:nextPage() == false  
    tmr.wdclr()  
 end  
 init_i2c_display()  
 function checkmail()  
 user="YOURADDRESS@GOOGLEMAIL.COM"  
 pass="YOURGMAILPASSWD"  
 b64 = crypto.toBase64(user .. ":" .. pass)  
 -- print (b64)  
 local LED_PIN1 = 4   
 gpio.mode(LED_PIN1, gpio.OUTPUT)  
 conn=net.createConnection(net.TCP, 1)  
 conn:on("receive", function(sck, c)  
 -- print(c)  
 start1,stop1=string.find(c,"<fullcount>")  
 start2,stop2=string.find(c,"</fullcount>")  
 if start1 then  
   unread=string.sub(c,stop1+1,start2-1)  
   print ("Found " .. unread .. " unread Mails.")  
    if tonumber(unread) > 0 then  
         gpio.write(LED_PIN1, gpio.LOW)  
         conn:close() -- we got what we came for, so close  
         bitmap_mailon()  
     else   
         gpio.write(LED_PIN1, gpio.HIGH)   
         conn:close() -- no Mail, so close  
         bitmap_mailoff()  
    end  
  end  
 end )  
 conn:on("connection", function(conn)  
    print("connected")  
    conn:send("GET https://mail.google.com/mail/feed/atom/ HTTP/1.1\r\n" ..  
        "Host: mail.google.com\r\n"..   
        "Authorization: Basic " .. b64 .. "\r\n" ..  
       "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"..  
        "\r\n\r\n")   
 end )  
 conn:on("disconnection", function(conn) print("disconnected") end )  
 conn:connect(443,"mail.google.com")  
 end  
 tmr.alarm(0,30000,tmr.ALARM_AUTO,checkmail)  

Not much stuff is needed for that little project:


Assembly is done in no time at all. Just connect power and I2C leads. (For me, this works without pull-up resistors.)

Not a lot to do.






Friday, 15 April 2016

How to send emails via gmail from an ESP8266 running NodeMCU

How to send smtp emails via gmail from an ESP8266 running NodeMCU

SSL Support

When I found out about NodeMCU's SSL support (yes: I am very late to the party), one of the first things to try was sending mails. There are web services that will do that for you, but I don't like to have yet another party involved. So I needed SMTP through an SSL connection,
There is an implementation in C here in the forums, but I couldn not find anything ready-made for NodeMCU.
What I did find, was a very nicely written LUA script from "Miguel" in the NodeMCU LUA examples. This only needed a few minor modifications to run on the current DEV-version of NodeMCU:

NodeMCU custom build by frightanic.com
branch: dev
commit: 3f418f995cfccbaf7a745e65c81251c4c50759e6
SSL: true
modules: adc,crypto,file,gpio,http,i2c,net,node,tmr,u8g,uart,wifi
 build built on: 2016-04-11 20:31
 powered by Lua 5.1.4 on SDK 1.5.1(e67da894)

Not all of the modules are really used in this script, of course. So you can trim that down a bit.

Example mail on iPhone


Send an e-mail

With all of that in place, it only took a few minutes to have the first mail sent from my ESP8266-DEV board.
So here is the code for you to try:


 -- Modifications for GMAIL by Andreas "Andy" Reischle: www.AReResearch.net  
 -- See https://support.google.com/a/answer/176600?hl=de for details on smtp with gmail  
 -- Now that NodeMCU has working SSL support, we can also talk to email services that  
 -- require encryption.   
 -- Caveat: I have not looked into the SSL implementation, but I suspect it is vulnerable  
 -- to man-in-the-middle attacks as the client doesn't check the server's certificate.  
 -- 20160415 ARe  
 --------Original Credits:  
 --------  
 ------- Working Example: https://www.youtube.com/watch?v=CcRbFIJ8aeU  
 ------- @description a basic SMTP email example. You must use an account which can provide unencrypted authenticated access.  
 ------- This example was tested with an AOL and Time Warner email accounts. GMail does not offer unecrypted authenticated access.  
 ------- To obtain your email's SMTP server and port simply Google it e.g. [my email domain] SMTP settings  
 ------- For example for timewarner you'll get to this page http://www.timewarnercable.com/en/support/faqs/faqs-internet/e-mailacco/incoming-outgoing-server-addresses.html  
 ------- To Learn more about SMTP email visit:  
 ------- SMTP Commands Reference - http://www.samlogic.net/articles/smtp-commands-reference.htm  
 ------- See "SMTP transport example" in this page http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol  
 ------- @author Miguel  
 --no longer required because it is part of the crypto module: require("base64")  
 -- The email and password from the account you want to send emails from  
 local MY_EMAIL = "YOURMAILADDRESS@gmail.com"  
 local EMAIL_PASSWORD = "YOURPASSWORD"  
 -- The SMTP server and port of your email provider.  
 -- If you don't know it google [my email provider] SMTP settings  
 local SMTP_SERVER = "smtp.gmail.com"  
 local SMTP_PORT = "465"  
 -- The account you want to send email to  
 local mail_to = "RECIPIENT@HISDOMAIN.COM"  
 -- Your access point's SSID and password  
 local SSID = "YOURWIFISSID"  
 local SSID_PASSWORD = "SECRET-I-WONT-TELL"  
 -- configure ESP as a station  
 wifi.setmode(wifi.STATION)  
 wifi.sta.config(SSID,SSID_PASSWORD)  
 wifi.sta.autoconnect(1)  
 -- These are global variables. Don't change their values  
 -- they will be changed in the functions below  
 local email_subject = ""  
 local email_body = ""  
 local count = 0  
 local smtp_socket = nil -- will be used as socket to email server  
 -- The display() function will be used to print the SMTP server's response  
 function display(sck,response)  
    print("Got a response: ")  
    print(response)  
 end  
 -- The do_next() function is used to send the SMTP commands to the SMTP server in the required sequence.  
 -- I was going to use socket callbacks but the code would not run callbacks after the first 3.  
 function do_next()  
       if(count == 0)then  
         count = count+1  
         local IP_ADDRESS = wifi.sta.getip()  
         print ("Send my IP: " .. IP_ADDRESS)  
         smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")  
       elseif(count==1) then  
         count = count+1  
         smtp_socket:send("AUTH LOGIN\r\n")  
       elseif(count == 2) then  
         count = count + 1  
         smtp_socket:send(crypto.toBase64(MY_EMAIL).."\r\n")  
       elseif(count == 3) then  
         count = count + 1  
         smtp_socket:send(crypto.toBase64(EMAIL_PASSWORD).."\r\n")  
       elseif(count==4) then  
         count = count+1  
         smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")  
       elseif(count==5) then  
         count = count+1  
         smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")  
       elseif(count==6) then  
         count = count+1  
         smtp_socket:send("DATA\r\n")  
       elseif(count==7) then  
         count = count+1  
         local message = string.gsub(  
         "From: \"".. MY_EMAIL .."\"<"..MY_EMAIL..">\r\n" ..  
         "To: \"".. mail_to .. "\"<".. mail_to..">\r\n"..  
         "Subject: ".. email_subject .. "\r\n\r\n" ..  
         email_body,"\r\n.\r\n","")  
         smtp_socket:send(message.."\r\n.\r\n")  
       elseif(count==8) then  
         count = count+1  
          tmr.stop(0)  
          smtp_socket:send("QUIT\r\n")  
       else  
         smtp_socket:close()  
       end  
 end  
 -- The connectted() function is executed when the SMTP socket is connected to the SMTP server.  
 -- This function will create a timer to call the do_next function which will send the SMTP commands  
 -- in sequence, one by one, every 5000 seconds.   
 -- You can change the time to be smaller if that works for you, I used 5000ms just because.  
 function connected(sck)  
   print("Connected - Starting Timer")  
   tmr.alarm(0,5000,1,do_next)  
 end  
 -- @name send_email  
 -- @description Will initiated a socket connection to the SMTP server and trigger the connected() function  
 -- @param subject The email's subject  
 -- @param body The email's body  
 function send_email(subject,body)  
    count = 0  
    email_subject = subject  
    email_body = body  
    print ("Open Connection")  
    smtp_socket = net.createConnection(net.TCP,1)  
    smtp_socket:on("connection",connected)  
    smtp_socket:on("receive",display)  
    smtp_socket:connect(SMTP_PORT,SMTP_SERVER)  
 end  
 -- Send an email  
 print ("Sending started...")  
 send_email("ESP8266-GMailSender","Hi there!")  

This will need a little tidying, but will certainly make it into one of my projects.

Caveat:

NodeMCU's SSL implementation does currently not check the server's certificate. So I suspect man-in-the-middle attacks are easy.

Saturday, 26 March 2016

UDP-Ranger - a simple ESP8266 range tester

The problem

I tried to find reliable information on the range of the ESP-12 series modules, but was not quite happy with what I found. Neither the use of highly directional antennas (or is it "antennae"?) nor the selection of client devices seemed right to draw conclusions about the actual range.

EDIT: see the 1st part of my video about the tester here.
EDIT: and here is the 2nd part if the video with the results

The idea

ESP-8266 modules at both ends of the connection seemed like a good idea to me. Normally you would use a simple ping-test to see if packets are lost on the way between the modules.

ICMP

Despite the fact that the LWIP stack in NodeMCU does handle ICMP properly, I have yet to see a "Ping" program to send/revceive ICMP echo-requests/replies.

TCP

TCP connections between two NodeMCU endpoints are super easy. But the TCP  protocol will do it's best to compensate the loss of packets, so we wouldn't detect missing packets until the connection breaks up completely.

UDP

UDP does not provide such a recovery mechanism for lost packets, so the application has to handle that. We can use that easily to find out when packets go missing.

The solution

Ok, so UDP it is. We'll simply connect an ESP-12e module in station-mode to an ESP-12f module in soft-ap mode and send UDP packets from the ESP-12e to the ESP-12f module.
The payload of each packet is a numer that is incremented by one for each packet. So if a packet is missing, it is easy to detect.
The ESP-modules

What you need


The server.lua script

 local LED_PIN1 = 4  
 gpio.mode(LED_PIN1, gpio.OUTPUT)  
 local sw1 = true  
 wifi.setmode(wifi.SOFTAP)  
 cfg={}  
    cfg.ssid="AReResearch"  
    wifi.ap.config(cfg)  
 function init_OLED(sda,scl)  
    sla = 0x3c  
    i2c.setup(0, sda, scl, i2c.SLOW)  
    disp = u8g.ssd1306_128x64_i2c(sla)  
    disp:setFont(u8g.font_6x10)  
    disp:setFontRefHeightExtendedText()  
    disp:setDefaultForegroundColor()  
    disp:setFontPosTop()  
 end  
 init_OLED(5,6)  
 err=0  
 cold=1  
 disp:firstPage()  
   repeat  
    disp:drawStr(0, 10, "AReResearch UDP-Ranger")  
    disp:drawStr(5, 35, "Waiting for client...")  
   until disp:nextPage() == false  
 s=net.createServer(net.UDP)   
 s:on("receive",function(s,c)  
   print("Sequence="..c.." Previous:"..cold)  
 if ((cold+1)~=tonumber(c)) then  
   err=err+1  
   end  
 disp:firstPage()  
   repeat  
    disp:drawStr(0, 10, "AReResearch UDP-Ranger")  
    disp:drawStr(5, 35, "Packet Nr:" .. c)  
    disp:drawStr(5, 45, "Errors:" .. err)  
     until disp:nextPage() == false  
     if (sw1) then  
       gpio.write(LED_PIN1, gpio.LOW)  
     else  
       gpio.write(LED_PIN1, gpio.HIGH)  
     end  
   sw1 = not sw1  
 cold=c  
 end)   
 s:listen(8888)  

The client-lua script
 wifi.setmode(wifi.STATION)  
 wifi.sta.config("AReResearch","")  
 wifi.sta.connect()  
 LED_PIN1 = 4  
 gpio.mode(LED_PIN1, gpio.OUTPUT)  
 print (wifi.sta.getip())  
 x=1  
 tmr.alarm(2, 1000, 1, function()  
   conn = net.createConnection(net.UDP, 0)  
   conn:connect(8888,"192.168.4.1")  
   conn:send(x)  
   conn:close()  
   conn = nil  
   x=x+1  
   print (x)  
   if x>1000 then x=1 end  
   p=tonumber(wifi.sta.status())  
   print (p)  
   if p == 5  
     then  
     gpio.write(LED_PIN1, gpio.LOW)  
     print ("LED OFF")  
     else  
     gpio.write(LED_PIN1, gpio.HIGH)  
     print ("LED ON")  
     end  
 end)  

Ok, the programming is admittedly a bit sloppy. The counter will simply roll over at 1000 packets and will thus increment the "lost packets" counter by one. It is good enough for me at the moment.

Start the "server"module first

The "client" has sent packets

How to use this

Once the client module has connected to the "server", the server module's  LED will be toggled every time a packet is received. More info in how many packets have been missed is shown on the OLED.
So it is easy to tell when the connection starts breaking up.

The results

My first test run gave me a pretty stable connection up to 300 meters. Beyond 400m I couldn't get anything at all.

Thursday, 10 December 2015

Espressif ESP-8266: minimal configuration for running the ESP-12e module

I am working on a project where I haven't quite decided on some of the details, so I wanted a module that breaks out a lot of the ESP8266's pins, just to have as many options available as possible.

Here is also a 5 minute video about it.

The ESP-12e module seems like a good choice, with the added benefit of having 4MBytes of flash memory.
ESP-12e module from Banggod
So I ordered a pack of three from Bangood for just under 8 Euros. After quite a long wait they arrived and I had to take them to the workbench for a quick test drive, right away.

Odd stuff

A few things are a bit odd about these modules:
  • The silkscreen is a very poor print quality
  • The ADC pin is labelled ADG
  • The GPIO labels are a mess. Eg: There is no GPIO0 (this is labelled GPIO6 instead)

Where's GPOI0?
Todo: try flashing LEDs on all GPIOs to compare against NodeMCUs IO table


Basic configuration

So after a little experimentation, this turned out the most basic configuration:
Basic config for ESP-12e
I plan to run this without a circuit board, so I'll simply shorten GPOI15 to ground and connect the "Chip Power Down" Pin (CH_PD) to 3.3V. 

The Module came preinstalled with some AT-firmware, I didn't much care about.

Flashing new firmware

To program new firmware, GPOI0 (which for some reason is GPIO6 here) needs to be connected to ground. I am a huge fan of NodeMCU, so I flashed that to the module.
Ground GPIO6 (=GPIO0) to flash firmware via UART

This goes without saying

Connecting the serial-usb converter is unspectacular. Just the usual RXD-TXD / TXD-RXD thing. And don't forget to connect the ground wires.
Connecting the USB2Serial converter



Wednesday, 25 November 2015

Using node.dsleep() in NodeMCU to extend battery lifetime in ESP8266 projects

For some applications, like checking sensors, the ESP8266 does not need to run permanently with all it's bells and whistles on. The datasheet claims 10uA when in deep sleep mode.
NodeMCU, currently my preferred firmware, does support that sleep mode, but I've never tried using it. Mainly because it is a pain to modify the ESP-01 which used to be my perferred module.

Olimex MOD-WIFI-ESP8266-DEV

With the Olimex modules, I aquired a while ago, trying this out is a piece of cake. Both the reset-pin and GPIO 16 are freely accessible. The ESP8266 wakes up from deep sleep on a falling edge on the reset pin. This signal does not necessarily need to come from GPIO16, but can also be generated externally.

The brown wire does it all

NodeMCU syntax

It is explained in detail here. Basically it is:

node.dsleep(Time-In-uSecs , option)

Where "option" can be 0-4. But I don't quite understand the "0" option yet.
If you send it to sleep for 0 useconds, you'll need to trigger the wakeup from an external source.

Power considerations

In my experiments, the running module took around 70mA from it's 3,3V supply.
In deep sleep mode, the module draws a little less than 0.8mA which is great and will run the system for months with a good 18650 rechargeable battery. Still it is quite a bit more than the 10uA from the data sheet.
Looking at the Olimex datasheet, two things come to mind:
  • The SPI Flash memory (W25Q16BVSSIG) has a 25-50 uA standby current and can peak to 25mA when active.
  • There is a power LED with a 2k resistor that is constantly on and will probably account for most of the current
Another interesting option to node.dsleep() ist option 4, which leaves WiFi disabled when waking up. This saves a lot of power while the system can read sensors or process other information. I've seen it draw around 12mA in this mode.

Video

I've also documented that in a short video on my youtube channel.

Todo

Try the same with an ESP-12 that has no LED

Saturday, 24 October 2015

Using the ESP8266 as a WiFi range extender

This blog article refers to my YouTube Video you find here.
It shows how an ESP8266 module (like this one) can be used as a (rather unreliable) WiFi range extender.

Overview of the setup

Beside an ESP8266 module, you need to:

  • download the modified firmeware here and flash it to your module 
  • copy the DNS forwarder script from here to your module
  • add a route to the 192.168.4.0 subnet to your default gateway (i.e. usually  your WiFi dsl/cable router)
  • attach the module to your WiFi network and run it in StationAP mode:
 wifi.setmode(wifi.STATIONAP)  
 wifi.sta.config("YOURSSID","YOURWIFIPASSWD")  
 tmr.alarm(0, 500, 1, function()  
     if wifi.sta.getip()==nil then  
      print("Connecting to AP...")  
     else  
      tmr.stop(1)  
      tmr.stop(0)  
      print("Connected as: " .. wifi.sta.getip())  
     end  
   end)  
 cfg={}  
    cfg.ssid="intarwebs"  
    wifi.ap.config(cfg)  

  • connect another device to the "intarwebs" SSID. If you want to really use that, you should encrypt that side as well. Here is how.
The disconnects from the Wifi Router appear to be related to  big packets and/or heavy traffic. It has been suggested that it might be a power issue, but neither with the scope, nor with the Fluke 87V's min/max function I was able to detected a significant voltage drop.
I have captured the traffic with wireshark, but could not make sense of it yet. My best guess at the moment is that with a big TCP windows size, the module runs into a buffer size problem or that it is busy for too long on the "left" side. The module only has one radio to serve both connections, so unlike your typical router, it can't forward a continuous stream of packets.



Wednesday, 23 September 2015

Generic UDP proxy for NodeMCU / ESP8266 - Simple LUA DNS proxy

For a project that has been in the works for quite some time, I need a ESP8266 module to act as a DNS proxy. Other than on my very popular CaptiveIntraweb project, that simply lies to all DNS requests, I need real DNS lookups this time.

Getting my head slowly around the event driven nature of NodeMCU, the code turned into a very compact, generic UDP proxy or forwarder.
The script is completely unaware of the structure of the data and could be used to proxy all sorts of UDP data.

Here is my code:

 -- Simple DNS Proxy  
 -- 20150923 by Andy Reischle  
 -- Blog: www.AReResearch.net  
 -- Vids: www.youtube.com/AReResearch  
 --  
 -- Uses googles dns server 8.8.8.8  
 -- change to whatever suits you  
 cu=net.createConnection(net.UDP,0)  
 cu:on("receive",function(cu,c)   
   -- print("Got a reply")  
   s:send(c)  
   end)  
 s=net.createServer(net.UDP)  
 s:on("receive",function(s,d)  
   -- print ("Got a request!")  
   cu:connect(53,"8.8.8.8")  
   cu:send(d)   
   end)  
 s:listen(53)  

The ESP-module is connected to a WiFi AP, of course. The IP address of the ESP module is 192.168.1.74 and will be different, depending on your home DHCP server.

I can query DNS information through the module now:
me@raspberrypi:~$ nslookup
> server 192.168.1.74
Default server: 192.168.1.74
Address: 192.168.1.74#53
> www.areresearch.net
Server:         192.168.1.74
Address:        192.168.1.74#53

Non-authoritative answer:
www.areresearch.net     canonical name = ghs.google.com.
ghs.google.com  canonical name = ghs.l.google.com.
Name:   ghs.l.google.com
Address: 173.194.65.121
>
The corresponding tcpdump also looks very clean:

me@raspberrypi:~$ sudo tcpdump -i eth0 port 53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
23:39:08.416736 IP noname.43027 > noname.domain: 56537+ A? www.areresearch.net. (37)
23:39:08.422009 IP noname.46122 > fritz.box.domain: 4560+ PTR? 58.1.168.192.in-addr.arpa. (43)
23:39:08.426857 IP fritz.box.domain > noname.46122: 4560* 1/0/0 PTR noname. (88)
23:39:08.428198 IP noname.45680 > fritz.box.domain: 56651+ PTR? 74.1.168.192.in-addr.arpa. (43)
23:39:08.430620 IP fritz.box.domain > noname.45680: 56651* 1/0/0 PTR noname. (88)
23:39:08.432969 IP noname.38314 > fritz.box.domain: 15794+ PTR? 1.1.168.192.in-addr.arpa. (42)
23:39:08.435987 IP fritz.box.domain > noname.38314: 15794* 1/0/0 PTR fritz.box. (89)
23:39:08.480105 IP noname.domain > noname.43027: 56537 3/0/0 CNAME ghs.google.com., CNAME ghs.l.google.com., A 173.194.65.121 (101)

While the rest of the project still requires a lot of tinkering, this little piece of the puzzle works nicely.


Friday, 18 September 2015

New CaptiveIntraweb release V3 - ESP8266 / NodeMCU based captive portal

After a few hours of brushing things up, I released a new version of my CaptiveIntraweb on  my GitHub repo.
Apart from a few bug fixes, an all-new init.lua now does the Wifi Setup, compiles the LUA files and starts the servers. It also features an option to prevent the TCP and UDP servers from starting.

I did most of the development on my new, very user friendly V3 NodeMcu Lua WIFI Development Board I got directly from the PRC from Banggood. That board has 4MByte of flash memory. (Yes. I mean MBytes here, not MBit)

Looks a lot like a ESP-12E module on the board

If you don't know about CaptiveIntraweb, here is the original video from May 2015, although quite a bit of progress has been made since then.

With the new CaptiveIntraweb  loaded, the module startup now looks like this:
 ---------------------  
 Setting up WiFi AP...  
 Done.  
 ---------------------  
 Flash size is 4096 kBytes.  
 File system:  
  Total : 3360 kBytes  
  Used : 124 kBytes  
  Remain: 3236 kBytes  
 ---------------------  
 Compiling LUA files...  
 No need to compile   dns-liar.lua  
 No need to compile   server.lua  
 Compiling done.  
 ---------------------  
 Send some xxxx Keystrokes now to abort startup.  
 Will launch servers in 5 seconds...  
 > ---------------------  
 Starting HTTP Server  
 HTTP Server listening. Free Heap:    13080  
 Starting DNS Server  
 DNS Server listening. Free Heap:    10008  
 ---------------------  

Thursday, 2 July 2015

Second (successful) attempt to route IP packets with ESP8266

Now that one was a piece of cake:
As suspected /app/include/lwipopts.h overruled the file I modified previously.

So with a 
#define IP_FORWARD 1
in there, the the module started forwarding packets

Ping connectivity table
PING 192.168.1.50 192.168.1.75 192.168.4.1 192.168.4.3
192.168.1.50 n/a n/a n/a YES
192.168.1.75 YES n/a n/a n/a
192.168.4.1 YES n/a n/a YES
192.168.4.3 YES n/a YES n/a



So I now could ping the Laptop (ouch: forgot to disable the firewall first) from the mobile device and vice versa.
Here is the caveat:
  • I need a static route from the Laptop to the "StationMode" interface of the ESP8266. The cooler way to do that is on the default router.
Up to now this is an easy one for the ESP module. Both subnets are directly connected, so the routing decision is not really that hard. With very little tweaking, this could already be used  as an extremely simple range extender working at layer 3.
To daisy-chain / mesh more of these, I need to supply routing information to LWIP. It is not too obvious where to do that in the code or what it takes to add commands to manipulate routes through LUA.

Wednesday, 1 July 2015

First (failed) attempt to route IP packets with ESP8266

In every other comment on my previous projects, someone brought up the topic of mesh networking with ESP8266 modules. Gooooogling the topic, I couldn't find a project that had made into a stable release. (Drop me a line in the comments if you found/have one)

Taking things nice & slow, I started with the following setup:




Ping connectivity table
PING 192.168.1.50 192.168.1.75 192.168.4.1 192.168.4.3
192.168.1.50 n/a n/a n/a n/a
192.168.1.75 YES n/a n/a n/a
192.168.4.1 YES n/a n/a YES
192.168.4.3 NO n/a n/a n/a

So as expected, the ESP8266/NodeMCU does not forward IP packets. I had a peek at the NodeMCU sources and made the following change to /app/include/lwip/opt.h:

 /**  
  * IP_FORWARD==1: Enables the ability to forward IP packets across network  
  * interfaces. If you are going to run lwIP on a device with only one network  
  * interface, define this to 0.  
  */  
 #ifndef IP_FORWARD  
 // #define IP_FORWARD           0  
 #define IP_FORWARD           1  
 #endif  

I rebuilt the firmware, flashed it to a ESP Module and:

FAILED. No changes to the module's routing behaviour.

If anyone is more familiar with the code, don't hesitate to leave a comment.


Next Steps:

  • Get packet forwarding to work
  • Routes? What routes? (There is a hook for those in later versions of LWIP. Backporting possible?)



PS:
Another search of the source code shows that there is another place that sets IP_FORWARD: /app/include/lwipopts.h - I'll try that next.







Monday, 22 June 2015

Two OLIMEX MOD-WIFI-ESP8266-DEV boards in the mail

When a CaptiveIntraweb experimenter from Chicago pointed out that he had problems with Olimex ESP8266 modules, we looked into the problem and it seemed like a file system related issue.
The cool thing is that these modules come with 2MByte of i2c flash, rather than the usual 512k. And that might just be the source of the problem.

I wasn't aware these modules existed and immediately ordered a pair. Despite the fact that the German postal service is on strike, the modules arrived on Saturday.

Nice silkscreen 

The weekend was rather busy, so I couldn't test drive the modules. From the first look, I am impressed by the build quality and the nicely readable silkscreen. So impressed in fact, that I'll mount the headers upside-down to have an unobstructed view of the print.

One thing I didn't like at first glance was that to change to flash mode, I need to change soldered jumpers. With the number of tries I need to get things right, I considered mounting a switch.
A closer look at the schematic revealed this:
Now that's nice circuit design! I can still use a jumper cable on the breadboard to tie GPIO0 to GND manually to reflash the firmware. 

I will try that tonight and let you know how it went.
It went better than I expected. See here.

Wednesday, 20 May 2015

Mini WiFi-Throwie with CR123A

Last night I finally found the time to fire up the soldering iron and try the CaptiveIntraweb with a CR123A cell.
As expected, this worked without any issues. From the data sheet, I expect a run time of approx. one day, although I haven't tried that yet.
Again the discharge rate of  around 70mA ist significantly higher than the 20mA mentioned in the data sheet. From this page it looks like the Panasonic cell is the best choice for high discharge currents.
A bit of tape (Kapton tape should be the ideal choice) to told it together and that's it.
Just don't forget to recover the throwie after the battery is drained and recycle it properly.

I will have the video on my Youtube Channel as soon as I have it ready.