Skip to content

Check internet availability #137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/compile-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- name: Blues Wireless Notecard
SKETCH_PATHS: |
- examples/ConnectionHandlerDemo
- examples/CheckInternetAvailabilityDemo
ARDUINOCORE_MBED_STAGING_PATH: extras/ArduinoCore-mbed
ARDUINOCORE_API_STAGING_PATH: extras/ArduinoCore-API
SKETCHES_REPORTS_PATH: sketches-reports
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/* SECRET_ fields are in `arduino_secrets.h` (included below)
*
* If using a WiFi board (Arduino MKR1000, MKR WiFi 1010, Nano 33 IoT, UNO
* WiFi Rev 2 or ESP8266/32), create a WiFiConnectionHandler object by adding
* Network Name (SECRET_WIFI_SSID) and password (SECRET_WIFI_PASS) in the
* arduino_secrets.h file (or Secrets tab in Create Web Editor).
*
* WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS);
*
* If using a MKR GSM 1400 or other GSM boards supporting the same API you'll
* need a GSMConnectionHandler object as follows
*
* GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
*
* If using a MKR NB1500 you'll need a NBConnectionHandler object as follows
*
* NBConnectionHandler conMan(SECRET_PIN);
*
* If using a Portenta + Ethernet shield you'll need a EthernetConnectionHandler object as follows:
*
* DHCP mode
* EthernetConnectionHandler conMan;
*
* Manual configuration
* EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK);
*
* Manual configuration will fallback on DHCP mode if SECRET_IP is invalid or equal to INADDR_NONE.
*
* This sketch enables the ConnectionHandler to check for internet availability (only for IP based connectivity)
* before reporting the Connected state. By default the check is disabled.
*
*/

#include <Arduino_ConnectionHandler.h>

#include "arduino_secrets.h"

#define CONN_TOGGLE_MS 60000

#if !(defined(BOARD_HAS_WIFI) || defined(BOARD_HAS_GSM) || defined(BOARD_HAS_LORA) || \
defined(BOARD_HAS_NB) || defined(BOARD_HAS_ETHERNET) || defined(BOARD_HAS_CATM1_NBIOT))
#error "Please check Arduino Connection Handler supported boards list: https://github.com/arduino-libraries/Arduino_ConnectionHandler/blob/master/README.md"
#endif

#if defined(BOARD_HAS_ETHERNET)
EthernetConnectionHandler conMan(SECRET_IP, SECRET_DNS, SECRET_GATEWAY, SECRET_NETMASK);
#elif defined(BOARD_HAS_WIFI)
WiFiConnectionHandler conMan(SECRET_WIFI_SSID, SECRET_WIFI_PASS);
#elif defined(BOARD_HAS_GSM)
GSMConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
#elif defined(BOARD_HAS_NB)
NBConnectionHandler conMan(SECRET_PIN);
#elif defined(BOARD_HAS_LORA)
LoRaConnectionHandler conMan(SECRET_APP_EUI, SECRET_APP_KEY);
#elif defined(BOARD_HAS_CATM1_NBIOT)
CatM1ConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
#elif defined(BOARD_HAS_CELLULAR)
CellularConnectionHandler conMan(SECRET_PIN, SECRET_APN, SECRET_GSM_USER, SECRET_GSM_PASS);
#endif

bool attemptConnect = false;
uint32_t lastConnToggleMs = 0;

void setup() {
/* Initialize serial debug port and wait up to 5 seconds for port to open */
Serial.begin(9600);
for(unsigned long const serialBeginTime = millis(); !Serial && (millis() - serialBeginTime <= 5000); ) { }

#ifndef __AVR__
/* Set the debug message level:
* - DBG_ERROR: Only show error messages
* - DBG_WARNING: Show warning and error messages
* - DBG_INFO: Show info, warning, and error messages
* - DBG_DEBUG: Show debug, info, warning, and error messages
* - DBG_VERBOSE: Show all messages
*/
setDebugMessageLevel(DBG_INFO);
#endif
/* Enable the connection handler to check for internet availability.
* By default is disabled.
*/
conMan.enableCheckInternetAvailability(true);
/* Add callbacks to the ConnectionHandler object to get notified of network
* connection events. */
conMan.addCallback(NetworkConnectionEvent::CONNECTED, onNetworkConnect);
conMan.addCallback(NetworkConnectionEvent::DISCONNECTED, onNetworkDisconnect);
conMan.addCallback(NetworkConnectionEvent::ERROR, onNetworkError);

Serial.print("Network Adapter Interface: ");
switch (conMan.getInterface()) {
case NetworkAdapter::WIFI:
Serial.println("Wi-Fi");
break;
case NetworkAdapter::ETHERNET:
Serial.println("Ethernet");
break;
case NetworkAdapter::NB:
Serial.println("Narrowband");
break;
case NetworkAdapter::GSM:
Serial.println("GSM");
break;
case NetworkAdapter::LORA:
Serial.println("LoRa");
break;
case NetworkAdapter::CATM1:
Serial.println("Category M1");
break;
case NetworkAdapter::CELL:
Serial.println("Cellular");
break;
default:
Serial.println("Unknown");
break;
}
}

void loop() {
/* Toggle the connection every `CONN_TOGGLE_MS` milliseconds */
if ((millis() - lastConnToggleMs) > CONN_TOGGLE_MS) {
Serial.println("Toggling connection...");
if (attemptConnect) {
conMan.connect();
} else {
conMan.disconnect();
}
attemptConnect = !attemptConnect;
lastConnToggleMs = millis();
}

/* The following code keeps on running connection workflows on our
* ConnectionHandler object, hence allowing reconnection in case of failure
* and notification of connect/disconnect event if enabled (see
* addConnectCallback/addDisconnectCallback) NOTE: any use of delay() within
* the loop or methods called from it will delay the execution of .update(),
* which might not guarantee the correct functioning of the ConnectionHandler
* object.
*/
conMan.check();
}

void onNetworkConnect() {
Serial.println(">>>> CONNECTED to network");
}

void onNetworkDisconnect() {
Serial.println(">>>> DISCONNECTED from network");
}

void onNetworkError() {
Serial.println(">>>> ERROR");
}
19 changes: 19 additions & 0 deletions examples/CheckInternetAvailabilityDemo/arduino_secrets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Required for WiFiConnectionHandler
const char SECRET_WIFI_SSID[] = "NETWORK NAME";
const char SECRET_WIFI_PASS[] = "NETWORK PASSWORD";

// Required for GSMConnectionHandler
const char SECRET_APN[] = "MOBILE PROVIDER APN ADDRESS";
const char SECRET_PIN[] = "0000"; // Required for NBConnectionHandler
const char SECRET_GSM_USER[] = "GSM USERNAME";
const char SECRET_GSM_PASS[] = "GSM PASSWORD";

// Required for LoRaConnectionHandler
const char SECRET_APP_EUI[] = "APP_EUI";
const char SECRET_APP_KEY[] = "APP_KEY";

// Required for EthernetConnectionHandler (without DHCP mode)
const char SECRET_IP[] = "IP ADDRESS";
const char SECRET_DNS[] = "DNS ADDRESS";
const char SECRET_GATEWAY[] = "GATEWAY ADDRESS";
const char SECRET_NETMASK[] = "NETWORK MASK";
33 changes: 27 additions & 6 deletions src/CatM1ConnectionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,7 @@ NetworkConnectionState CatM1ConnectionHandler::update_handleInit()
pinMode(ON_MKR2, OUTPUT);
digitalWrite(ON_MKR2, HIGH);
#endif
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState CatM1ConnectionHandler::update_handleConnecting()
{
if(!GSM.begin(
_settings.catm1.pin,
_settings.catm1.apn,
Expand All @@ -80,8 +76,33 @@ NetworkConnectionState CatM1ConnectionHandler::update_handleConnecting()
Debug.print(DBG_ERROR, F("The board was not able to register to the network..."));
return NetworkConnectionState::ERROR;
}
Debug.print(DBG_INFO, F("Connected to Network"));
return NetworkConnectionState::CONNECTED;
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState CatM1ConnectionHandler::update_handleConnecting()
{
if (!GSM.isConnected())
{
return NetworkConnectionState::INIT;
}

if(!_check_internet_availability){
return NetworkConnectionState::CONNECTED;
}

int ping_result = GSM.ping("time.arduino.cc");
Debug.print(DBG_INFO, F("GSM.ping(): %d"), ping_result);
if (ping_result < 0)
{
Debug.print(DBG_ERROR, F("Internet check failed"));
Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast<unsigned int>(NetworkConnectionState::CONNECTING)]);
return NetworkConnectionState::CONNECTING;
}
else
{
Debug.print(DBG_INFO, F("Connected to Internet"));
return NetworkConnectionState::CONNECTED;
}
}

NetworkConnectionState CatM1ConnectionHandler::update_handleConnected()
Expand Down
23 changes: 19 additions & 4 deletions src/CellularConnectionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,31 @@ NetworkConnectionState CellularConnectionHandler::update_handleInit()
Debug.print(DBG_ERROR, F("SIM not present or wrong PIN"));
return NetworkConnectionState::ERROR;
}
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState CellularConnectionHandler::update_handleConnecting()
{
if (!_cellular.connect(String(_settings.cell.apn), String(_settings.cell.login), String(_settings.cell.pass))) {
Debug.print(DBG_ERROR, F("The board was not able to register to the network..."));
return NetworkConnectionState::ERROR;
}
Debug.print(DBG_INFO, F("Connected to Network"));
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState CellularConnectionHandler::update_handleConnecting()
{
if (!_cellular.isConnectedToInternet()) {
return NetworkConnectionState::INIT;
}

if (!_check_internet_availability) {
return NetworkConnectionState::CONNECTED;
}

if(getTime() == 0){
Debug.print(DBG_ERROR, F("Internet check failed"));
Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast<unsigned int>(NetworkConnectionState::CONNECTING)]);
return NetworkConnectionState::CONNECTING;
}

return NetworkConnectionState::CONNECTED;
}

Expand Down
6 changes: 3 additions & 3 deletions src/ConnectionHandlerDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ enum class NetworkAdapter {

static unsigned int const CHECK_INTERVAL_TABLE[] =
{
/* INIT */ 100,
#if defined(BOARD_HAS_NOTECARD) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
/* CONNECTING */ 4000,
/* INIT */ 4000,
#else
/* CONNECTING */ 500,
/* INIT */ 500,
#endif
/* CONNECTING */ 500,
/* CONNECTED */ 10000,
/* DISCONNECTING */ 100,
/* DISCONNECTED */ 1000,
Expand Down
1 change: 1 addition & 0 deletions src/ConnectionHandlerInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ConnectionHandler::ConnectionHandler(bool const keep_alive, NetworkAdapter inter
: _keep_alive{keep_alive}
, _interface{interface}
, _lastConnectionTickTime{millis()}
, _check_internet_availability{false}
, _current_net_connection_state{NetworkConnectionState::INIT}
{

Expand Down
4 changes: 4 additions & 0 deletions src/ConnectionHandlerInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class ConnectionHandler {

virtual void connect();
virtual void disconnect();
void enableCheckInternetAvailability(bool enable) {
_check_internet_availability = enable;
}

virtual void addCallback(NetworkConnectionEvent const event, OnNetworkEventCallback callback);
void addConnectCallback(OnNetworkEventCallback callback) __attribute__((deprecated));
Expand Down Expand Up @@ -106,6 +109,7 @@ class ConnectionHandler {
virtual void updateCallback(NetworkConnectionState next_net_connection_state);

bool _keep_alive;
bool _check_internet_availability;
NetworkAdapter _interface;

virtual NetworkConnectionState update_handleInit () = 0;
Expand Down
37 changes: 29 additions & 8 deletions src/EthernetConnectionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ NetworkConnectionState EthernetConnectionHandler::update_handleInit()
Debug.print(DBG_ERROR, F("Error, ethernet shield was not found."));
return NetworkConnectionState::ERROR;
}
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState EthernetConnectionHandler::update_handleConnecting()
{
IPAddress ip(_settings.eth.ip.type, _settings.eth.ip.bytes);

// An ip address is provided -> static ip configuration
Expand All @@ -91,7 +86,7 @@ NetworkConnectionState EthernetConnectionHandler::update_handleConnecting()
Debug.print(DBG_ERROR, F("Failed to configure Ethernet, check cable connection"));
Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d",
_settings.eth.timeout, _settings.eth.response_timeout);
return NetworkConnectionState::CONNECTING;
return NetworkConnectionState::INIT;
}
// An ip address is not provided -> dhcp configuration
} else {
Expand All @@ -100,11 +95,37 @@ NetworkConnectionState EthernetConnectionHandler::update_handleConnecting()
Debug.print(DBG_VERBOSE, "timeout: %d, response timeout: %d",
_settings.eth.timeout, _settings.eth.response_timeout);

return NetworkConnectionState::CONNECTING;
return NetworkConnectionState::INIT;
}
}

return NetworkConnectionState::CONNECTED;
return NetworkConnectionState::CONNECTING;
}

NetworkConnectionState EthernetConnectionHandler::update_handleConnecting()
{
if (Ethernet.linkStatus() == LinkOFF) {
return NetworkConnectionState::INIT;
}

if (!_check_internet_availability) {
return NetworkConnectionState::CONNECTED;
}

int ping_result = Ethernet.ping("time.arduino.cc");
Debug.print(DBG_INFO, F("Ethernet.ping(): %d"), ping_result);
if (ping_result < 0)
{
Debug.print(DBG_ERROR, F("Internet check failed"));
Debug.print(DBG_INFO, F("Retrying in \"%d\" milliseconds"), CHECK_INTERVAL_TABLE[static_cast<unsigned int>(NetworkConnectionState::CONNECTING)]);
return NetworkConnectionState::CONNECTING;
}
else
{
Debug.print(DBG_INFO, F("Connected to Internet"));
return NetworkConnectionState::CONNECTED;
}

}

NetworkConnectionState EthernetConnectionHandler::update_handleConnected()
Expand Down
6 changes: 6 additions & 0 deletions src/GSMConnectionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ GSMConnectionHandler::GSMConnectionHandler(const char * pin, const char * apn, c
: ConnectionHandler{keep_alive, NetworkAdapter::GSM}
{
_settings.type = NetworkAdapter::GSM;
// To keep the backward compatibility, the user can call enableCheckInternetAvailability(false) for disabling the check
_check_internet_availability = true;
strncpy(_settings.gsm.pin, pin, sizeof(_settings.gsm.pin)-1);
strncpy(_settings.gsm.apn, apn, sizeof(_settings.gsm.apn)-1);
strncpy(_settings.gsm.login, login, sizeof(_settings.gsm.login)-1);
Expand Down Expand Up @@ -105,6 +107,10 @@ NetworkConnectionState GSMConnectionHandler::update_handleInit()

NetworkConnectionState GSMConnectionHandler::update_handleConnecting()
{
if(!_check_internet_availability){
return NetworkConnectionState::CONNECTED;
}

Debug.print(DBG_INFO, F("Sending PING to outer space..."));
int const ping_result = _gprs.ping("time.arduino.cc");
Debug.print(DBG_INFO, F("GPRS.ping(): %d"), ping_result);
Expand Down
1 change: 1 addition & 0 deletions src/GenericConnectionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bool GenericConnectionHandler::updateSetting(const models::NetworkSetting& s) {
if(_ch != nullptr) {
_interface = s.type;
_ch->setKeepAlive(_keep_alive);
_ch->enableCheckInternetAvailability(_check_internet_availability);
return _ch->updateSetting(s);
} else {
_interface = NetworkAdapter::NONE;
Expand Down
Loading
Loading