I'm trying to assign the IP Address of the device to a String variable. When I use Serial.println(Ethernet.localIP()) to test it displays the IP Address in octets. If I use String(Ethernet.localIP()); then it displays it as a decimal.
Is there a way to assign the octet format to a variable?
String MyIpAddress;
void StartNetwork()
{
Print("Initializing Network");
if (Ethernet.begin(mac) == 0) {
while (1) {
Print("Failed to configure Ethernet using DHCP");
delay(10000);
}
}
Serial.println(Ethernet.localIP()); //displays: 192.168.80.134
MyIpAddress = String(Ethernet.localIP());
Serial.println(MyIpAddress); //displays: 2253433024
}
Turns out that the IPAddress property is an array. One simple way to display the IP address is as follows:
String DisplayAddress(IPAddress address)
{
return String(address[0]) + "." +
String(address[1]) + "." +
String(address[2]) + "." +
String(address[3]);
}
A more lightweight approach is this:
char* ip2CharArray(IPAddress ip) {
static char a[16];
sprintf(a, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
return a;
}
An IP address is, at maximum, 15 characters long, so a 16-character buffer suffices. Making it static ensures memory lifetime, so you can return it safely.
Another approach: the character buffer may be provided by the caller:
void ip2CharArray(IPAddress ip, char* buf) {
sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}
just use toString()
display.drawString(0, 30, WiFi.localIP().toString());
Related
I have an app that I am writing three strings to EEPROM. The strings are from when the user first starts the app. They are from "WiFiManager".
code
WiFiManager wifiManager;
WiFiManagerParameter customAPIKey("authorizationKey", "Authorization Code", authorizationKey, 32);
WiFiManagerParameter customAPIKey2("apiKey", "Time Zone #", apiKey, 32);
WiFiManagerParameter customAPIKey3("userNameKey", "User Name",userNameKey, 32);
wifiManager.addParameter(&customAPIKey);
wifiManager.addParameter(&customAPIKey2);
wifiManager.addParameter(&customAPIKey3);
wifiManager.autoConnect("FloWT3");
Serial.println("Connected");
strcpy(authorizationKey, customAPIKey.getValue());
strcpy(apiKey, customAPIKey2.getValue());
strcpy(userNameKey, customAPIKey3.getValue());
So this is when the app starts up if it can't connect to the internet it opens up a local access point "FloWT3" and the user fills in the local WiFi Name, Password, MQTT authorizationKey, Time Offset, and MQTT Username.
WiFi manager automatically stores the WiFi Name and Password and I store the other three in EEPROM with this code;
This is all in void setup()
Then in void loop()
WiFiManager wifiManager;
//if the wifi is not connected I open "FloWT3" access point again.
if (WiFi.status() == WL_DISCONNECTED) {
wifiManager.autoConnect("FloWT3");
delay(60000);}
//but if it is connected I access EEPROM and read what has been read.
else if (WiFi.status() == WL_CONNECTED) { Serial.println("Connected");
delay(2000);
WiFiClient client;
EEPROM.begin(512); //Initialize EEPROM
//This is where I moved the code to and added if statement.
String rrr = apiKey;
if (rrr.length()==0){
Serial.println("empty"):
}
else {
Serial,println("not empty");
//Write string to eeprom
String uuu = authorizationKey;
Serial.print("uuu");
Serial.print(uuu);
String www = apiKey;//Homenetwork + uuu;
Serial.print("www");
Serial.print(www);
String yyy = userNameKey;
String fff = String(www)+String(",");
String vvv = String(yyy)+String(",");
Serial.print("vvv");
Serial.print(vvv);
for(int i=0;i<uuu.length();i++) //loop upto string lenght www.length() returns length of string
{
EEPROM.write(0x0F+i,uuu[i]); //Write one by one with starting address of 0x0F
}
for(int i=0;i<fff.length();i++) //loop upto string lenght www.length() returns length of string
{
EEPROM.write(0x50+i,fff[i]); //Write one by one with starting address of 0x0F
}
for(int i=0;i<vvv.length();i++) //loop upto string lenght www.length() returns length of string
{
EEPROM.write(0x90+i,vvv[i]); //Write one by one with starting address of 0x0F
}
EEPROM.commit(); //Store data to EEPROM
}
delay (500);
String www;
//here I read the first part I wrote to address 0x0F which is the authorizationKey
for(int i=0;i<32;i++)
{
www = www + char(EEPROM.read(0x0F+i)); //Read one by one with starting address of 0x0F
}
//here is read from the address 0X50 which I wrote the apiKey (time offset)
String uuu;
for(int i=0;i<32;i++)
{uuu = uuu + char(EEPROM.read(0x50+i));
}
//here I read from address 0x090+i where I wrote the userNameKey
String vvv;
for(int i=0;i<32;i++)
{vvv = vvv + char(EEPROM.read(0x90+i));
}
Serial.println("this");
Serial.print(www);
Serial.println("that");
Serial.print(uuu);
Serial.println("those");
Serial.print(vvv);
When I program the ESP8266-01 the first time so the user has to fill in the info in the "FloWT3" access point these are the reading I get on the Serial Monitor
this
11:35:13.576 -> aio_XXXXXXXXXXXXXXXXXXXXXXXXXXXthat
11:35:13.576 -> -07,⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮those
11:35:13.576 -> XXXXXXX,⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮
This is as expected and everything works fine.
Now when I run the app and it connects with the stored information I get these reading which are the same
this
11:35:13.576 -> aio_XXXXXXXXXXXXXXXXXXXXXXXXXXXthat
11:35:13.576 -> -07,⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮those
11:35:13.576 -> XXXXXXX,⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮
I can now split out the parts I need using indexOf(",") and substrings. Everything is working very well.
I am thankful to hcheung for the suggestion and I will study up more on strcpy.
I found the reason for the replacement ,s. When the app open and ran it wrote a blank string to the beginning of the EEPROMs thus overriding the first character. So I moved the write part of the EEPROM into the if(WiFi.status() == WL_CONNECTED and also checked to see if the length of a String from the apiKey was equal to 0 or not. If it was 0 then the info was already stored in the EEPROM and didn't need to be written again. If it had a length then the app was being set up for the first time and writing to EEPROM needed to happen. I have changed my original post to reflect these changes.
I have a sketch that requests a device token from Facebook in order to authenticate a Wemos D1 Mini.
All in all, I want to reproduce the following, which gives me a device code in less than a second:
curl https://graph.facebook.com/v2.7/device/login -d
"type=device_code&access_token=MYTOKEN"
I set up the following sketch which works albeit very slowly. It fetches the device token in about 17 seconds.
It seems that String response = client.readString(); is the culprit.
Can any offer advice on why that could be, and how to possibly remedy it?
Thank you kindly,
Nate
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
WiFiClientSecure client; //edited
void setup() {
connect(WIFI_SSID, WIFI_PWD); //edited
Serial.println(getFBDeviceToken());
}
void connect(const char* WIFI_SSID, const char* WIFI_PWD) {
delay(1000);
WiFi.persistent(false);
delay(1000);
WiFi.mode(WIFI_STA);
if (WiFi.status() == WL_DISCONNECTED) {
WiFi.begin(WIFI_SSID, WIFI_PWD);
while(WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.println("connecting...");
}
Serial.println("\r\n"+WiFi.localIP());
}
}
String getFBDeviceToken(){
//Connect to FB SSL
if(!client.connect(host, httpPort)){
return "** Failed to connect **";
}
client.println("POST " + path + " HTTP/1.1");
client.println("Host: " + String(host));
client.println("User-Agent: ESP8266/1.0");
client.println("Connection: close");
client.println("Content-Type: application/x-www-form-urlencoded;");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.println(data);
String response = client.readString();
int bodypos = response.indexOf("\r\n\r\n") + 4;
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(response.substring(bodypos));
String device_token = root[String("user_code")];
return device_token;
}
I am not sure if this is still relevant for you but I faced the same situation and I believe I found a solution. If it is not relevant to you, perhaps it will help some other, especially given that the default WiFiClientSecure library will soon be switched to BearSSL and no support is currently being given for the existing implementation.
Although I did not manage to speed up readString function, I used the WiFiClientSecure::read(uint8_t *buf, size_t size) function to get the data from the server:
// Buffer size, 128 bytes in this case
#define RESP_BUFFER_LENGTH 128
// Pointer to actual buffer
uint8_t * _buffer = new uint8_t[RESP_BUFFER_LENGTH];
// String to hold the final response
String _responseString = "";
// If info is still available
while (wifiClient.available())
{
// Fill the buffer and make a note of the total read length
int actualLength = wifiClient.read(_buffer, RESP_BUFFER_LENGTH);
// If it fails for whatever reason
if(actualLength <= 0)
{
// Handle as you see fit
return -1;
}
// Concatenate the buffer content to the final response string
// I used an arduino String for convenience
// but you can use strcat or whatever you see fit
_responseString += String((char*)_buffer).substring(0, actualLength);
}
// Clear buffer memory
delete[] _buffer;
I don't know why the regular readString() is so slow, but this method is considerably faster, with my relatively small messages (~50 bytes) the response is being read almost instantly.
If look under hood, readString() always reads all data and when it reads the last symbol it stucks with server communication.
To avoid it you should not read last one symbol somehow.
I read headers by using readStringUntil('\n') and searching Content-Length header.
When headers has been read, just use readBytes with content-length.
HTTP request now took around 150ms.
I am working with a Ciseco srf module trying to send "+++" from an arduino nano. My code is
bool b =false;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.write('+');// Ihave tried Serial.write("+++")
Serial.write('+');// but this sends "+++<CR>" :(
Serial.write('+');
}
void loop() {
String content = "";
char character;
if(!b)
{
//Serial.print("sent");
b = true;
}
while(Serial.available()) {
character = Serial.read();
content.concat(character);
}
if (content != "") {
Serial.println(content);
}
}
The problem is Arduino seems to send a Carriage Return <CR> on Serial.write("+++") or other combination. Can someone help me turn off the Carriage Return on Arduino and be strict to program serial communication?
According to arduino manual http://www.arduino.cc/en/Serial/Write
use serial.write(0x2B) three times to send the '+' character to the SRF module.
or you can fill a buffer with those 3 characters and send them with serial.write(buffer,len).
I have a problem in accessing received udp string, I can get it by serial though. I just need to get my incoming udp data into a variable using the ethercard library in loop() function so I can use them in my program.Here's the code I'm working with:
#include <EtherCard.h>
#include <IPAddress.h>
#define STATIC 1 // set to 1 to disable DHCP (adjust myip/gwip values below)
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,200 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
//callback that prints received packets to the serial port
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {
Serial.println(data);
}
void setup(){
Serial.begin(57600);
Serial.println("\n[backSoon]");
if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)
Serial.println( "Failed to access Ethernet controller");
#if STATIC
ether.staticSetup(myip, gwip);
#else
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
//register udpSerialPrint() to port 1337
ether.udpServerListenOnPort(&udpSerialPrint, 1337);
//register udpSerialPrint() to port 42.
ether.udpServerListenOnPort(&udpSerialPrint, 42);
}
void loop(){
//this must be called for ethercard functions to work.
ether.packetLoop(ether.packetReceive());
//? incoming = data; <--- this is my problem
//Serial.println(incoming);
}
It's just a slightly modified version of the UDPListener example that comes with the ethercard library.
Thank you
I'm still on a steep learning curve myself but have managed to get UDP talking between units so hope following helps. Suspect the quickest way would be to create a global variable such as:
char gUDPdata[30] = "";
then in your udpSerialPrint routine add the following for a quick and dirty result. This copies 'data' to a global variable that you can see in your main loop.
Serial.println(data);
data[0] = 0;
strcpy(data, gUDPdata);
then in your main loop following should produce same as Serial.print in the udpSerialPrint routine.
Serial.println(gUDPdata);
On my mac, I did a command line
ipconfig getifaddr en1
and it shows
10.0.0.2
However when I use the
struct ifaddrs *id;
int success=0;
success=getifaddrs(&id);
printf("Network Address of %s :- %d\n",id->ifa_name,id->ifa_addr);
it shows
Network Address of lo0 :- 8393376
So, how does the 10.0.0.2 relate to 8393376?
Seems like they don't match from the two ways of finding the IP address.
id->ifa_addr
Is some kind of struct sockaddr (e.g. a struct sockaddr_in), which contains the type of
the address (e.g. IPv4, IPv6, Ethernet MAC address, or similar), and the
binary representation of the address. It is not a string that you can print with printf's %s.
You might be able to use this:
void
print_sockaddr(struct sockaddr* addr,const char *name)
{
char addrbuf[128] ;
addrbuf[0] = 0;
if(addr->sa_family == AF_UNSPEC)
return;
switch(addr->sa_family) {
case AF_INET:
inet_ntop(addr->sa_family,&((struct sockaddr_in*)addr)->sin_addr,
addrbuf,sizeof(struct sockaddr_in));
break;
case AF_INET6:
inet_ntop(addr->sa_family, &((struct sockaddr_in6*)addr)->sin6_addr,
addrbuf,sizeof(struct sockaddr_in6));
break;
default:
sprintf(addrbuf,"Unknown family (%d)",(int)addr->sa_family);
break;
}
printf("%-16s %s\n",name,addrbuf);
}
...
print_sockaddr(id->ifa_addr,id->ifa_name);
getifaddrs returns a linked list of struct ifaddrs , representing each interface.
You'll need to do:
struct ifaddrs *addrs,*tmp;
if(getifaddrs(&addrs) != 0) {
perror("getifaddrs");
return 1;
}
for(tmp = addrs; tmp ; tmp = tmp->ifa_next) {
print_sockaddr(tmp->ifa_addr, tmp->ifa_name);
}
freeifaddrs(addrs);
Dude, to print the IP you need do this:
struct sockaddr_in * ip;
ip = (struct sockaddr_in *) id->ifa_addr;
if (ip->sin_family == AF_INET)
printf("Network Address: %s\n",inet_ntoa(ip->sin_addr));
try do this.