En aquest cas s'ha dissenyat un sistema d'alarma que detecta l'obertura d'una caixa forta. Una aplicació mòbil permet consultar l'estat de la caixa forta. El programa del microcontrolador és el següent:
#include <SPI.h> // Carreguem la biblioteca SPI #include <WiFiNINA.h> // Carreguem la biblioteca WiFiNINA #include <Adafruit_NeoPixel.h> #define LDRpin A3 #define server_len 50 #define pag_len 400
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(3, 1, NEO_GRB + NEO_KHZ800); const char idXarxa[] = "xarxa-wifi"; const char contrasenya[] = "contrasenya-wifi"; int lectura; const String server0 = "script.google.com"; String pagina0 = ""; const String pagina_base = "/macros/s/^^fycbzfYsaYSF4qT2Ggx0o7G_VsaPEQZYYTmrHDetbbj_fiO6o64KyWDRHhLbbResmzVaKj/ex"; char server[server_len]; char pagina[pag_len]; unsigned long darreraConnexio = 0; const unsigned long periodeConnexio = 10000UL; bool pendent, completa, redir; bool ara = false; float llum; String data; int num; String peticio = ""; // Aquí guardarem una línia de la petició del client String peticioAux = ""; // i la petició anterior (també ho farem servir de reserva) int status = WL_IDLE_STATUS; WiFiSSLClient client;
void setup() { // Inicialització
pinMode(3, OUTPUT);
cadena.begin(); // Inicialitza els NeoPixels
cadena.show();
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("No s'ha trobat el dispositiu Wi-Fi");
while (true)
; // Bloquegem el programa
}
String versio = WiFi.firmwareVersion();
if (versio < "1.0.0") {
Serial.println("Convindria actualitzar el firmware");
}
while (status != WL_CONNECTED) {
Serial.print("Connectant a la xarxa ");
Serial.println(idXarxa);
status = WiFi.begin(idXarxa, contrasenya);
delay(10000); // Ho tornarem a intentar passats 10 s
}
Serial.print("Connectat a ");
Serial.println(WiFi.SSID());
Serial.print("Estat de la connexió: ");
Serial.println(WiFi.status());
Serial.print("Adreça IP del dispositiu: ");
Serial.println(WiFi.localIP());
Serial.print("Intensitat del senyal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.println();
redir = false;
}
void loop() { // Programa que es repeteix indefinidament
// El bucle principal té tres parts:
// 1. Gestió dels caràcters que arriben
// 2. Tractament de les dades rebudes
// 3. Nova petició quan ha passat el temps
while (client.available()) {
// Gestió dels caràcters que arriben
// Aquest bucle va guardant els caràcters rebuts
// i espera al moment en que arriba un salt de línia
char c = client.read(); // Rebem caràcters del servidor
if (c == '\n') { // Mirem si és un salt de línia
peticioAux = peticio; // Guardem la petició anterior
peticio = ""; // Ens preparem per a la línia següent
completa = true; // Preparat per escriure-ho
} else {
peticio += c; // Afegim el caràcter rebut
}
// Quan ha arribat un salt de línia, hem de mirar què ha arribat
if (completa){ // Ha arribat una línia completa
if (peticioAux.startsWith("HTTP/1.1 200")){ // Resposta bona
pendent = true;
}
if (peticioAux.startsWith("HTTP/1.1 302")){ // Redireccionament
redir = true;
}
if (redir && (peticioAux.startsWith("Location:"))){
// Si hi ha redireccionament, hem de buscar l'adreça
// i extreure'n el servidor i la pàgina
String adre = peticioAux.substring(peticioAux.indexOf("//") +2);
String server1 = adre.substring(0, adre.indexOf(".com") +4);
String pagina1 = adre.substring(adre.indexOf(".com") +4);
server1.toCharArray(server, 50);
pagina1.toCharArray(pagina, 400);
ara = true;
}
completa = false;
}
}
// Hi ha una resposta per processar
// Però ignorarem les dades que ens envia l'script
if (pendent) {
pendent = false;
}
// Quan toca, tornem a fer una petició
if (ara || ((millis() - darreraConnexio > periodeConnexio))) {
if(!ara) {
lectura = analogRead(LDRpin);
Serial.print("Lectura = ");
Serial.println(lectura);
data = "?";
data += "l=";
data += lectura;
data += "&m=a";
if (lectura < 1000){
if (num==0){
tone(3, 440);
cadena.setPixelColor(0, 0, 150, 0); // Pixel 0 vermell
cadena.show(); // Actualitz
delay(2000);
noTone(3);
cadena.setPixelColor(0, 0, 0, 0); // Pixel 0 verd
cadena.show(); // Actualitz
num++;
}
} else {
noTone(3);
num=0;
}
}
if (redir){
redir = false;
} else {
pagina0 = pagina_base + data;
server0.toCharArray(server, server_len);
pagina0.toCharArray(pagina, pag_len);
}
client.stop();
if (client.connect(server, 443)) {
Serial.println("S'ha fet la connexió al servidor");
client.print("GET ");
client.print(pagina);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
// Guardem quan hem fet la connexió
darreraConnexio = millis();
Serial.print("Enviat: ");
Serial.println(data);
} else {
Serial.println("connection failed");
}
ara = false;
}
}
El programa de l'script és el següent:
var IdFull = "^^jxRPxZjhCzdUSjSB0hXY5wBB-dEL8yiQeuQteic9Xg"; // Identificador del full de càlcul
var numFull = 0; // Número del full amb el que hem de treballar
var numCols =1;
var ara = new Date();
function doGet(e) {
var resultat = '';
var camps = new Array(1); // Valors per guardar a la taula
var Hora = ara.getHours();
var Minut = ara.getMinutes();
var horaActual = Hora + ":" + Minut + " h";
var titol = "Alerta de seguretat"; // Idioma de la app
var text = "Avui a les " + horaActual + " s'ha produït una obertura de la caixa forta. \n";
text = text + "\nHoy a las " + horaActual + " se ha producido una apertura de la caja fuerte. \n";
text = text + "\nToday at " + horaActual + " the safe has been opened. ";
// Assignem els paràmetres a variables
var llum = e.parameter.l;
var mail = e.parameter.mail;
var m = e.parameter.m;
if ((m=='a')){
if ((llum == undefined)){
resultat = 'Falten paràm';
} else if ((llum < 1000)){
camps[0] = llum;
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
var casant = sheet[numFull].getDataRange().getValues()[sheet[numFull].getLastRow()-1][0];
sheet[numFull].appendRow(camps); // Afegeix una fila amb la llista de dades en format matriu
resultat = 'Valors guardats';
if ((casant <1000)){
return ContentService.createTextOutput(resultat);
} else {
var full = sheet[1].getDataRange().getValues();
range = sheet[1].getLastRow(); // Índex de la darrera filera
if (range >=1){ // Sabent que no hi ha títols, range és el número de files no buides
for (let i = 0; i <= range-1; i++) {
var filera = full[i]; // Agafem la filera i
var correu_filera=filera[0];
MailApp.sendEmail(correu_filera, titol, text);
}
}
}
return ContentService.createTextOutput(resultat);
} else {
camps[0] = llum;
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
sheet[numFull].appendRow(camps); // Afegeix una fila amb la llista de dades en format matriu
resultat = 'Valors guardats';
return ContentService.createTextOutput(resultat);
}
}
if ((m=='b')){
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
// Llegim les dades del full seleccionat
var full = sheet[numFull].getDataRange().getValues();
range = sheet[numFull].getLastRow(); // Índex de la darrera filera (+1 pels títols)
if (range > 1){ // Si és 1 només hi ha els títols
var filera = full[range -1]; // Agafem la darrera filera
var resultat = '';
var a = filera[0];
if (Number(a)==a){
return ContentService.createTextOutput(a);
}
}
return ;
}
if ((m=='c')){
camps[0] = mail;
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
sheet[1].appendRow(camps); // Afegeix una fila amb la llista de dades en format matriu; 1 és numfull on estan els correus
resultat = 'Valors guardats';
return ContentService.createTextOutput(resultat);
}
}
L'aplicació feta amb App Inventor té tres pantalles. La disposició d'elements a la primera pantalla és:

El programa és el següent:



La disposició d'elements a la segona pantalla és:

El programa és el següent:

La disposició d'elements a la tercera pantalla és:

El programa és el següent:


Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.