So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By Obvious0ne
#68388 I'm trying to evaluate using the ESP8266 for a new product and I'm stuck. I set up a simple test app that's supposed to connect, send a short message, get the reply, disconnect, and then repeat.

I am able to connect and send/receive data, but the socket close command doesn't seem to work correctly.

I noticed that I wasn't always seeing the print statement I had in the close callback and that the available heap kept getting smaller with every iteration. At some point I noticed that the close messages that I do get all have a "something went wrong" exit code -99, and I assume that is the root of my problem.

I simplified the code as much as possible so that now it's pretty much the same as the example code from the nodemcu.readthedocs page. I tried putting the ws:close call in the receive callback and I've also tried calling it from a tmr.create():alarm(1000, tmr.ALARM_SINGLE... function and the results are the same.

Here's the minimal version of the code that's failing:

    local ws = websocket.createClient()
    ws:on("connection", function(ws)
      print('got ws connection')
      ws:send('hello!')
    end)
    ws:on("receive", function(_, msg, opcode)
      print('got message:', msg, opcode) -- opcode is 1 for text message, 2 for binary
      ws:close()
    end)
    ws:on("close", function(_, status)
      print('connection closed', status)
      ws = nil -- required to lua gc the websocket client
    end)
   
    ws:connect('ws://echo.websocket.org')

Here are the results from Lualoader:
dofile("websocket2.lua")
> got ws connection
got message: hello! 1
connection closed -99

I should have the latest version - I did a build from the master branch at nodemcu-build.com earlier this week.
Am I doing something wrong? Have other people successfully used websockets with this device?

Thanks
Glen
User avatar
By Obvious0ne
#68510 I got an email back from the developer of this module. Apparently the -99 return code is a minor bug and always happens when you initiate a close. I still haven't been able to make the test where I open the socket, send a message, and then close the socket work reliably though.

The following is the terminal output with my current code after adding some manual garbage collection statements to see if that is a part of the problem. It looks like quite often something just isn't letting go when I try to close - and it takes the module 10 minutes to figure it out and resume normal operation.

Code: Select alldofile("websocket2.lua")
Running websocket2.lua
> Pre-collect heap available:36760
Post-collect heap available:36792
Tx:1
Rx:   ServerABC: Websocket message number 1
Pre-collect heap available:34104
Post-collect heap available:34200
websocket not available

Then 10 minutes worth of this printing over and over:
Pre-collect heap available:34152
Post-collect heap available:34200
websocket not available

Ws closed, code:   -103
Pre-collect heap available:36304
Post-collect heap available:36600
Tx:2
Rx:   ServerABC: Websocket message number 2
Ws closed, code:   -99
Pre-collect heap available:34320
Post-collect heap available:34616
Tx:3
Rx:   ServerABC: Websocket message number 3
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:4
Rx:   ServerABC: Websocket message number 4
Pre-collect heap available:32120
Post-collect heap available:32224
websocket not available

Then 10 minutes worth of this printing over and over:
Pre-collect heap available:34144
Post-collect heap available:34192
websocket not available

Ws closed, code:   -103
Pre-collect heap available:36304
Post-collect heap available:36600
Tx:5
Rx:   ServerABC: Websocket message number 5
Ws closed, code:   -99
Pre-collect heap available:34320
Post-collect heap available:34616
Tx:6
Rx:   ServerABC: Websocket message number 6
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:7
Rx:   ServerABC: Websocket message number 7
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:8
Rx:   ServerABC: Websocket message number 8
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:9
Rx:   ServerABC: Websocket message number 9
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:10
Rx:   ServerABC: Websocket message number 10
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:11
Rx:   ServerABC: Websocket message number 11
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:12
Rx:   ServerABC: Websocket message number 12
Ws closed, code:   -99
Pre-collect heap available:32336
Post-collect heap available:32632
Tx:13
Rx:   ServerABC: Websocket message number 13
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:14
Rx:   ServerABC: Websocket message number 14
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:15
Rx:   ServerABC: Websocket message number 15
Ws closed, code:   -99
Pre-collect heap available:32336
Post-collect heap available:32632
Tx:16
Rx:   ServerABC: Websocket message number 16
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:17
Rx:   ServerABC: Websocket message number 17
Ws closed, code:   -99
Pre-collect heap available:32368
Post-collect heap available:32664
Tx:18
Rx:   ServerABC: Websocket message number 18
Ws closed, code:   -99
Pre-collect heap available:32336
Post-collect heap available:32632
Tx:19
Rx:   ServerABC: Websocket message number 19
Ws closed, code:   -99
Pre-collect heap available:32336
Post-collect heap available:32632
Tx:20
Rx:   ServerABC: Websocket message number 20
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:21
Rx:   ServerABC: Websocket message number 21
Ws closed, code:   -99
Pre-collect heap available:32336
Post-collect heap available:32632
Tx:22
Rx:   ServerABC: Websocket message number 22
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:23
Rx:   ServerABC: Websocket message number 23
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:24
Rx:   ServerABC: Websocket message number 24
Ws closed, code:   -99
Pre-collect heap available:32344
Post-collect heap available:32640
Tx:25
Rx:   ServerABC: Websocket message number 25
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:26
Rx:   ServerABC: Websocket message number 26
Ws closed, code:   -99
Pre-collect heap available:32352
Post-collect heap available:32648
Tx:27
Rx:   ServerABC: Websocket message number 27
Pre-collect heap available:32128
Post-collect heap available:32232
websocket not available

Then 10 minutes worth of this printing over and over:
Pre-collect heap available:34144
Post-collect heap available:34192
websocket not available


Ws closed, code:   -103
Pre-collect heap available:36304
Post-collect heap available:36600
Tx:28
Rx:   ServerABC: Websocket message number 28
Ws closed, code:   -99
Pre-collect heap available:34320
Post-collect heap available:34616
Tx:29
Rx:   ServerABC: Websocket message number 29
Ws closed, code:   -99
Pre-collect heap available:32360
Post-collect heap available:32656
Tx:30
Rx:   ServerABC: Websocket message number 30
Ws closed, code:   -99


I have concerns about scope in my code where I'm relying on the callbacks that live inside the send_websocket_message function to still work after the function has exited, but I ran into problems trying to move the callbacks outside of send_websocket_message. When I do that with the ws_connect function my call to ws:send results in a panic message because the websocket isn't connected - but the whole reason we got into ws_connect was because of the "connection" event. I don't know what I'm doing wrong - I'm pretty new to lua scripting.

Here's the code with the calls inside the send_websocket_message function. This code resulted in the output I posted above:
Code: Select all-- This file creates websocket connection, sends a test message, closes the connection, and then repeats

print("Running websocket2.lua")
local message_timer = tmr.create()  -- Timer used to periodically open the socket and send a message
local message_counter = 1           -- Counter variable for test messages
local ws = nil                      -- Websocket handle
   
-- In this test, the following function just establishes the connection and the send happens in the "on connection" method
function send_websocket_message()

   print("Pre-collect heap available:" .. node.heap()) 
   collectgarbage("collect")
   print("Post-collect heap available:" .. node.heap()) 
   if ws == nil then
      ws = websocket.createClient()         
     
      -- Register the callback function for when a connection is established
      ws:on("connection",
         function(ws_connect)         
            message = "Websocket message number "..message_counter
            print("Tx:"..message_counter)         
            message_counter = message_counter + 1
            ws:send(message)

            -- Set up a timer to shut down the websocket connection
            --if not tmr.create():alarm(500, tmr.ALARM_SINGLE, function()
               --print('Websocket test done - closing the connection')   
               --if (ws ~= nil) then
                  --ws:close()
               --end           
            --end)
            --then
               --print("Timer already exists - shouldn't happen")
            --end         
           
            -- Stop the timer that calls send_websocket_message after a specified number of messages
            if message_counter > 30 then
               message_timer:stop()
               message_timer:unregister()
            end           
         end)

      -- Register the callback function for when the websocket is closed
      ws:on("close",
         function(ws_close, status)
            print('Ws closed, code:', status)
            ws = nil
         end)           

      -- Register the callback function for when data is received
      ws:on("receive",
         function(ws_receive, msg, opcode)
            print('Rx:', msg)
            ws:close()
         end)
         
      -- Issue the websocket connect command
      ws:connect('ws://ADDRESS_REMOVED')     
   else
      print("websocket not available")
   end
end

-- Start a timer that will call send_websocket_message at the specified number of milliseconds
message_timer:register(5000, tmr.ALARM_AUTO, send_websocket_message)
message_timer:start()


Here is the code with the callbacks moved out - this code doesn't work at all, but I don't know why
Code: Select all-- This file creates websocket connection, sends a test message, closes the connection, and then repeats

print("Running websocket2.lua")
local message_timer = tmr.create()  -- Timer used to periodically open the socket and send a message
local message_counter = 1           -- Counter variable for test messages
local ws = nil                      -- Websocket handle
   
function ws_connect()         
   message = "Websocket message number "..message_counter
   print("Tx:"..message_counter)         
   message_counter = message_counter + 1
   if (ws ~= nil) then
      ws:send(message)
   end

   -- Set up a timer to shut down the websocket connection
   --if not tmr.create():alarm(500, tmr.ALARM_SINGLE, function()
      --print('Websocket test done - closing the connection')   
      --if (ws ~= nil) then
         --ws:close()
      --end           
   --end)
   --then
      --print("Timer already exists - shouldn't happen")
   --end         

   -- Stop the timer that calls send_websocket_message after a specified number of messages
   if message_counter > 30 then
      message_timer:stop()
      message_timer:unregister()
   end           
   end   

function ws_close(status)
   print('Ws closed, code:', status)
   ws = nil
end         

function ws_receive(msg, opcode)
   print('Rx:', msg)
   if (ws ~= nil) then
      ws:close()
   end
end
   
-- In this test, the following function just establishes the connection and the send happens in the "on connection" method
function send_websocket_message()

   print("Pre-collect heap available:" .. node.heap()) 
   collectgarbage("collect")
   print("Post-collect heap available:" .. node.heap()) 
   if ws == nil then
      ws = websocket.createClient()         
     
      -- Register the callback function for when a connection is established
      ws:on("connection", ws_connect())

      -- Register the callback function for when the websocket is closed
      ws:on("close", ws_close(status))           

      -- Register the callback function for when data is received
      ws:on("receive", ws_receive(msg, opcode))
         
      -- Issue the websocket connect command
      ws:connect('ws://ADDRESS_REMOVED')     
   else
      print("websocket not available")
   end
end

-- Start a timer that will call send_websocket_message at the specified number of milliseconds
message_timer:register(5000, tmr.ALARM_AUTO, send_websocket_message)
message_timer:start()