Simple TCP server with LUA on ESP8266

Here is a new LUA script example for your ESP8266 running NodeMCU. The script creates a TCP server listening on port 80. Each time you receive data on the server, it toggles the LED connected to the ESP8266 and sends a message back to the client.

If you need help with installing NodeMCU on your ESP8266, here I have a post for the process.

First TCP server example

Let us got through the code in detail and in the end, you will find the full code.

gpio0 = 3
gpio2 = 4

We need to map our GPIOs to the correct pin numbers. This was already discussed in the last article.

ssid = "AP-Name"
password = "YourPassword"

Enter your Wifi SSID which you want to use for the connection and also the password for this network.

pinLed = gpio0
pinStatus = 0

gpio.mode(pinLed, gpio.OUTPUT)

Here we define our GPIO0 as the LED output and create a helper variable to save the pin status.

wifi.setmode(wifi.STATION)
wifi.sta.config(ssid, password)

tmr.alarm(0, 1000, 1, function()
     if wifi.sta.getip() == nil then
          print("connecting...")
     else
          print("IP: ", wifi.sta.getip())
          tmr.stop(0) -- Stop loop
          main() -- Start the main function
     end
end)

This code block sets your module into STATION mode, which can connect to other access points. Then it will configure the Wifi SSID and password. After the configuration, it will enter a loop that runs every 1000 ms. Here we check if the module has an IP which means we are connected to our network and start the main function. If not we will run in this loop as long as we have no IP.

server = net.createServer(net.TCP)
server:listen(80, function(connection)
     connection:on("receive", function(connection, payload)
          [...]
     end)
end)

Now we can create the TCP server. The net.createServer() lets you create a UDP or TCP server. With net.TCP we tell the function that we want a TCP server.

We tell the server module to implement a function when we receive a connection on port 80. If this connection receives a payload we start a new function.

print(payload)
connection:send("<p>Hello Browser, I'm an ESP-01 module</p>")
pinStatus = 1 - pinStatus
gpio.write(pinLed, pinStatus)
connection:close()

This is the content of our receive function. We print our payload, so we can see what happens. Then we send back a string to the connected client. On our board, we toggle the LED to show that the receive function was called. After all of this, we close the connection.

And here the full structured code with comments:

-- Implement pin mapping
gpio0 = 3
gpio2 = 4

ssid = "AP-Name"
password = "YourPassword"

pinLed = gpio0
pinStatus = 0

-- Set pinLed to output
gpio.mode(pinLed, gpio.OUTPUT)

-- Start the wifi connection
wifi.setmode(wifi.STATION)
wifi.sta.config(ssid, password)

-- Do loop until connection is established
tmr.alarm(0, 1000, 1, function()
     if wifi.sta.getip() == nil then
          print("connecting...")
     else
          print("IP: ", wifi.sta.getip())
          tmr.stop(0) -- Stop loop
          main() -- Start the main function
     end
end)

-- Main function
function main()
     server = net.createServer(net.TCP) -- Creates TCP server
     server:listen(80, function(connection) -- Listening on port 80
          connection:on("receive", function(connection, payload) -- Call function on receive
               print(payload) -- Print received data
               connection:send("<p>Hello Browser, I'm an ESP-01 module</p>") -- Send a message to the client
               pinStatus = 1 - pinStatus -- Toggle pinStatus
               gpio.write(pinLed, pinStatus) -- Set LED to 0 or 1
               connection:close() -- Close the connection
          end)
     end)
end

The second example with the URL request

Because all of the initialization is the same as in the first example, we only look at the main function.

function main()
     server = net.createServer(net.TCP)
     server:listen(80, function(connection)
          connection:on("receive", function(connection, payload)
               [...]
          end)
     end)
end

The creation of the TCP server is the same. Only the part in the receive function is different this time, so we skip to the next code block.

findLedOn = string.find(payload, "led_on")
findLedOff = string.find(payload, "led_off")

We search for the two strings “led_on” and “led_off” in the payload. If the string is not found, the variable will contain nil.

if findLedOn == nil and findLedOff == nil then
     connection:send("<p>Usage:</br>[IP]/led_on - turn LED on</br>[IP]/led_off - turn LED off</p>")
elseif findLedOn ~= nil then
     connection:send("<p>LED is now on</p>")
     pinStatus = 1
     gpio.write(pinLed, pinStatus)
elseif findLedOff ~= nil then
     connection:send("<p>LED is now off</p>")
     pinStatus = 0
     gpio.write(pinLed, pinStatus)
else
     connection:send("<p>Bad command</p>")
end

Here we check if we have found the strings in the payload. If both variables contain nil, we have not found both strings. For this reason, we send a message to the connected client, which describes the usage of this script.

If one of the strings was found, we toggle the LED into the requested state and send a confirmation to the client.

And here is the full structured code with comments:

-- Implement pin mapping
gpio0 = 3
gpio2 = 4

ssid = "AP-Name"
password = "YourPassword"

pinLed = gpio0
pinStatus = 0

-- Set pinLed to output
gpio.mode(pinLed, gpio.OUTPUT)

-- Start the wifi connection
wifi.setmode(wifi.STATION)
wifi.sta.config(ssid, password)

-- Do loop until connection is established
tmr.alarm(0, 1000, 1, function()
     if wifi.sta.getip() == nil then
          print("connecting...")
     else
          print("IP: ", wifi.sta.getip())
          tmr.stop(0) -- Stop loop
          main() -- Start the main function
     end
end)

-- Main function
function main()
     server = net.createServer(net.TCP) -- Creates TCP server
     server:listen(80, function(connection) -- Listening on port 80
          connection:on("receive", function(connection, payload) -- Call function on receive

               findLedOn = string.find(payload, "led_on") -- Search for string "led_on"
               findLedOff = string.find(payload, "led_off") -- Search for string "led_off"

               print(payload) -- Print received data

               if findLedOn == nil and findLedOff == nil then
                    connection:send("<p>Usage:</br>[IP]/led_on - turn LED on</br>[IP]/led_off - turn LED off</p>")
               elseif findLedOn ~= nil then
                    connection:send("<p>LED is now on</p>")
                    pinStatus = 1
                    gpio.write(pinLed, pinStatus)
               elseif findLedOff ~= nil then
                    connection:send("<p>LED is now off</p>")
                    pinStatus = 0
                    gpio.write(pinLed, pinStatus)
               else
                    connection:send("<p>Bad command</p>")
               end

               connection:close() -- Close connection
          end)
     end)
end

Here you can find other NodeMCU related posts.

1 thought on “Simple TCP server with LUA on ESP8266”

  1. Hallo,

    danke für diese schöne Arbeit. Hier ist noch einen Beispiel für TCP Client (Konsole c#) falls jemand sie braucht.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Sockets;
    using System.IO;
    namespace TCPClient
    {
    class Program
    {

    static void Main(string[] args)
    {
    while (true) {
    TcpClient tcpClient = new TcpClient(“192.168.1.82”, 80);
    // StreamReader STR = new StreamReader(tcpClient.GetStream());
    // Uses the GetStream public method to return the NetworkStream.
    NetworkStream netStream = tcpClient.GetStream();

    if (netStream.CanWrite)
    {
    Byte[] sendBytes = Encoding.UTF8.GetBytes(“Halli ich bin TCP Client”);
    netStream.Write(sendBytes, 0, sendBytes.Length);
    // sendBytes = Encoding.UTF8.GetBytes(“Q”);
    // netStream.Write(sendBytes, 0, sendBytes.Length);
    }
    else
    {
    Console.WriteLine(“You cannot write data to this stream.”);
    tcpClient.Close();

    // Closing the tcpClient instance does not close the network stream.
    netStream.Close();
    return;
    }

    if (netStream.CanRead)
    {
    // for (var i = 0; i < 5; ++i)
    // {
    Console.WriteLine("Read…");
    System.Threading.Thread.Sleep(1000);
    byte[] buffer = new byte[1024];
    var recv = netStream.Read(buffer, 0, 1024);
    Console.WriteLine("{0} Bytes empfangen: {1}", recv, Encoding.ASCII.GetString(buffer, 0, recv));
    //}
    }
    else
    {
    Console.WriteLine("Cannot read");
    }

    //Console.ReadKey();
    }

    }
    }
    }

    Reply

Leave a Comment