Proxy LCD – Remote LCD

First brick for my ‘secret’ project is ready. It is a remote LCD based on NodeMCU. Such node has a char lcd (HD44780) connected to it and listens for incoming broadcast messages. After receiving message that is for this node it displays content. It is nothing new but lets quickly summarize it.

Source code on GitHub

Wiring HD44780

As a brain I’m using NodeMCU v3. Why v3? Because it has a nice VU pin with 5V 🙂
We can connect any HD44780 via GPIO (here is sample for any except 40×4, for it add E2 connection):

  LCD                      NodeMCU
1 VSS ------------- GND
2 VDD ----------------------- VU 
3 V0 ------/\/\/\-
              \---- GND
4 RS ------------------------ D6
5 R/W ------------- GND
6 E ------------------------- D7
11 D4 ----------------------- D5
12 D5 ----------------------- D3
13 D6 ----------------------- D1
14 D7 ----------------------- D2
15 A ------/\/\/\-
              \---- VU
16 K -------------- GND

Or via i2c (here is 40×4 with E2, for other remove E2 wiring):

LCD                                     PCF8574                    
13 -------- GND               GND ----- A0   Vcc ---- +5V            
14 -------- +5V               GND ----- A1   SDA ---- D1         
12 --/\/\ [potentiometer]     GND ----- A2   SCL ---- D2         
       \--- GND              LCD4 ----- P0   INT                 
11 [RS]---- P4               LCD3 ----- P1   P7
10 -------- GND              LCD2 ----- P2   P6 ----- LCD15
 9 [E]----- P5               LCD1 ----- P3   P5 ----- LCD9
15 [E2] --- P6                GND ----- GND  P4 ----- LCD11
 4 [DB4]--- P0
 3 [DB5]--- P1
 2 [DB6]--- P2                          NodeMCU
 1 [DB7]--- P3                        SDA --- D3 
17 --/\/\ [potentiometer]             SCL --- D4
       \--- +5V                       +5V --- V


We are using boilerplate as the base. We have two configuration files, one is parameters.lua and second is parameters-device.lua. If you do not have those files remove .dist from parameters.dist.lua and parameters-device.dist.lua.
Be sure that you set NET_AP and NET_PASSWORD correctly (in parameters.lua). AP is the name of access point and PASSWORD is its password.
Next set node name in parameters-device.lua. This is the name that I will refer to quite often.
With this node should boot. If you ever hit reboot-loop wire GND to D1, it will abort booting.

Setting LCD

Main code goes to main.lua file. This file is launched after making WiFi connection.
I’m gonna show you two examples, one with display 16×2 connected via gpio and second with 40×4 connected via i2c.

16×2 via GPIO

network_message = require "network_message"
gpio_driver = require "lcd_hd44780_gpio"
hd44780 = require("lcd_hd44780")
server_listener = require "server_listener"
hd44780_handler = require "lcd_hd44780_handler"

drv = gpio_driver()
lcd = hd44780(16, 2, drv, 'buffered', 0, 0)

lcd:set_xy(0, 1)
lcd:write("Awaiting content")
lcd:set_xy(9, 0)

--attach lcd to handler
lcd_handler = hd44780_handler(lcd)

-- add handlers to listener
server_listener.add("lcd", lcd_handler)


-- run server

What is going on there?
First we import 5 modules. Those required by display are: lcd_hd44780_gpio and lcd_hd44780. First is a driver, define the way lcd is connected to nodemcu, second is higher abstract class, allows easy writes.
Module network_message takes care of network messages.
We have a module server_listener. Its job is to receive messages and pass them to all handlers. And handler is a special class that knows what messages are supported by module. In this example we have a hd44780_handler.

40×4 via i2c

network_message = require "network_message"

i2c_driver = require("lcd_hd44780_i2c")
hd44780 = require("lcd_hd44780")

server_listener = require "server_listener"
hd44780_handler = require "lcd_hd44780_handler"

--setup LCD
pins = {
    RS= 4,
    E1= 5,
    E2= 6,
    DB4= 0,
    DB5= 1,
    DB6= 2,
    DB7= 3,

drv = i2c_driver(0x20, 4, 5, pins)
lcd = hd44780(40, 4, drv, 'buffered', 0, 0)

lcd:write('Awaiting content')
lcd:write('> Ready')
lcd:set_xy(33, 0)

--attach lcd to handler
lcd_handler = hd44780_handler(lcd)

-- add handlers to listener
server_listener.add("lcd", lcd_handler)

-- run server

In this example we are using lcd_hd44780_i2c driver. We set pins manually because we are using second E signal.

Network messages

Message is a packet in iot:1 protocol. This is used to communicate between Nodes. It is simple json string. After receiving message, server decode it to table and checks if current node is on target list. To target all nodes keyword ALL is used.
Lets look at sample message:

    "protocol": "iot:1",
    "node": "Rpi-lcd-1",
    "chip_id": "RpiB",
    "event": "lcd.content",
    "parameters: [
        "content": [
             "-(=^.^)", "       "
    "response": "",
    "targets": [

Three events are supported by LCD handler: lcd.cmd, lcd.char and lcd.content. For us most important is lcd.content.
When sending it you need to send content of each row (field parameters/content).

Real live usage

So we have a nice device, some messages, protocols, nodes but who cares? We want to display something ! But how to do it?
It is relatively easy when we use CharLCD Python module with WiFi driver.

We can easily install it via:

pip install charlcd

and we need one more library: iot_message. This is python implementation of iot:1 protocol.

pip install iot_message

We have all dependencies so lets see the code:

from iot_message import message
from charlcd.drivers.wifi_content import WiFi
from charlcd.buffered import CharLCD

msg = message.Message('desktop-main')
drv = WiFi(msg, ['node-40x4'], ('', 5053))
lcd = CharLCD(40, 4, drv)

msg1 = message.Message('desktop-main')
drv1 = WiFi(msg, ['node-1'], ('', 5053))
lcd1 = CharLCD(16, 2, drv1)

lcd.write('Hi from desktop !', 1, 0)
lcd.write('-(=^_^)', 33, 0)

lcd1.write('-(=^_^)', 9, 0)

msg = message.Message('desktop-main')

In this line we create a message pattern and set our name.

drv = WiFi(msg, ['node-40x4'], ('', 5053))

Here we initialize WiFi driver, we set Message, target node names (names of remote LCD nodes) and our broadcast IP with port.

lcd = CharLCD(40, 4, drv)

Finally we initialize LCD with size and driver. In this example we are using WiFi driver but we may use i2c or gpio driver. This is very useful on Raspberry Pi.

lcd.write('Hi from desktop !', 1, 0)
lcd.write('-(=^_^)', 33, 0)

In those three lines we write to buffer at position 1×0 and 33×0. Then we flush content to LCD. Buffer works locally but flush() sends it to remote node.


This summarize remote LCD Node. If you want to know more see tag nodehd44780
TLDR: node can display text that is in message delivered via wifi. Easiest way to send sth to it is via CharLCD python library.

One comment

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.