En aquest cas s'ha dissenyat un sonòmetre per a sales interiors. El microcontrolador treballa com a client i envia periòdicament el valor de so mesurat a un full de càlcul de Google i, a més, canvia el color del LED. Es fa servir un script per enviar, si el nivell de so és elevat, un correu electrònic a la persona responsable. Addicionalment, hi ha una aplicació per a mòbils que permet consultar la informació. 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> // biblioteca per als NeoPixels #define LED 1 // pota on hem connectat el LED #define MICpin A6 #define numMost 500
WiFiSSLClient client; Adafruit_NeoPixel cadena = Adafruit_NeoPixel(1, LED, NEO_GRB + NEO_KHZ800); const char idXarxa[] = "xarxa"; // Nom del punt d'accés const char contrasenya[] = "contrasenya"; // Contrasenya de connexió const char formulari[] = "1PKLQIW4EEKrIHUUUgCmqn7fxyZ5FnPTj-rvpt1tYKL0/edit#gid=1237915684"; const char adrePost[] = "/forms/u/0/d/e/1FAMpQLSdWJmRvnpm0zFrYqgMZPyqhwpSbvkdrDouvRHRacovY8CGr-g/formResponse"; char server_script[] = "script.google.com"; char id_script[]= "/macros/s/AKfycbybIYvW1WTHcCzSbwmeIOtj_FPNcXYaSbpqPvAGfdjd9LL4u-0/exec?accio=darrer"; String camp = "entry.286343721"; char server_full_calcul[] = "docs.google.com"; String data; int status = WL_IDLE_STATUS; int lectures[numMost]; int lectura, maxim, minim, suma; float rms, lecCorr, mitjana; int R, G, B; // Aquí guardarem els colors
void setup() { // Inicialització
Serial.begin(9600); // Monitor sèrie
cadena.begin(); // Inicialitza els NeoPixels
cadena.show();
while (!Serial) {
; // Esperem que l'usuari obri el monitor sèrie
}
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();
Serial.println("Anem a connectar al servidor");
}
void loop() {
// Primer escrivim els valors en un full de càlcul
if (status != WiFi.status()) { // Mirem si ha canviat l'estat de la connexió
status = WiFi.status();
if (status == WL_AP_CONNECTED) {
Serial.println("Dispositiu connectat al punt d'accés");
} else {
Serial.println("El dispositiu s'ha desconnectat del punt d'accés");
}
}
maxim = 0;
minim = 1024;
suma = 0;
for (int i = 0; i < numMost; i++){
lectura = analogRead(MICpin);
suma = suma + lectura;
if(lectura > maxim){
maxim = lectura;
}
if(lectura < minim){
minim = lectura;
}
lectures[i] = lectura;
}
mitjana = float(suma) / numMost;
rms = 0;
for (int i = 0; i < numMost; i++){
lecCorr = float(lectures[i]) - mitjana;
rms = rms + lecCorr * lecCorr;
}
rms = sqrt(rms / numMost);
data = "";
data += camp;
data += "=";
data += rms;
data += "&submit=Submit";
if (client.connect(server_full_calcul, 443)) {
Serial.println("Connectat");
client.print("POST ");
client.print(adrePost);
client.print("?formkey=");
client.print(formulari);
client.println("&ifq HTTP/1.1");
client.print("Host: ");
client.println(server_full_calcul);
client.println("Content-Type: application/x-www-form-urlencoded");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.print(data);
client.println();
Serial.print("Enviat So = ");
Serial.print(rms);
}
delay(1000);
if (!client.connected()) {
Serial.println();
Serial.println("Desconnectant");
client.stop();
}
delay(10000);
// Ara llegim aquests valors i encenem el LED
if (rms <= 5) { // El LED s'encén de color verd perquè hi ha poc soroll
R= 0;
G= 255;
B= 0;
} else if ((rms> 5)&& (rms<= 10)){ // El LED s'encén de color taronja
R= 255;
G= 128;
B= 0;
}
else if (rms > 10){ // El LED s'encén de color vermell perquè hi ha molt soroll
R= 255;
G= 0;
B= 0;
if (client.connect(server_script, 443)) {
Serial.println("Connectat");
client.println(server_script);
client.print(id_script);
}
}
cadena.setPixelColor(0, R, G, B);
cadena.show();
}
L'script és el següent:
var IdFull = "1PKLQIW4EEErIHUUUbCmqn7gxyZ5FnPTj-rvpt1tSRL0"; // Identificador del full de càlcul
// S'aconsegueix picant a Comparteix i triant Opcions avançades
var numCols = 2; // Nombre de columnes de treball que tenim al full de càlcul
var range1;
var range2;
// Script per interactuar amb el full de càlcul
// Funció que s'executa quan hi ha una ordre get
// La nostra funció tindrà un paràmetre: so
function doGet(e) {
// Assignem els paràmetres a variables
var RMS= e.parameter.so;
// Obrim el full de càlcul
var sh = SpreadsheetApp.openById(IdFull);
var sheet = sh.getSheets();
// Llegim les dades del full 1 per obtenir el valor RMS
var full1 = sheet[1].getDataRange().getValues();
range1 = sheet[1].getLastRow();
if (range1 > 1){ // Si és 0 només hi ha els títols
var darreraConnexio = full1[range1 -1][0];
}
// Llegim les dades del full 2 per obtenir el correu i el lloc
var full2 = sheet[2].getDataRange().getValues();
range2 = sheet[2].getLastRow();
if (range2 > 1){ // Si és 0 només hi ha els títols
var destinatari = full2[range2 -1][0];
var lloc= full2[range2 -1][1];
}
var ara = new Date();
var Hora = ara.getHours();
var Minut = ara.getMinutes();
var horaActual = Hora + ":" + Minut + " h";
var Dia= ara.getDate();
var Mes= ara.getMonth()+1;
var Any= ara.getFullYear();
var diaActual= Dia + "-" + Mes + "-" + Any;
var titol = "Avís: so elevat";
var text = "Avui, dia " + diaActual + ", a les " + horaActual + ", s'ha produït un esdeveniment que ha provocat l'enviament d'aquest correu electrònic. ";
text= text + "\n \n";
text= text + " A la sala " + lloc +" hi ha actualment un soroll molt elevat. "
text= text + "\n \n";
text = text + "Concretament, de " + RMS + " unitats. Aquest valor es troba per sobre del límit establert. ";
text= text + "\n \n";
text = text + "Si us plau, convindria reduir el volum per no molestar els veïns i companys.";
text = text + "\n\n"; // Dos salts de línia
text = text + "Gràcies!";
var interval_millis= 10*60*1000; // Correspon a 10 min
if (ara.getTime() - darreraConnexio.getTime() >= interval_millis){
MailApp.sendEmail(destinatari, titol, text);
sheet[1].appendRow ([ara, RMS]);
}
return ContentService.createTextOutput(RMS);
}
L'aplicació feta amb App Inventor té dues 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:


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