Reputation: 669
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
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
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
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