How can I make the WifiClient.connect work in Arduino? - arduino

I would like to know if WifiClient.connect does not allow the locally running server to be connected (e.g. http://localhost:8080). I discovered that WifiClient.connect works when the url is anything public (e.g. www.google.com). Please help if there may be something I can programmatically change in order to connect the localhost server. The code below is a portion of setup().
status = WiFi.begin(ssid, pass);
// if you're not connected, stop here:
if ( status != WL_CONNECTED) {
Serial.println("Couldn't get a wifi connection");
while(true);
}
// if you are connected, print out info about the connection:
else {
Serial.println("Connected to network");
}
// configure the uri to be called
char apiURL[] = "127.0.0.1";
uint16_t port = 8080;
if (client.connect(apiURL, port)){
Serial.println("connected to " + String(apiURL));
// it always prints this statement
}else{
Serial.println("not calling " + String(apiURL));
}
One more (and maybe silly) thing I would like to ask: would Bluetooth be a better option than Wifi when I want my Arduino to send data to server (e.g. making POST request)?

Related

esp32 BLE client application - connect to device name

I've hacked apart the ESP32 BLE arduino sketches to do what I want. The server side is easy. Please see code below:
if (con == 0){
digitalWrite(LED, LOW);
}
if (con == 1){
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
}
if (deviceConnected) {
pCharacteristic->setValue((uint8_t*)&value, 4);
pCharacteristic->notify();
value++;
delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
con = 1;
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
con = 0;
}
This works exactly how I want. It simply sits idle doing nothing, when a device connects to the BLE server then it will flash an LED.
No problems there, even though I suspect my code isn't 'that pretty.
What i'm having trouble doing however is creating an ESP32 client to connect to the BLE device.
The client has the name set as
BLEDevice::init("BOX_A1");
The example code seems to want UID for both the service and characteristic. Is there any way to just connect to the short advertised name? No data is being shared, it's just simply acting as a beacon to identify a box when connected to.
Thanks
Andrew
You can't connect to a device using the advertised name, not directly at least.
If you want to use the advertised name you have to scan for all BLE devices around you and select the one matching your name. The BLE scan example shows you how this is done. The code scans for a scanTime of 5 seconds, waits 2 seconds and starts scanning again:
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
The example just prints the amount of found devices, you want to search through them and look for the correct name. The BLEScan returns an object of type BLEScanResults. You can access the found devices using getDevice with an index. Something like this might work to print the names of all found devices:
BLEAdvertisedDevice device;
for (int i = 0; i < foundDevices.getCount(); ++i) {
device = foundDevices.getDevice(i);
Serial.println(device.getName().c_str());
}
Now you can compare the names and work with the correct device.
To my understanding,
You want the client to connect to the server with given advertised name.
After connection is success, server turns on led.
You do have notification service running on server, but your client isn't interested.
Below is the client code which only connects to server with name "BOX_A1".
First Set our callback function that checks if device name matches when scanner discovers the devices:
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
void onResult(BLEAdvertisedDevice advertisedDevice)
{
if (advertisedDevice.getName() == "BOX_A1")
{
advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
foundDevice = new BLEAdvertisedDevice(advertisedDevice);
deviceFound = true;
Serial.print("Device found: ");
Serial.println(advertisedDevice.toString().c_str());
}
}
};
Use the BLEAdvertisedDevice object i.e. foundDevice object to connect to this server.
BLEClient* connectToServer(BLEAdvertisedDevice* device) {
BLEClient* pClient = BLEDevice::createClient();
if (pClient->connect(device)){ // Connect to the remote BLE Server.
Serial.println(" - Connected to server");
return pClient;
}
else{
Serial.println("Failed to Connect to device");
return NULL;
}
}
Use following line to call this connect function, it return the client object which can be used to disconnect from server.
if(deviceFound==true){
BLEClient* myDevice = connectToServer(device);
if(myDevice!=NULL){
Serial.print("Connected to the BLE Server: ");
Serial.println(device->getName().c_str());//print name of server
//DO SOME STUFF
//disconnect the device
myDevice->disconnect();
Serial.println("Device disconnected.");
}
}
This was the client side.
At server side to set the connection status flag use the following:
//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("Client Connected");
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
Serial.println("Client Disconnected");
deviceConnected = false;
}
};

Send data from ESP32 to Processing via wifi

I was trying to connect ESP32 (client)-Processing (server) and I think I made it work, but server doesn't receive or print anything. Why processing doesn't recognise when client is connected? I am new to Processing and trying to undrestand how it works.
Processing:
import processing.net.*;
Server myServer;
void setup() {
size(400, 400);
// Starts a myServer on port 5204
myServer = new Server(this, 5204);
println(Server.ip());
}
void serverEvent(Server someServer, Client someClient) {
println("We have a new client: " + someClient.ip());
}
ESP32:
#include <WiFi.h>
const char* ssid = "myNetwork";
const char* pass = "myPassword";
void setup()
{
Serial.begin(115200);
delay(10);
WiFi.begin(ssid,pass);
Serial.print("Connecting.");
while(WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("WiFi connected - IP address: ");
Serial.println(WiFi.localIP());
delay(500);
}
void loop()
{
const uint16_t port = 5204;
const char * host = "10.0.26.xx";
Serial.print("Connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
if (client.connect(host, port)){
Serial.println("Sending data"); // printed on serial monitor
client.print("Hello");
}
// This will send a request to the server
client.print("Send this data to the server");
Serial.println("Closing connection.");
client.stop();
}
EDITED
It gives the same prints even if I don't run the processing program. So is it connected somewhere else instead of the server?
At the processing I am getting only that "The value of parameter someServer is not used"
Well, I figured out. It was a firewall issue. I disable the firewall and then it worked. Also, before that I created a new rule for the Processing and the Port but for some reason it didn't work I don't undrestand why. Disabled it was the solution to my problem.
Your processing code is missing the part where you retrieve data from the client.
You need to add something like this:
void draw() {
// Get the next available client
Client thisClient = myServer.available();
// If the client is not null, and says something, display what it said
if (thisClient != null) {
String whatClientSaid = thisClient.readString();
if (whatClientSaid != null) {
println(thisClient.ip() + "t" + whatClientSaid);
}
}
}
Source
I don't see any other obvious issues but I cannot test something similar to your setup right now. Maybe you can give it a try.

Need help getting a SparkFun ESP8266 connecting to a URL

I've been trying to get a piece of code that sends a text message to a phone when an IFTTT applet site is visited, I've been following this tutorial regarding the text message itself and this one for the WiFi shield for the ability to connect to a webpage and an HTTP request.
Basically, my problem is that it will connect to any "simple" site like google.com but it can't for "longer/complex" links. I was wondering if you would have any idea how would I solve this problem and get this to work. I've tried just using the addition symbol to combine the "simple" link and the rest of my desired link but that doesn't work either.
#include <SoftwareSerial.h> // Include software serial library, ESP8266 library dependency
#include <SparkFunESP8266WiFi.h> // Include the ESP8266 AT library
void setup() {
Serial.begin(9600);
String url = "/trigger/ESP/with/key/dwSukgpyQsyampQMkXXXX";
Serial.print (url);
// put your setup code here, to run once:
if (esp8266.begin()) // Initialize the ESP8266 and check it's return status
Serial.println("ESP8266 ready to go!"); // Communication and setup successful
else
Serial.println("Unable to communicate with the ESP8266 :(");
int retVal;
retVal = esp8266.connect("network", "networkpassword");
if (retVal < 0)
{
Serial.print(F("Error connecting: "));
Serial.println(retVal);
}
IPAddress myIP = esp8266.localIP(); // Get the ESP8266's local IP
Serial.print(F("My IP is: ")); Serial.println(myIP);
ESP8266Client client; // Create a client object
retVal = client.connect("maker.ifttt.com" + url, 80); // Connect to sparkfun (HTTP port)
if (retVal > 0)
Serial.println("Successfully connected!");
client.print("GET / HTTP/1.1\nHost: maker.ifttt.com" + url + "\nConnection: close\n\n");
while (client.available()) // While there's data available
Serial.write(client.read()); // Read it and print to serial
}
void loop() {
// put your main code here, to run repeatedly:
}
Thanks, any help would be very much appreciated!
First, the connect function requires a server(name) to connect to. In your case: maker.ifttt.com. Anything after the .com will make the connection fail (because it's not a correct servername).
Second: this function needs an IP address (like 54.175.81.255) or an array of characters. You cannot concatenate.
After you've established the connection, you can send and receive data to a specific part of this website, using the print function.
Also, in this function you can't concatenate.
Luckily, there is a String class where we easily can concatenate.
So, after you've created the client object (ESP8266Client client;), this could be the code:
String url;
char host[] = "maker.ifttt.com";
retVal = client.connect(host, 80);
if (retVal > 0) {
Serial.println("Successfully connected!");
}
url = "GET / HTTP/1.1\r\nHost: ";
url += host;
url += "/trigger/ESP/with/key/dwSukgpyQsyampQMkXXXX";
url += "\nConnection: close\n\n";
client.print(url);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}

ESP32 WPS reconnect on power-on

I am trying to develop an IoT device that should provide some functionality using a HTTP/REST API. I decided to use the ESP32 chip (on "ESP32 dev board").
Now I want to implement an easy-to-use WLAN configuration. I don't want to store credentials in my source code like many other samples do; so I decided to use WPS.
I tried to implement a basic web server using the sources here:
https://randomnerdtutorials.com/esp32-web-server-arduino-ide/ - and then I added the WPS functionality from the Wifi/WPS samples shipped with the EPS32 extensions for Arduino IDE.
Now the WPS already works, i.e. when the dev-board gets powered it is in WPS connection mode and waits for the router to accept the WPS connection. It successfully gets the SSID and connects to the WLAN.
But when I power-off the ESP32, and power-on again, I have to do the WPS reconnection procedure again. I'd expect a reconnection, that stores the credentials and is able to connect to the same WLAN again when the ESP32 device is powered-on at any time later. I guess I have to store some credentials and use them to re-establish the connection - but where do I get the credentials, and how do I reconnect?
I did search the web for "ESP32 WLAN WPS reconnect" and similar terms, but did find only reconnect strategies for non-wps (SSID + password) connections. I did also check the WiFi library documentation and the esp_wps library documentation, but didn't find anything suitable.
That's the WLAN WPS connection source:
#include <WiFi.h>
#include "esp_wps.h"
#define ESP_WPS_MODE WPS_TYPE_PBC
esp_wps_config_t config = WPS_CONFIG_INIT_DEFAULT(ESP_WPS_MODE);
String wpspin2string(uint8_t a[]){
//...
}
void WiFiEvent(WiFiEvent_t event, system_event_info_t info){
switch(event){
case SYSTEM_EVENT_STA_START:
Serial.println("Station Mode Started");
break;
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("Connected to :" + String(WiFi.SSID()));
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("Disconnected from station, attempting reconnection");
WiFi.reconnect();
break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
Serial.println("WPS Successfull, stopping WPS and connecting to: " + String(WiFi.SSID()));
esp_wifi_wps_disable();
delay(10);
WiFi.begin();
break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED:
Serial.println("WPS Failed, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
Serial.println("WPS Timedout, retrying");
esp_wifi_wps_disable();
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
break;
case SYSTEM_EVENT_STA_WPS_ER_PIN:
Serial.println("WPS_PIN = " + wpspin2string(info.sta_er_pin.pin_code));
break;
default:
break;
}
}
// some GPIO stuff, removed for SO question
void setup() {
// initialize some GPIO for status etc. - removed for SO
//Initialize serial and wait for port to open:
Serial.begin(115200);
while(!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// We start by connecting to a WiFi network
WiFi.onEvent(WiFiEvent);
WiFi.mode(WIFI_MODE_STA);
Serial.println("Starting WPS");
esp_wifi_wps_enable(&config);
esp_wifi_wps_start(0);
// attempt to connect to Wifi network:
while(WiFi.status() != WL_CONNECTED) {
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
delay(700);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
//irrelevant for SO question
}
The ESP, both 32 and 8266, remember the last AP it was connected to. So simple call WiFi.begin(); without any credentials will make it connect to that last AP. Then in your while(WiFi.status() != WL_CONNECTED) loop you could make it timeout and then call the esp_wifi_wps_start(0); if it does not connect.
you can find the answer here https://www.esp32.com/viewtopic.php?f=19&t=27004
the SSID and password are stored in the config and given to esp_wifi_set_config, after WPS has finished, you can just use the getter function again by calling:
wifi_config_t config;
esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &config);
if (err == ESP_OK) {
printf("SSID: %s, PW: %s\n", (char*) config.sta.ssid, (char*) config.sta.password);
} else {
printf("Couldn't get config: %d\n", (int) err);
}
and you can then find the SSID and password in that struct again.

Configure WiFi on ESP8266 uing WIFI_AP_STA mode

I am trying to program my NodeMCU (Lolin v3) board in such a way that I can use it to configure the WiFi settings without having to hard code the credentials. I know there is a WiFiManager Library, but I don't intend to use that since I need to do my own implementation, not use the UI that the library provides. The credentials provided by the user are stored in a file using SPIFFS, used to check whether to start the board in AP_STA mode or STA mode only.
Below is the logic I use:
void connectWiFi(String ssid, String password, boolean staOnly = false) {
boolean state = true;
int i = 0;
if(staOnly)
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), password.c_str());
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if (i > 10) {
state = false;
break;
}
i++;
}
return state;
}
void join() {
String ssid = setupServer.arg("ssid");
String password = setupServer.arg("password");
result = connectWifi(ssid, password);
if(result) {
Serial.println("Connected");
// **THIS IS THE PROBLEMATIC PART**
setupServer.send(200, "text/plain", WiFi.localIP().toString());
// save credentials to a file
Serial.println("Conf saved");
delay(2000);
ESP.restart();
} else
setupServer.send(200, "text/plain", "fail");
}
void setup() {
Serial.begin(115200);
WiFi.disconnect(true);
boolean fileExists = SPIFFS.exists(WIFI_CONF_FILE);
if(!fileExists) {
WiFi.mode(WIFI_AP_STA);
WiFi.softAP("AP", "password");
IPAddress myIP = WiFi.softAPIP();
setupServer = ESP8266WebServer(myIP, 8888);
setupServer.on("/join", join);
setupServer.begin();
} else {
// read file contents for ssid and password
connectWifi(ssid, password, true);
// do some work here
}
}
void loop() {
setupServer.handleClient();
}
So now when I do a fresh boot, the board enters AP_STA mode and starts with SSID AP. I connect to it and open http://192.169.4.1/join?ssid=mywifi&password=12345678 in the browser. Somehow the connection gets terminated and I get "Destination Unreachable" in my browser. But the serial monitor prints 'Connected' and 'Conf saved'.
I want to know why it isn't returning the success response to the browser. I need the localIP after it has connected to the WiFi. It returns the failed response correctly in case it fails. How can I ensure it will always return the IP address assigned to it back to the client that connected to it before restarting?
Any help is appreciated.
Thanks!
Looks like it is bound to happen as radio module is shared between two modes.
Found the explaination for this issue here: https://github.com/esp8266/Arduino/issues/3282
This is related to the fact that STA will switch to the channel of the AP it is trying to connect to, and SoftAP will have to switch to the same channel. So the client (PC or smartphone connected to the SoftAP) will have to reconnect to the SoftAP on its new channel. In most cases this causes TCP connections to be reset.

Resources