Small 128×64 OLED i2c displays can picked up for just over £3 on Amazon, and they are great for interfacing with a NodeMCU IoT device.
Wiring is simple…
- NodeMCU 3.3v – OLED VCC
- NodeMCU GND – OLED GND
- NodeMCU D1 – OLED SDA
- NodeMCU D2 – OLED SCL or SCK

Your NodeMCU firmware must have been compiled with the i2c and u8g modules included. If you need to add these, see my previous post – NodeMCU Lua setup using a Mac. It also explains how to upload the example Lua code below.
The u8g module comes with some great examples. I’ve taken some of the relevant parts for a simple two page Lua script that prints out two alternating screens of text.
sda = 1 -- SDA Pin
scl = 2 -- SCL Pin
function init_display(sda,scl) --Set up the u8glib lib
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
function updateDisplay(func)
-- Draws one page and schedules the next page, if there is one
local function drawPages()
func()
if (disp:nextPage() == true) then
node.task.post(drawPages)
end
end
-- Restart the draw loop and start drawing pages
disp:firstPage()
node.task.post(drawPages)
end
function drawScreen1()
disp:drawFrame(2,2,126,62)
disp:drawFrame(5,5,121,57)
disp:drawStr(5, 20, " RobertPrice.co.uk")
disp:drawStr(5, 35, " @robertprice")
end
function drawScreen2()
disp:drawFrame(2,2,126,62)
disp:drawFrame(5,5,121,57)
disp:drawStr(5, 20, " NodeMCU OLED Test")
disp:drawStr(5, 35, " 12th July 2017")
end
local drawDemo = { drawScreen1, drawScreen2 }
function demoLoop()
-- Start the draw loop with one of the demo functions
local f = table.remove(drawDemo,1)
updateDisplay(f)
table.insert(drawDemo,f)
end
init_display(sda,scl)
demoLoop()
tmr.alarm(4, 5000, 1, demoLoop)
This may look a bit complex for just displaying text, but it aims to be reusable. We use the tmr.alarm to avoid bogging the CPU down in a loop.

I’ve tried this with two different i2c OLED displays, and they both work.