Internet de les coses amb ESP32 i ESP8266

Exemples Referència Plaques   Recursos CITCEA
Projectes Programació Perifèrics   Inici

Sonòmetre

Programa del grup 4

En aquest cas s'ha dissenyat un sonòmetre per a un estudi musical. El microcontrolador treballa com a client i envia periòdicament el valor de so mesurat i el seu espectre freqüencial a un full de càlcul de Google, si es supera un determinat llindar, fent servir un script. A més, canvia el color del LED. Un applet d'IFTTT envia un missatge de Telegram la informació que es va penjant al full de càlcul. Addicionalment, hi ha una aplicació per a mòbils que permet consultar la informació. El programa del microcontrolador és el següent:

#include "arduinoFFT.h"
#include <WiFiNINA.h> 
#include <SPI.h>
#include <Adafruit_NeoPixel.h>
#define SAMPLES 512			// tiene que ser una potencia de 2
#define SAMPLING_FREQUENCY 10000	// Hz, menos de 10000 por el ADC, la mitad es la freq max hasta la cual te muestra
#define MICpin A6
#define LED 1
#define maxl 50				// brillo maximo del LED
#define maxp 30				// valor maximo para que se envien los datos
#define server_len 50
#define pag_len 400
arduinoFFT FFT = arduinoFFT();
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(3, 1, NEO_GRB + NEO_KHZ800);
WiFiSSLClient client;
const char idXarxa[] = "xarxa";	// Nombre del punto de acceso
const char contrasenya[] = "contrasenya";	// Contraseña de connexión
const String server0 = F("script.google.com");
String pagina0 = "";
const String pagina_base = F("/macros/s/AKfycbyVI9uKFTJHpBlcF_DQOl_v0LS0H_lWxzG7owK5CsUfXqh9tg/exec");
char server[server_len];
char pagina[pag_len];
unsigned long darreraConnexio = 0;
const unsigned long periodeConnexio = 10000UL;
bool pendent, completa, redir;
bool ara = false;
String data;
String peticio = "";	// Aquí guardaremos una línea de la petición del cliente
String peticioAux = "";	// y la petición anterior
int maxim, minim, suma, y, x;
const int vhz[] PROGMEM = {10, 25, 31, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
	1000, 1250, 1600, 2000, 2500, 3150, 4000, 4990};	// 25 es el numero de muestras que cogemos para enviar a sheets
float lecCorr, mitjana, rms;	// en vhz se ponen los valores 10 y 4990 donde deberian ir 20 y 5000 por errores que da el arduino
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
int status = WL_IDLE_STATUS;
void setup() {
	cadena.begin();	
	cadena.show();
	Serial.begin(115200);
	pinMode(LED, OUTPUT);
	sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
	while (status != WL_CONNECTED) {
		status = WiFi.begin(idXarxa, contrasenya);
	}
	redir = false;
}
void loop() {
	maxim = 0;
	minim = 1024;
	suma = 0;
	// calcul de x
	for(int i=0; i<SAMPLES; i++) {
		microseconds = micros();
		vReal[i] = analogRead(MICpin);
		vImag[i] = 0;
		suma = suma + vReal[i];
		if(vReal[i] > maxim){
			maxim = vReal[i];
		}
		if(vReal[i] < minim){
			minim = vReal[i];
		}
	}
	mitjana = float(suma) / SAMPLES;
	rms = 0;
	for (int i = 0; i < SAMPLES; i++){
		lecCorr = float(vReal[i]) - mitjana;
		rms = rms + lecCorr * lecCorr;
	}
	rms = sqrt(rms /SAMPLES);
	x=rms*maxl/512;
	if (x>maxl){
		x=maxl;
	}
	if (x<0){
		x=0;
	}
	byte x2=byte(x);
	cadena.setPixelColor(0,x2,maxl-x2,0);//RGB
	cadena.show(); 
	while (client.available()) {
		char c = client.read();
		if (c == '\n') {
			peticioAux = peticio;
			peticio = "";
			completa = true;
		} else {
			peticio += c;
		}
		if (completa){
			if (peticioAux.startsWith(F("HTTP/1.1 200"))){
				pendent = true;
			}
			if (peticioAux.startsWith(F("HTTP/1.1 302"))){
				redir = true;
			}
			if (redir && (peticioAux.startsWith(F("Location:")))){
				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;
		}
	}
	if (pendent) {
		pendent = false;
	}
	if(x2>maxp){		// valor a partir del cual consideramos que es mucho ruido
		FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
		FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
		FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
		double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
		if (ara || ((millis() - darreraConnexio > periodeConnexio))) {
			data = "?X=";
			data += x;
			for (byte i = 0; i < 25 ; i++){
				data += "&v" + String(vhz[i]) + "hz=";
				data += 20*log10(vReal[round((vhz[i]*SAMPLES)/(SAMPLING_FREQUENCY/2))])-40;
					// para que no de valores tan altos
			}
			if (redir){
				redir = false;
			} else {
				pagina0 = pagina_base + data;
				server0.toCharArray(server, server_len);
				pagina0.toCharArray(pagina, pag_len);
			}
			ara = false;
			client.stop();
			if (client.connect(server, 443)) {
				client.print(F("GET "));
				client.print(F(pagina));
				client.println(F(" HTTP/1.1"));
				client.print(F("Host: "));
				client.println(F(server));
				client.println(F("Connection: close"));
				client.println();
				darreraConnexio = millis();
				Serial.println(data);
			} else {
				Serial.println(F("connection failed"));
			}
		}
	}
}

L'script és el següent:

var IdFull = "1LtKt6XSbV9L8QWDtxrme7PXWWVo0Lfu1ODrdPpouYWI"; 
var numFull = 0;	
function doGet(e) {
	var resultat = '';
	var camps = new Array(26); 
	var X = e.parameter.X; 
	var v10hz = e.parameter.v10hz; 
	var v25hz = e.parameter.v25hz;
	var v31hz = e.parameter.v31hz;
	var v40hz = e.parameter.v40hz;
	var v50hz = e.parameter.v50hz;
	var v63hz = e.parameter.v63hz;
	var v80hz = e.parameter.v80hz;
	var v100hz = e.parameter.v100hz;
	var v125hz = e.parameter.v125hz;
	var v160hz = e.parameter.v160hz;
	var v200hz = e.parameter.v200hz;
	var v250hz = e.parameter.v250hz;
	var v315hz = e.parameter.v3150hz;
	var v400hz = e.parameter.v400hz;
	var v500hz = e.parameter.v500hz;
	var v630hz = e.parameter.v630hz;
	var v800hz = e.parameter.v800hz;
	var v1000hz = e.parameter.v1000hz;
	var v1250hz = e.parameter.v1250hz;
	var v1600hz = e.parameter.v1600hz;
	var v2000hz = e.parameter.v2000hz;
	var v2500hz = e.parameter.v2500hz;
	var v3150hz = e.parameter.v3150hz;
	var v4000hz = e.parameter.v4000hz;
	var v4990hz = e.parameter.v4990hz;
	if (X == undefined){
		resultat = 'Falten paràmetres';
	} else {
		camps[0]="";
		camps[1] = X; 
		camps[2] = v10hz;	// Va als 20 Hz
		camps[3] = v25hz;
		camps[4] = v31hz;
		camps[5] = v40hz;
		camps[6] = v50hz;
		camps[7] = v63hz;
		camps[8] = v80hz;
		camps[9] = v100hz;
		camps[10] = v125hz;
		camps[11] = v160hz;
		camps[12] = v200hz;
		camps[13] = v250hz;
		camps[14] = v315hz;
		camps[15] = v400hz;
		camps[16] = v500hz;
		camps[17] = v630hz;
		camps[18] = v800hz;
		camps[19] = v1000hz;
		camps[20] = v1250hz;
		camps[21] = v1600hz;
		camps[22] = v2000hz;
		camps[23] = v2500hz;
		camps[24] = v3150hz;
		camps[25] = v4000hz;
		camps[26] = v4990hz;	// Va als 5000 Hz
		var valu = new Array(1);
		valu[0] = camps;	
		var sh = SpreadsheetApp.openById(IdFull);
		var sheet = sh.getSheets();
		var range = sheet[numFull].getLastRow();
		if (range > 1){	
			var rangeVal = sheet[numFull].getRange(2, 1, 1, 27); 
			rangeVal.setValues(valu);	
		} else {
			sheet[numFull].appendRow(camps); 
		}
		for(j = 1;j < 27;j++){ 
				camps[j] = "";
		}
		camps[0] =X;
		sheet[numFull].appendRow(camps); 
		resultat = 'Valors guardats';
	}
	return ContentService.createTextOutput(resultat); 
}

L'aplicació feta amb App Inventor té el següent disseny de pantalla:

Pantalla

El programa és el següent:

Programa
Programa

 

 

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