Modificare le credenziali di accesso alla rete Wi-Fi via BLE 4.73/5 (10)

Ti piace questo articolo? Condividilo dove vuoi!

Sarà capitato a molti di scrivere uno sketch per Arduino in cui la scheda che stiamo programmando utilizza per accedere al mondo internet la connettività Wi-Fi, per far questo è sempre necessario inserire nel codice i valori stringa o array di caratteri che si riferiscono al nome della rete SSID a cui il dispositivo si dovrà connettere e la password per l’accesso (hard-coding).

Una volta programmata la scheda Arduino si connetterà in automatico alla rete Wi-Fi con le credenziali specificate nel codice ed eseguirà il programma contenuto nella funzione loop ().

Ma cosa succede se le credenziali della rete impostata cambiano o se spostiamo la board Arduino in una zona non servita dalla rete Wi-Fi impostata?

In questo caso dovremmo ricollegare fisicamente la scheda ad un PC con IDE Arduino, modificare lo sketch di partenza cambiando i valori SSID e password, compilare il tutto e programmare nuovamente la board con una discreta perdita di tempo!!!

In questo tutorial vedremo come semplificare questa procedura utilizzando la connessione Bluetooth Low Energy (BLE) che affianca quella Wi-Fi in molte schede della famiglia Arduino e in particolare ci concentreremo su come scrivere il programma per la scheda Arduino Nano 33 IOT, utilizzata per realizzare questa breve guida.

Prima di iniziare

Prima di iniziare la stesura di un programma è sempre bene porsi alcune domande sul come si vuole realizzare il progetto e a seguito delle risposte provare a descriverne l’implementazione mediante un banale ma non troppo diagramma di flusso, queste le domande a cui ho provato a dare una risposta:

Qual è il requisito principale del progetto?

La risposta alla prima domanda è piuttosto semplice, quello che vogliamo ottenere è riuscire a cambiare i parametri per il collegamento alla rete Wi-Fi senza essere costretti a ricompilare il codice sorgente, senza spostare la scheda dal punto di lavoro e soprattutto senza essere costretti a dover ri-collegare fisicamente la board ad un PC.

Come posso soddisfare il requisito del punto precedente?

Le strade in informatica possono essere molte, nel caso specifico l’idea alla base del progetto nasce da una discussione nata nel gruppo Telegram Bar Filo Connesso in cui è stato ipotizzato di utilizzare il collegamento BLE a disposizione nella Nano 33 IOT come mezzo per ricevere i parametri.

Quando e come attivare il collegamento BLE?

Considerando che nell’applicazione che vogliamo realizzare il BLE è uno strumento da utilizzare solo e esclusivamente quando abbiamo la necessità di riconfigurare la scheda, ho scelto di attivare il collegamento nella fase di reset della board in risposta alla pressione di un pulsante esterno, che chiameremo da ora in poi pulsante di recovery.

In quale supporto di memoria posso salvare i valori di configurazione della rete?

Di solito i parametri, modificabili dall’utente sono salvati in EEPROM, sfortunatamente la scheda che abbiamo deciso di utilizzare non dispone di questo tipo di memoria, pertanto l’unica possibilità che ci rimane è la memoria FLASH solitamente ad uso esclusivo del programma.

Con cosa posso caricare i valori di configurazione nella scheda Arduino?

Per collegarsi con la scheda e scaricare i nuovi valori in memoria ho scelto di realizzare una piccola APP Android in questo modo sarà sufficiente avvicinarsi con il proprio smartphone al dispositivo da configurare ed inviare le nuove credenziali di rete.

Come diagnosticare lo stato in cui si trova la scheda Arduino?

Per poter identificare se la scheda sta eseguendo il programma scritto nel loop, se è in ascolto o è connessa al client ho deciso di modificare la frequenza di lampeggio di un led che per comodità sarà il led on-board della Nano 33 IOT, la frequenza di lampeggio indicherà immediatamente all’utente in quale stato si trova la scheda.

Diagramma di flusso

Proviamo adesso a rappresentare graficamente gli algoritmi che vogliamo implementare all’interno del codice.

Breve introduzione al BLE

Introdotto a partire dalla versione 4.0 delle specifiche bluetooth il BLE può essere definito come uno standard di comunicazione radio a basso consumo energetico che permette di creare una rete personale wireless a corto raggio (WPAN).

Tralasciando le modalità di comunicazione broadcasting e observing fuori dal contesto di questo articolo, possiamo dire che i dispositivi che partecipano alla creazione della rete di comunicazione possono ricoprire due differenti ruoli:

  • Peripheral (slave): E’ un dispositivo, nel nostro caso l’Arduino Nano 33 IOT, che si rende visibile agli altri, solitamente a bassa potenza e con risorse hardware limitate, invia periodicamente pacchetti dati di tipo advertising per segnalare la propria presenza nella rete in attesa di accettare una richiesta di connessione dal dispositivo Central.
  • Central (master): E’ un dispositivo, nel nostro caso il telefono cellulare, in grado di effettuare una ricerca dei device visibili e di avviare una richiesta di connessione al dispositivo Peripheral. Stabilità la connessione sarà il master a gestire l’invio e/o ricezione dati.

Nel momento in cui il master si connette allo slave il processo di advertising si interrompe e si instaura un collegamento bidirezionale tra i due dispositivi, il protocollo di comunicazione utilizzato, denominato GATT (Generic Attribute Profile), permette al client (master) di richiedere informazioni al server (slave) riguardanti i dati offerti, denominati caratteristiche, che raggruppati insieme costituiscono il servizio offerto dal client.

Nel nostro caso per esempio il servizio che sarà offerto dal peripheral ovvero dalla board Arduino sarà quello di “Configurazione rete Wi-Fi” le caratteristiche che faranno parte di questo servizio saranno soltanto due, ovvero SSID e password.

Per comprendere al meglio le basi del funzionamento BLE è necessario ricordare come ogni servizio debba essere identificato da un ID numerico univoco chiamato UUID (universally unique identifier) che ha una lunghezza per i servizi personali, cioè definiti dal programmatore, di 128bit (16 byte).

Questo numero è formato da 32 caratteri esadecimali (4 bit per carattere) divisi in 5 gruppi separati dal trattino secondo lo schema 8-4-4-4-12, per generare l’UUID del servizio solitamente ci si affida ad un sito online, tipo:

https://www.uuidgenerator.net/

Una volta generato randomicamente l’ID di riferimento del servizio per ottenere gli identificativi delle caratteristiche che fanno parte di quel servizio è sufficiente incrementare di 1 unità il primo gruppo (8 caratteri) a sinistra dell’identificativo.

Collegamenti elettrici su breadboard

Il codice Arduino

Analizziamo adesso il programma Arduino dividendolo in più parti e commentando ciascun blocco di codice in modo da comprenderne il significato.

Le librerie

/*
  Scheda: Arduino Nano 33 IoT
  Autore: Vignolini Fabrizio
  Data: 21/05/2022
  Versione: 1.0
*/

#include <SPI.h> 
#include <WiFiNINA.h>
#include <ArduinoBLE.h>
#include <FlashStorage.h>

Le librerie che fanno parte del progetto sono:

SPI.h – Già inclusa nell’IDE Arduino,viene utilizzata per la gestione dell’interfaccia seriale SPI per la comunicazione tra il uP SAMD21 e il modulo NINA-W102 che si occupa di gestire stand-alone la connettività Wi-Fi e BLE.

WiFiNINA.h – Supporto per la connettività Wi-Fi, si installa dal gestore librerie nel menu strumenti dell’IDE.

ArduinoBLE.h – Supporto per la connettività BLE, si installa dal gestore librerie nel menu strumenti dell’IDE.

FlashStorage.h – Utilizzata per archiviare nella memoria flash i dati da salvare a run-time ovvero in esecuzione di programma. E’ necessario premettere che l’utilizzo di questo tipo di memoria, solitamente ad uso esclusivo del firmware, per operazioni di salvataggio dati è consigliata solo nel caso in cui non sia disponibile una EEPROM interna o esterna al microcontrollore questo perché la memoria FLASH ha, rispetto ad un EEPROM, un numero limitato di cicli di scrittura il cui superamento può portare ad un lento deterioramento della memoria stessa con conseguente perdita di capacità di conservare i dati. Nel nostro caso l’utilizzo della memoria Flash è sporadico e riservato solo ed esclusivamente all’aggiornamento delle credenziali per l’accesso alla rete Wi-Fi esterna, pertanto l’integrità della memoria non è a rischio. Si installa dal gestore librerie nel menu strumenti dell’IDE.

#define e variabili globali

#define REC_BUTTON_PIN 2
#define ACT_LED_PIN 13

#define ACT_LED_TIME_BLE_ON 50 
#define ACT_LED_TIME_BLE_CON 250
#define ACT_LED_TIME_BLE_SYNC 500
#define ACT_LED_TIME_LOOP 1000
#define SETUP_WAIT_TIME 10000

#define UUID_SERVICE_MYWIFI "9ffb2eb6-842a-4e3f-9245-71218e0a846f"
#define UUID_CHARACTERISTIC_MYWIFI_SSID "9ffb2eb7-842a-4e3f-9245-71218e0a846f"
#define UUID_CHARACTERISTIC_MYWIFI_PASS "9ffb2eb8-842a-4e3f-9245-71218e0a846f"

typedef struct {
  bool dataValid; 
  char ssid[32];
  char pass[63];
} t_wifiCred;

t_wifiCred myWiFiCred;
FlashStorage(flashMyWiFiCred, t_wifiCred);

unsigned long currentMillis = 0;
unsigned long prevMillis = 0;

In questa parte del programma si utilizza la direttiva #define per definire, senza sprecare memoria, i nomi che identificheranno all’interno del codice valori costanti.

REC_BUTTON_PIN e ACT_LED_PIN sono rispettivamente i piedini a cui sono collegati il pulsante di recovery e il led di stato, nel nostro caso il pin D2 e il pin D13 ovvero il LED_BUILTIN.

Arduino Nano 33 IOT – Pinout

I #define la cui etichetta inizia per ACT_LED_TIME definiscono il semi-periodo (TON e TOFF sono uguali) in mS del lampeggio del led di stato, frequenza che varierà in relazione a ciò che il programma dovrà fare.

SETUP_WAIT_TIME è il tempo, sempre in mS, di attesa iniziale in cui l’utente dovrà premere il tasto di recovery per poter procedere con il caricamento delle caratteristiche via BLE.

Merita di essere commentata la parte di codice dedicata all’utilizzo della memoria Flash.

Prima di tutto si definisce un nuovo tipo di dato composto (t_wifiCred), utilizzando la parola chiave typedef combinata con struct, i cui elementi sono un valore booleano e due array di caratteri.

Questo nuovo tipo di dato è dimensionato per contenere la lunghezza massima delle etichette che identificano SSID e password, il campo booleano dataValid sarà settato al valore true una volta che i due array di caratteri saranno stati riempiti con i valori appropriati.

FlashStorage(flashMyWiFiCred, t_wifiCred) riserva nella Flash un’area di memoria etichettata come “flashMyWiFiCred” riservata per immagazzinare le credenziali per l’accesso alla rete Wi-Fi.

Setup()

void setup() {
  boolean myWiFiRec = false;
  byte index = 1;
  int actLedTimeBLE;

  String myWiFi_SSID = "";
  String myWiFi_PASS = "";

  pinMode(REC_BUTTON_PIN, INPUT_PULLUP);
  pinMode(ACT_LED_PIN, OUTPUT);

  Serial.begin(9600);

  // while (!Serial) {}

  Serial.println ("Premere pulsante di recovery per modificare SSID e PW Wi-Fi via BLE");
  Serial.println (SETUP_WAIT_TIME / 1000);
  while (currentMillis < SETUP_WAIT_TIME && (!myWiFiRec)) {
    myWiFiRec = !(digitalRead(REC_BUTTON_PIN));
    currentMillis = millis();
    if (currentMillis >= (index * 1000)) {
      Serial.println (SETUP_WAIT_TIME / 1000 - index++);
    }
  }

  myWiFiCred = flashMyWiFiCred.read();

  if (myWiFiRec || (!myWiFiCred.dataValid)) {

    BLEService myWiFiService(UUID_SERVICE_MYWIFI);
    BLEStringCharacteristic myWiFiCharacteristic_SSID(UUID_CHARACTERISTIC_MYWIFI_SSID, BLEWrite, 32);
    BLEStringCharacteristic myWiFiCharacteristic_PASS(UUID_CHARACTERISTIC_MYWIFI_PASS, BLEWrite, 63);

    if (!BLE.begin()) {
      Serial.println("Errore collegamento con modulo radio NINA-W102 !!!");
      while (true);
    }

    BLE.setDeviceName("Arduino_Nano_33_IOT");
    BLE.setLocalName("Arduino_Nano_33_IOT");
    BLE.setAdvertisedService(myWiFiService);

    myWiFiService.addCharacteristic(myWiFiCharacteristic_SSID);
    myWiFiService.addCharacteristic(myWiFiCharacteristic_PASS);

    BLE.addService(myWiFiService);

    myWiFiCharacteristic_SSID.writeValue(myWiFi_SSID);
    myWiFiCharacteristic_PASS.writeValue(myWiFi_PASS);

    BLE.advertise();

    Serial.println("BLE attivo, in attesa collegamento dispositivo client...");

    while (myWiFiRec || (!myWiFiCred.dataValid)) {

      ledActivity(ACT_LED_TIME_BLE_ON);

      BLEDevice central = BLE.central();
      if (central)  {

        Serial.print("Connesso a dispositvo client: ");
        Serial.println(central.address());

        actLedTimeBLE = ACT_LED_TIME_BLE_CON;

        while (central.connected())
        {

          ledActivity(actLedTimeBLE);

          if (myWiFiCharacteristic_SSID.written())
          {
            myWiFi_SSID = myWiFiCharacteristic_SSID.value();
            myWiFi_SSID.toCharArray(myWiFiCred.ssid, 32);
            Serial.print("SSID: ");
            Serial.println(myWiFiCred.ssid);
            myWiFiCred.dataValid = true;
            actLedTimeBLE = ACT_LED_TIME_BLE_SYNC;
          }
          if (myWiFiCharacteristic_PASS.written())
          {
            myWiFi_PASS = myWiFiCharacteristic_PASS.value();
            myWiFi_PASS.toCharArray(myWiFiCred.pass, 63);
            Serial.print("PASS: ");
            Serial.println(myWiFiCred.pass);
            myWiFiCred.dataValid = true;
            actLedTimeBLE = ACT_LED_TIME_BLE_SYNC;
          }
        }

        if (myWiFiCred.dataValid) {
          Serial.println("Scrittura SSID e PW nella memoria Flash...");
          flashMyWiFiCred.write(myWiFiCred);
        }

        Serial.print("Disconnesso da dispositvo client: ");
        Serial.println(central.address());

        myWiFiRec = false;

        BLE.stopAdvertise();
        BLE.end();

        wiFiDrv.wifiDriverDeinit();
        wiFiDrv.wifiDriverInit();

      }
    }
  } else {

  }

  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Errore collegamento con modulo radio NINA-W102 !!!");
    while (true);
  }

  if (myWiFiCred.dataValid == true) {
    if (connectToAP())printWifiStatus();
  } else {
    Serial.println("Credenziali per il collegamento con la rete mancanti, caricare da App!!!");
    while (true);
  }

}

La funzione setup() contiene il codice utilizzato per gestire il collegamento BLE tra la scheda Arduino e lo smartphone e per scrivere / leggere i dati in Flash, analizziamo le parti più significative:

In questo primo blocco viene impostato il pin del pulsante di recovery come ingresso con pull-up attivo mentre il pin del led di stato viene ovviamente impostato come uscita.

L’istruzione commentata while (!Serial) {} è particolarmente utile durante la prima verifica del firmware, in questo caso è necessario de-commentarla prima di procedere al caricamento. Questa istruzione permette, nelle schede con porte USB native, tipo la Nano 33 IOT, di bloccare l’esecuzione del codice fino a quando non viene aperta la finestra del monitor seriale, in questo modo non ci perderemmo i messaggi inviati alla porta seriale utili per diagnosticare eventuali malfunzionamenti del firmware.

Utilizzatela e una volta terminata la verifica commentatela o rimuovetela insieme a tutte le istruzioni di stampa sul monitor seriale.

In questo secondo blocco di codice viene eseguito un ciclo while di attesa che terminerà o al raggiungimento del tempo SETUP_WAIT_TIME, impostato a 10 secondi o al momento in cui viene premuto il tasto di recovery, in questo ultimo caso la variabile booleana myWiFiRec diventerà true.

L’istruzione legge il contenuto della memoria Flash e lo copia nella variabile globale myWiFiCred di tipo t_wifiCred, in questo modo tutte le volte che il programma ripartirà avrò una copia dalla Flash delle credenziali salvate per l’accesso alla rete Wi-Fi.

Il corpo dell’istruzione condizionale if che contiene la procedura di attivazione del BLE viene eseguito solo se è stato premuto il tasto di recovery nel ciclo while precedente o se l’elemento datavalid letto dalla memoria Flash è uguale a 0.

ATTENZIONE !!!

Ogni volta che carichiamo un nuovo sketch il contenuto della memoria viene cancellato, ovvero riempito di zeri.

E’ questo il caso in cui l’elemento datavalid forza l’esecuzione del corpo dell’istruzione condizionale if visto in precedenza.

Questo è il blocco dedicato ad inizializzare la comunicazione BLE, la prima cosa che viene fatta è istanziare l’unico servizio che utilizziamo myWiFiService mediante l’oggetto BLEService, fatto questo sarà necessario aggiungere le due caratteristiche al servizio attribuendo a ciascuna un nome identificativo myWiFiCharacteristic_SSID e myWiFiCharacteristic_PASS ogni caratteristica è definita come valore stringa e il metodo di pubblicazione è in sola scrittura BLEWrite, questo significa che Arduino potrà solo ricevere i dati dallo smartphone, altra proprietà che viene passata è la lunghezza delle stringhe pari a 32 e 63 caratteri in accordo con quanto definito precedentemente quando abbiamo riservato spazio nella memoria Flash per allocare SSID e password.

Assegniamo a questo punto, dopo aver verificato la corretta inizializzazione del modulo BLE, lo stesso nome Arduino_Nano_33_IOT al servizio e al dispositivo, questo identificativo sarà utile per riconoscere il device nella fase di ricerca dei dispositivi da accoppiare su smartphone.

Aggiungiamo le caratteristiche con il metodo addCharacteristic, attiviamo il servizio con BLE.addService(myWiFiService) e per finire avviamo la pubblicazione. Da questo momento in poi Arduino sarà visibile a tutti i dispositivi di tipo central, nel nostro progetto lo smartphone con App Android.

Dopo l’attivazione e l’inizializzazione del BLE il programma si predispone ad eseguire un ciclo while teoricamente infinito, da quale usciremo se il campo dataValid diventa true ovvero se inviamo da App Android i nuovi valori SSID e password o se ci connettiamo e disconnettiamo con lo smartphone anche senza modificare le credenziali di rete Wi-Fi.

Nel ciclo while impostiamo il lampeggio del led di stato ogni 50mS (molto veloce) e restiamo in ascolto di un eventuale dispositivo central verificandone la connessione con BLE.central().


Quando il dispositivo esterno si connette ad Arduino il corpo dell’istruzione condizionale if viene eseguito, il lampeggio del led di stato viene impostato ogni 250mS (rallenta) ed entriamo nel ciclo while che durerà fino a quando il dispositivo central resterà connesso con la scheda.

Le due istruzioni if, contenute nel ciclo while del blocco precedente, ci permettono di recuperare i dati inviati dalla App Android, i valori ricevuti in formato stringa saranno convertiti in array di char con la funzione toCharArray() in questo modo potranno essere salvati nella memoria Flash, il lampeggio del led di stato viene impostato ogni 500mS (rallenta ancora).

ATTENZIONE !!!

Ho volutamente lasciato nel programma le istruzioni di stampa sulla console seriale per consentire, alla prima installazione la verifica dei dati inseriti. Anche la password di accesso alla rete sarà mostrata in chiaro sul monitor seriale.

Se i dati SSID e password sono stati inviati ad Arduino si procede con il salvataggio delle informazioni nello spazio riservato della memoria Flash

I moduli multi-radio, tipo il NINA-W102 del nostro Arduino nano 33 IOT, pur supportando sulla stessa frequenza di 2,4GHz differenti protocolli di comunicazione come il Wi-Fi e il Bluetooth non potranno, a causa della condivisione del modulo RF+Antenna, consentirne l’utilizzo contemporaneo.

Il diagramma a blocchi, estratto dal datasheet del costruttore, evidenzia come il trasmettitore radio, che si occupa della modulazione del segnale, sia in comune tra il blocco banda base Wi-Fi e Bluetooth.

Diagramma a blocchi famiglia NINA-W10

Altro problema in cui mi sono imbattuto è che l’attivazione di uno dei due standard di comunicazione porta all’impossibilità di utilizzare l’altro, unica soluzione il riavvio hardware della scheda.

Questa “limitazione” ampiamente dibattuta nei forum dedicati all’argomento è superabile in almeno un paio di modi, il primo, che ho scartato, prevedeva il Modding del firmware ufficiale del modulo Nina, l’altra soluzione sicuramente meno invasiva anche da un punto di vista di certificazione radio riguarda l’utilizzo della libreria wifi_drv.h richiamando nel codice alcune semplici metodi che andranno a forzare la reinizializzazione del driver Wi-Fi ovvero wiFiDrv.wifiDriverDeinit() e wiFiDrv.wifiDriverInit().

Le prima istruzione condizionale if controlla la comunicazione con il modulo Wi-Fi, ovviamente per quanto già detto in precedenza il solito Nina-W102 utilizzato per il collegamento BLE.

La seconda if esegue, se le credenziali in memoria Flash sono valide, una verifica del collegamento Wi-Fi.

loop() e funzioni

void loop() {
  ledActivity(ACT_LED_TIME_LOOP);
}

bool connectToAP() {
  int statusWiFi = WL_IDLE_STATUS;
  const byte MAX_RETRY = 5;
  byte retry = 1;

  WiFiSSLClient client;
  while ((statusWiFi != WL_CONNECTED) && (retry <= MAX_RETRY)) {
    Serial.print("Collegamento a rete SSID: ");
    Serial.print(myWiFiCred.ssid);
    Serial.print(" tentativo numero: ");
    Serial.println(retry++);
    statusWiFi = WiFi.begin(myWiFiCred.ssid, myWiFiCred.pass);
    delay(1000);
    if (statusWiFi == WL_CONNECTED ) {
      Serial.println("Connesso!!!");
      return true;
    }
  }
  Serial.println("Non connesso!!!");
  return false;
}

void printWifiStatus() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}

void ledActivity(int intervalTime) {
  currentMillis = millis();
  if (currentMillis - prevMillis >= intervalTime) {
    prevMillis = currentMillis;
    digitalWrite(ACT_LED_PIN, (!digitalRead(ACT_LED_PIN)));
  }
}

Il ciclo infinito loop, nella nostra applicazione, avrà quale unico compito quello di fa lampeggiare il led di stato ad una frequenza di una vola al secondo, in questo modo sapremo che il setup è terminato e che stiamo eseguendo il codice a run-time.

La funzione booleana connectToAP() restituisce true se il collegamento con l’Access Point ha successo.

Il ciclo while all’interno della funzione viene ripetuto fino al numero massimo dei retry impostati (5) o fino a che non avviene il collegamento con l’AP.

WiFi.begin inizializza le impostazioni di rete passando i valori array di char letti dalla memoria Flash corrispondenti al SSID e alla password.

La procedura printWifiStatus(), richiamata se la funzione predente è true, stampa sulla console seriale il nome della rete e l’indirizzo IP ricevuto dall’Access Point.

Monitor seriale

Vediamo adesso quali sono i messaggi stampati nel monitor seriale nel caso in cui sia stato premuto dall’utente il pulsante di recovery e siano state inviate via BLE le nuove credenziale per l’accesso alla rete Wi-Fi.

Configurazione credenziali di rete, modalità recovery

Nel caso in cui non venga premuto il pulsante di recovery e non sia stata precedentemente cancellata la memoria Flash i messaggi nel monitor seriale saranno quegli riportati nell’immagine che segue.

Accensione standard Arduino

Applicazione Android

L’applicazione per smartphone è stata realizzata con MIT App Inventor un tool di sviluppo per App Android creato dall’istituto di tecnologia del Massachusetts.

L’estensione per aggiungere la funzionalità BLE (BluetoothLE) all’ambiente di sviluppo può essere scaricata dal link:

https://mit-cml.github.io/extensions/

L’immagine che segue mostra i blocchi colorati che con il loro incastro determinano il codice dell’applicazione:

Dopo aver generato dall’ambiente di programmazione il file APK e dopo averlo installato sullo smartphone è necessario spendere due parole su come utilizzare l’applicazione.

In questi nove screenshots dell’APP Android è riportato in basso un testo evidenziato in giallo che commenta l’azione che l’utente dovrà fare per “avanzare” nella procedura di configurazione della rete Wi-Fi.

Valuta questo articolo, è anonimo e non richiede registrazioni!

Avatar photo

Fabrizio Vignolini

Diplomato come Perito Industriale in elettronica nel 1995, progettista elettronico da oltre 20 anni, responsabile marcatura CE e qualifica di prodotto dal 2017, appassionato di programmazione e stampa 3D, podista nel tempo libero.


Scansiona il QRCode per leggerlo sul cellulare!

Scansiona il QRCode con la nostra applicazione ufficiale per leggere l'articolo sul tuo smartphone Android! Scarica l'ultima versione


SPONSORIZZATO

Potrebbero interessarti anche...

2 risposte

  1. Tommy ha detto:

    Articolo Interessante e scritto molto bene. Ottimo!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *