Czarek
Czarek

Reputation: 669

Android & NodeMCU, receiving response from server does not work properly?

I have written an application on Android which realises sending simply requests (using Volley) to the server. The server is stood up on the NodeMCU (ESP8266) microcontroller, written in Lua. The problem is, that after sending the request, application not always is able to print the response. If the address is e.g. "http://www.google.com" it correctly sends request and receive and display response, but if it is the address from the code below - it correctly sends request (the server reacts) but does not (?) receive response (does not display it, displays: "That didn't work!"). Do you have any ideas, how can I fix it and be able to print the response?

Android (part responsible for sending requests):

buttonSynchro.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {


        // Instantiate the RequestQueue.
        String url = "http://192.168.1.12/";


        // Request a string response from the provided URL.
        StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        // Display the first 500 characters of the response string.
                        testTextView.setText("Response is: "+ response.substring(0,500));
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                testTextView.setText("That didn't work!");
            }
        });


        // Add the request to the RequestQueue.
        RequestQueue queue = Volley.newRequestQueue(SettingsActivity.this);
        queue.add(stringRequest);
    }
});  

NodeMCU, Lua:

station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)
function receive(conn, request)
        print(request)
        print()
        local buf = "";
        buf = buf.."<!doctype html><html>";
        buf = buf.."<h1> ESP8266 Web Server</h1>";
        buf = buf.."</html>";

        conn:send(buf);
        conn:on("sent", function(sck) sck:close() end);     
        collectgarbage();

end

function connection(conn) 
    conn:on("receive", receive) 

end

srv=net.createServer(net.TCP, 30) 
srv:listen(80, connection)

Upvotes: 0

Views: 790

Answers (3)

nPn
nPn

Reputation: 16728

Based on your comment above and the link you posted showing the traceback, your android app is crashing in the onResponse() method because you are asking for a substring longer than the actual string length.

You can fix this in a number of ways, but one would be to make the ending index be the minimum of the length of the response and 500 (which I assume is the max you can take in your TextView?). You can try changing

testTextView.setText("Response is: "+ response.substring(0,500));

to

testTextView.setText("Response is: "+ response.substring(0, Math.min(response.length(), n)));

or whatever other way you think is more appropriate to limit the length of the response that does not cause the IndexOutOfBoundsException

See the substring method here

public String substring(int beginIndex, int endIndex)

Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.

Examples:

 "hamburger".substring(4, 8) returns "urge"
 "smiles".substring(1, 5) returns "mile"

Parameters: beginIndex - the beginning index, inclusive. endIndex - the ending index, exclusive. Returns: the specified substring. Throws: IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or beginIndex is larger than endIndex.

Upvotes: 1

Marcel St&#246;r
Marcel St&#246;r

Reputation: 23535

The code by nPn works in some user agents (Chrome/Firfox/curl/wget on macOS) but not in others (Safari on macOS & iOS, Firefox Klar on iOS). That likely is due to missing HTTP headers.

I advise you stick to the example we have in our documentation at https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend.

srv = net.createServer(net.TCP)

function receiver(sck, data)
  print(data)
  print()

  -- if you're sending back HTML over HTTP you'll want something like this instead
  local response = {"HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n"}

  response[#response + 1] = "<!doctype html><html>"
  response[#response + 1] = "<h1> ESP8266 Web Server</h1>"
  response[#response + 1] = "</html>"

  -- sends and removes the first element from the 'response' table
  local function send(localSocket)
    if #response > 0 then
      localSocket:send(table.remove(response, 1))
    else
      localSocket:close()
      response = nil
    end
  end

  -- triggers the send() function again once the first chunk of data was sent
  sck:on("sent", send)

  send(sck)
end

srv:listen(80, function(conn)
  conn:on("receive", receiver)
end)

Also, your code (and nPn's for that matter) makes assumptions about WiFi being available where it shouldn't.

wifi.sta.config(station_cfg) (with auto-connect=true) and wifi.stat.connect are asynchronous and thus non-blocking - as are many other NodeMCU APIs. Hence, you should put the above code into a function and only call it once the device is connected to the AP and got an IP. You do that by e.g. registering a callback for the STA_GOT_IP event with the WiFi event monitor. You'll find a very elaborate example of a boot sequence that listens to all WiFi events at https://nodemcu.readthedocs.io/en/latest/en/upload/#initlua. For starters you may want to trim this and only listen for got-IP.

Upvotes: 2

nPn
nPn

Reputation: 16728

I am not a Lua expert, but I think you are registering your "sent" callback after you send the response.

I think you should move it into the connection function:

station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)
function receive(conn, request)
        print(request)
        print()
        local buf = "";
        buf = buf.."<!doctype html><html>";
        buf = buf.."<h1> ESP8266 Web Server</h1>";
        buf = buf.."</html>";
        conn:send(buf);  
        collectgarbage();

end

function connection(conn) 
    conn:on("receive", receive) 
    conn:on("sent", function(sck) sck:close() end);   
end

srv=net.createServer(net.TCP, 30) 
srv:listen(80, connection)

Upvotes: 0

Related Questions