The telephone and Internet providers are promising high availability. At least when they compete for you as a customer. The reality then often looks like that it happens frequently that you are offline at home. OK, I admit that it was worse in the past. In the meantime it has become better, but I wanted to find out how accurate my Internet is actually available at home. Or in other words, how often it fails.
While I was looking for a way to easily monitor my WiFi network, I came across two key links:
ESP8266 Internet Alarm is a project of 3zuli. It basically describes exactly what I want, except that I want to store the data on the internet so that I can see from anywhere if my network at home is online or not. There are many IOT platform services on the Internet, but Circus of Thing has caught my attention. It is a pleasantly simple and well-structured service that Jaume Miralles has created.
What it doesThe concept is very simple: an ESP32 or ESP8266 is connected to my WiFi network at home. Every minute the device queries data from a server on the Internet. It measures the time it takes to make 10 requests. Based on this, a kind of "speed" can be calculated as "requests per second". This value is sent to the server of Circus of Things, so I can view the data from anywhere at any time:
The example graph shows how my network performance drops when I upload large amounts of data to a server. So the measured value can indeed be used as an indication of my network performance. But also failures of my internet connection can be easily detected:
The data looks a bit confusing as they are so noisy, but that is due to the pragmatic measurement method. If I would transfer larger amounts of data, I would get more stable readings. But then I would also generate a completely unnecessary high traffic. To see what I want to see, the measured values are completely sufficient.
How it worksThe first step is to establish a connection to my WiFi network. It has been shown that the ESP chip sometimes needs several attempts before it works. Therefore it is tried several times, but without blocking the whole processor completely.
The LED on the development board is used to indicate the status of the program flow:
- OFF with short ON-blinks every second: Idle loop = waiting one minute
- ON with short OFF-blinks: Performing speed test
- permanently ON: Writing data to circusofthings.com
The idle loop is implemented in a very easy way:
The counter variable "minute_count" is used to jump every minute into the "speed test and upload part" of the code:
If the device is connected to the WiFi, the speed test is performed by getting 10 times values from the Server http://httpbin.org/ by calling the function server_get():
http://httpbin.org/ is a simple HTTP Request & Response Service or in other words: A simple site meant for testing of HTTP applications. A good reason to use httpbin.org instead of loading a Google search site is that it returns a very small amount of data (typically under 200 bytes). The code is not too complicated:
// =============================================================
// server_get()
// Call a GET request to httpbin.org.
// Wait until a response is available but the response itself is ignored
// return values is the number of milliseconds until a response was available
// =============================================================
int server_get(){
// Use WiFiClient class to create TCP connection
WiFiClient client;
// use httpbin.org to test the connection
// httpbin returns a very small amount of data and is highly reliable
const char* test_hostname = "httpbin.org";
const int httpPort = 80;
// Attempt to connect to httpbin.org:80 (http)
if (!client.connect(test_hostname, httpPort)) {
// If we can't connect, we obviously don't have internet
Serial.println("[ERR] GET-Server Connection failed!!!");
return 0;
} else {
String url = "/get";
// We need to manually create the HTTP GET message
// client.print() will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + test_hostname + "\r\n" +
"Connection: close\r\n\r\n");
// Wait until a response is available
// Wait up to 5 seconds for server to respond
// then skip waiting
int n_trials = 500;
while((!client.available()) && (n_trials > 0)){
n_trials--;
delay(10);
}
// we only need the time until the response is available
// therefore, we skip reading the response.
// for referece, this would be the code if one need the data:
/*
// Read all the lines of the reply from server and print them to Serial
int n_lines = 0;
while(client.available()){
String line = client.readStringUntil('\r');
n_lines++;
//Serial.print(line);
}
Serial.printf("[OK] %i lines received\n",n_lines);
*/
// return the milliseconds until a response was available
return n_trials*10;
}
}
Now the measured value simply has to be transmitted to the server of Circus-of-Things. To do this, you first have to create a user account on the server:
Then you can find in your account data, or at the "REST API" Link at the development section, the token you need for access:
Now all that remains to be done is to create a signal that records the measured values:
Jaume created some videos about how to set up signals and the dashboard. He also created some libraries for several IOT platforms and devices. To make the upload work best in my code, I wrote a small custom function that connects to, and uploads the measured value to the Circus Server:
// =============================================================
// Circus_write(const char* Circus_key, double value)
// send value to circusofthings.com website
// the hostname and token need to be configured globally
// the key is the id of the signal, the values should be added to
// The function returns the number of received lines
// =============================================================
int Circus_write(const char* Circus_key, double value) {
// Use WiFiClientSecure class to create TCP connection
WiFiClientSecure client;
const int httpsPort = 443;
if(verbose_output)
Serial.printf("--> connect to: %s:%i\r\n",Circus_hostname,httpsPort);
int n_lines = 0;
// check the connection
if (!client.connect(Circus_hostname, httpsPort)) {
Serial.println("[ERR] Circus Connection failed!!!");
return 0;
} else {
// convert the value into a char-Array
char value_char[15];
dtostrf(value,1,4,value_char);
// create the URI for the request
char url_char[250];
sprintf_P(url_char, PSTR("/WriteValue?Key=%s&Value=%s&Token=%s\r\n"), Circus_key, value_char, Circus_token);
String url_str = url_char;
if(verbose_output) {
Serial.print("Requesting URL: ");
Serial.println(Circus_hostname+url_str);
}
// We need to manually create the HTTP GET message
// client.print() will send the request to the server
client.print(String("GET ") + url_str + " HTTP/1.1\r\n" +
"Host: " + Circus_hostname + "\r\n" +
"Connection: close\r\n\r\n");
// Wait until a response is available
// But only a number of times
// Wait up to 5 seconds for server to respond
// then skip waiting
int n_trials = 500;
while(!client.available() && n_trials > 0){
n_trials--;
delay(10);
}
// Read all the lines of the reply from server
// force timeout to 1000ms (ESP8266 = 5000ms default value)
client.setTimeout(1000);
while(client.available()){
String line = client.readStringUntil('\r');
n_lines++;
if(verbose_output) Serial.print(line);
}
if(verbose_output) Serial.printf("\n[OK] %i lines received\n",n_lines);
}
return n_lines;
}
And that's it. Now I can always see if my home is online or offline!
One more remark: I started the project at the end of 2018. Since then the Netspeed Monitor is running at my home and records the performance. Just as a side note: Since the beginning of 2020 I have a new and faster access ;-) You will know why...
FeedbackI hope this code can prove to be useful to the wider community. Feel free to message me here if you have questions or comments.
Enjoy!
Regards,
Hans-Günther
Comments