Unofficial witty cloud module documentation with nodemcu firmware

Or how to make a quick internet button

February 25, 2016

I wanted to try my hand with ESP8266 modules, so I got a witty cloud development board. It's running a proprietary firmware from gizwits which I backed up if anyone wants to look at it.

The board is in two parts: programming board("cape") with ch340g usb serial and 3.3V converter (plus flash and reset buttons); and main board with the esp module, ams1117 3.3V voltage regulator, a button, a blue led, an rgb led, and a light sensor(photo resistor). All this for the price of a nodemcu board, but in a smaller form factor.

One of the greatest things of the ESP8266 ecosystem is nodemcu-firmware, an environment allowing you to program the microcontroller in lua, greatly simplifying the prototyping and familiarization.

After backing up the flash with esptool (see esptool read_flash), I flashed the latest release of nodemcu-firmware. Then, using nodemcu-uploader, one can access the lua REPL (nodemcu-uploader terminal) and uploads lua scripts (nodemcu-uploader --baud 9600 upload init.lua); init.lua being the first script being run at powerup.

Quick doc

I reverse-engineered the various goodies that are on board, since I didn't find any documentation on this specific board online:

Blue LED: use the PWM 4. High duty cycle = OFF.

-- Use a LED with a 500Hz PWM
function led(pin, level)
    pwm.setup(pin, 500, level)
    pwm.start(pin)
end

-- Control the Blue LED: 0 -> 1023 higher means light off
function blueLed(inverted_level)
    led(4, inverted_level)
end

blueLed(10) -- test at high intensity

RGB LED: use PWMs 8, 6, 7. High duty cyle = ON.

-- Control an RGB LED: three 0->1023 values; higher means more light
function rgb(r, g, b)
    led(8, r)
    led(6, g)
    led(7, b)
end

rgb(500, 0, 0) -- test RED

Button: GPIO 2. button pressed = 0 level.

-- launch connect() on button press
gpio.mode(2, gpio.INPUT)
gpio.trig(2, "down", connect)

Light sensor: use the ADC.

-- Print light sensor value
print(adc.read(0))

Going further

I then discovered the official nodemcu-firmware documentation currently points to the dev branch; which has many new modules and functions I wanted to use (like the wifi event monitor or http module) that weren't available in master yet. I used the nodemcu cloud builder, a service provided by a kind community member to build a custom version of nodemcu-firmware on the dev branch and the modules I needed enabled.

This allows to do this kind of code, that connects to wifi on a button press, and reacts with a simple HTTP request:

function connect()
    -- if wifi is already connected (config saved), launch job directly
    if wifi.sta.status() == wifi.STA_GOTIP then
        doOnlineJob()
        return
    end
    rgb(1000, 50, 0) -- turn orange
    for event=wifi.STA_IDLE,wifi.STA_GOTIP do
        wifi.sta.eventMonReg(event, monCallback)
    end
    wifi.sta.config("mynetworkssid", "mynetworkpassword")
    wifi.sta.eventMonStart(100) --the event mon polls every 100ms for a change
end

function monCallback(prevState)
    state = wifi.sta.status()
    if prevState == nil then
        prevState = "unknown"
    end
    print("Wifi status " .. prevState .. " -> " .. state)
    blueLed(state*204) -- led intensity depends on status, with success = OFF
    if state == wifi.STA_GOTIP then
        rgb(0, 200, 150) --blue/green-ish, wifi OK
        print("Got IP " .. wifi.sta.getip())
        wifi.sta.eventMonStop("unreg all") -- stop event monitor
        doOnlineJob()
    end
    if state == wifi.STATION_NO_AP_FOUND or state == wifi.STATION_CONNECT_FAIL then
        rgb(150, 0, 0) -- red/fail
        wifi.sta.eventMonStop("unreg all") -- stop event monitor
    end
end

function doOnlineJob()
    rgb(150, 0, 150) -- working, purple
    http.post("http://example.invalid/api/pushed", nil,
        '{"hello": "from_esp_witty_42"}', function(status_code, body)
            if status_code == nil or body == nil then
                print(status_code)
                print(body)
                rgb(200, 0, 0) --fail red
                return
            end
            print("Got code " .. status_code .. " answer " .. body)
            if status_code == 200 then
                rgb(0, 0, 200) --success, blue
            end
        end)
end

This is reproducing the software function of the DASH/IoT Button, Netflix Switch or Flic.

There are a few projects that will guide you through the hardware part of building a button with an ESP module.

PS: Be careful of big https cert chains, there's a hardcoded limit of 5120 bytes for the SSL buffer in the firmware, that might make the handshake fail.

PPS: 2016-07-01 I did a talk on ESP8266 modules at the Paris Embedded Meetup #9.

Share