0

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)
Czarek
  • 689
  • 9
  • 20
  • please check http://192.168.1.12/ is working in your browser. :-) – Rahul Mar 09 '18 at 23:01
  • Yes, of course it works. I thought I have already said that :) – Czarek Mar 10 '18 at 00:58
  • btw, You did _not_ say it worked in a browser, you said the server "reacted", I would assume that means you saw the request printed on the esp. – nPn Mar 10 '18 at 16:54
  • @nPn Yes, I have not said it directly. So to make it clear: after sending request I see the request printed on the esp and after sending request via browser I see page made with HTML code showed above. – Czarek Mar 10 '18 at 17:49

3 Answers3

2

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.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • I would like to add, that these does not work (for me) with Volley method of sending requests. But it works with sending requests method available here https://stackoverflow.com/questions/44377993/make-simply-http-request-and-receive-the-content Lua code from my question here does not work for both methods. Thank you. – Czarek Mar 11 '18 at 10:02
  • What? I'm confused...You accepted the answer even though it does not work for you? The Lua code _does_ work, guaranteed. I tested with all seven user agents I mentioned in the answer. – Marcel Stör Mar 11 '18 at 11:31
  • We have not undersood each other. Your Lua code work. Volley's method of sending request does not work (for me) (I am unable to print the response). Method of sending requests mentioned in the link I have posted in my last comment works correctly with your Lua code. In my last comment, I have not meant that your Lua code does not work. Maybe I should start: "Volley's method of sending requests does not work (for me) with these". – Czarek Mar 11 '18 at 13:25
  • It also might be helpful to print out the error that Volley is returning. – nPn Mar 11 '18 at 13:44
  • I am not able to insert plain text here, so I will give a link. Application sends request (server reacts) but then it stops working. https://ibb.co/fUoRCn – Czarek Mar 11 '18 at 14:11
  • 1
    Your problem is IndexOutOfBoundsException shown in your java traceback. You are asking for the substring 0 - 500, but the response is only 483 characters. I will post a simple answer. – nPn Mar 13 '18 at 21:40
1

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.

nPn
  • 16,254
  • 9
  • 35
  • 58
  • Yes, this solved Volley issue. I took this example 1:1 from documentation on https://developer.android.com and I have not thought that it may not work in this, simple case. – Czarek Mar 14 '18 at 11:03
0

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)
nPn
  • 16,254
  • 9
  • 35
  • 58
  • Thank you for your willingness to help, but it did not solved the issue. Now I see the request printed on the esp(server reacts) but I can not load page using browser. – Czarek Mar 10 '18 at 17:59
  • And of course I am unable to print the response in the Android application. – Czarek Mar 10 '18 at 18:06