A VNC server for Lua on NodeMCU
Posted: Wed Dec 28, 2016 5:35 am
This is a VNC server framework for Lua on NodeMCU. It implements a basic subset of the RFB protocol and enables Lua scripts to send graphics via TCP connection to a VNC client on PC or smartphone. It was inspired by pylotron which demonstrates the simplicity of graphical interaction between an embedded system and a smart client via VNC.
The vncserver.lua module and accompanying example scripts are available from nodemcu-vncsever on github.com.
Modules required to be compiled into the firmware:
Setting up the server
The vnc server operates on a NodeMCU socket instance which has to be prepared upfront by the user script: Establish a TCP server listening on port 5900 and call the start() function when a client connects.
All protocol sequences are subsequently handled by the vncserver module.
Hooks for client events
Once the server exchanged all required info, it stands by and waits for messages from the client. It will delegate these to the user script via callbacks. Callback functions for the following events can be registered with vncsrv.on()
Sending graphics to the client
Whenever the client requests a framebuffer update, the server should send a FramebufferUpdate message containing a list of rectangles. Note that vncserver only supports RRE encoding at the moment.
A rectangle tells the client which area of the display is affected and what is the background color of this region:
The following sub-rectangles (if any) define the regions with different colors. They are specified relative to the surrounding rectangle:
Example from rectangles.lua:
For more advanced graphics there's an integration with the u8g library. Add the virtual RLE framebuffer display into the firmware and render any u8g script on the VNC client (see u8g_vnc.lua for details):
The vncserver.lua module and accompanying example scripts are available from nodemcu-vncsever on github.com.
Modules required to be compiled into the firmware:
- net
- bit
- struct
- u8g with fb_rle display
Setting up the server
The vnc server operates on a NodeMCU socket instance which has to be prepared upfront by the user script: Establish a TCP server listening on port 5900 and call the start() function when a client connects.
Code: Select all
vncsrv = require("vncserver")
-- Set up TCP server
srv = net.createServer( net.TCP, 120 )
srv:listen( 5900,
function( conn )
-- start VNC server with connected socket
vncsrv.start( conn, 128, 128 )
end
)
All protocol sequences are subsequently handled by the vncserver module.
Hooks for client events
Once the server exchanged all required info, it stands by and waits for messages from the client. It will delegate these to the user script via callbacks. Callback functions for the following events can be registered with vncsrv.on()
- fb_update client sent a FramebufferUpdateRequest
- disconnection client disconnected
- key client sent a KeyEvent
- pointer client sent a PointerEvent
- data_sent all queued data was sent to the client
Sending graphics to the client
Whenever the client requests a framebuffer update, the server should send a FramebufferUpdate message containing a list of rectangles. Note that vncserver only supports RRE encoding at the moment.
A rectangle tells the client which area of the display is affected and what is the background color of this region:
Code: Select all
vncsrv.rre_rectangle( base_x, base_y, width, height, num_subrectangles, background )
The following sub-rectangles (if any) define the regions with different colors. They are specified relative to the surrounding rectangle:
Code: Select all
vncsrv.rre_subrectangle( rel_x, rel_y, width, height, color )
Example from rectangles.lua:
Code: Select all
function draw_rectangles()
-- FramebufferUpdate message indicating that 1 rectangle description follows:
vncsrv.update_fb( 1 )
-- Next is the rectangle in RRE encoding, 4 sub-rectangles will follow:
vncsrv.rre_rectangle( 0, 0, 128, 128, 4, 0 )
-- The sub-rectangles:
vncsrv.rre_subrectangle( 10, 10, 30, 10, red )
vncsrv.rre_subrectangle( 50, 20, 20, 40, green )
vncsrv.rre_subrectangle( 80, 80, 40, 40, blue )
vncsrv.rre_subrectangle( 60, 50, 30, 50, yellow )
end
For more advanced graphics there's an integration with the u8g library. Add the virtual RLE framebuffer display into the firmware and render any u8g script on the VNC client (see u8g_vnc.lua for details):
Code: Select all
disp = u8g.fb_rle( drv_cb, srv_width, srv_height )