En aquest cas s'ha implementat un menú a la pantalla que permet triar entre dues formes de treballar: valors actuals de corrent o potència i estudi de consum. A l'estudi de consum es fan mesures durant un temps establert i es reb un informe de resultats per correu electrònic. La durada de l'estudi es pot triar entre una i vint-i-quatre hores. L'informe inclou la recomanació de la companyia elèctrica més favorable als resultats obtinguts.
El programa del microcontrolador és el següent:
// BIBLIOTEQUES #include <ssd1306.h> #include <ssd1306_console.h> #include <SPI.h> #include <WiFiNINA.h> // DEFINICIONS #define SensLec A5 #define SensRef A6 #define numEsp 2 #define numCicles 100 #define brunzidor 3 #define pols_ok 4 #define pols_down 5 #define pols_home 7 #define N_Sol4 784 #define N_La4 880 #define N_Si4 988 #define N_Do5 1047 #define N_Mi5 1319 #define server_len 50 // Wifi #define pag_len 400 // Wifi
// VARIABLES GLOBALS
Ssd1306Console console;
SAppMenu menu;
unsigned long tempsAnt;
float maxI = 0;
float minI = 0;
float sumaquad = 0;
float suma = 0;
int n = 0;
const char* elements_main[] = { "Estudi de Consum", "Dades" };
const char* elements_dades[] = { "Intensitat", "Potencia"};
const char* elements_estudideconsum[] = { "1 h", "2 h", "3 h", "4 h", "5 h", "6 h", "7 h",
"8 h", "9 h", "10 h", "11 h", "12 h", "13 h", "14 h",
"15 h", "16 h", "17 h", "18 h", "19 h", "20 h", "21 h",
"22 h", "23 h", "24 h"};
int pg_actual = 0;
float Intensitat = 0;
float Potencia = 0;
int HoresEstudi = 0;
int ValorInicialBarra = 0;
int Temps1percent = 0;
bool estatEstudi = false;
const char idXarxa[] = "xarxa-wifi"; // Nom del wifi
const char contrasenya[] = "contrasenya-wifi"; // Contrasenya wifi
const String server0 = "script.google.com";
String pagina0 = "";
const String pagina_base = "/macros/s/^^fycby1cuinpq5leudHyDWD15ck5aiJOHGW39HzpQeqPEj48SIyTl0lEWCaNTUatL668rf4rg/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í 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;
// SETUP
void setup(){
Serial.begin(9600); // Monitor sèrie
// Pantalla i menu
ssd1306_setFixedFont(ssd1306xled_font6x8);
ssd1306_128x64_i2c_init();
ssd1306_clearScreen();
ssd1306_createMenu(&menu, elements_main, sizeof(elements_main) / sizeof(elements_main[0]));
ssd1306_showMenu(&menu);
// Conexió wifi
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();
redir = false;
// Definició de pins
pinMode(brunzidor, OUTPUT);
pinMode(pols_down, INPUT_PULLUP);
pinMode(pols_ok, INPUT_PULLUP);
pinMode(pols_home, INPUT_PULLUP);
// Musiqueta tot llest
tone(3, N_Sol4, 120);
delay(140);
tone(3, N_La4, 120);
delay(140);
tone(3, N_Si4, 120);
delay(140);
tone(3, N_Do5, 250);
delay(300);
noTone(3);
}
// LOOP
void loop(){
calculSensor();
sendData();
menuNavigation();
realTimeShow();
}
// FUNCIONS
void musiqueta(){
tone(3, N_Do5, 80);
delay(100);
tone(3, N_Mi5, 80);
delay(100);
noTone(3);
}
void calculSensor(){
int lec_sensor = analogRead(SensLec);
int ref_sensor = analogRead(SensRef);
float Iinst = 30 * 3.3 * (lec_sensor - ref_sensor) / 1023 / numEsp;
sumaquad = sumaquad + (Iinst * Iinst);
suma = suma + abs(Iinst);
n++;
if(Iinst > maxI){
maxI = Iinst;
}
if(Iinst < minI){
minI = Iinst;
}
if((millis() - tempsAnt) > (20 * numCicles)){
tempsAnt = millis();
float medI = 1.1107 * suma / n;
float Irms = sqrt(sumaquad / n);
Intensitat = Irms;
Potencia = Irms*230;
maxI = 0;
minI = 0;
sumaquad = 0;
suma = 0;
n = 0;
}
}
void sendData(){
while (client.available()){
char c = client.read(); // Rebem caràcters del servidor
if (c == '\n'){
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
}
if (completa){
if (peticioAux.startsWith("HTTP/1.1 200")){
pendent = true;
}
if (peticioAux.startsWith("HTTP/1.1 302")){
redir = true;
}
if (redir && (peticioAux.startsWith("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 (ara || ((millis() - darreraConnexio > periodeConnexio))){
if(!ara){
data = "?";
data += "Intensitat=";
data += Intensitat;
}
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();
darreraConnexio = millis();
Serial.print("Enviat: ");
Serial.println(data);
} else {
Serial.println("connection failed");
}
ara = false;
}
}
void menuNavigation(){
if (!digitalRead(pols_down) && (pg_actual == 0 || pg_actual == 1 || pg_actual == 2 )){
ssd1306_menuDown(&menu);
ssd1306_clearScreen();
ssd1306_showMenu(&menu);
delay(200); // Debounce
} else if (!digitalRead(pols_ok)) {
int selection = ssd1306_menuSelection(&menu);
if (pg_actual == 0){ // MAIN
musiqueta();
if (selection == 0){ // MAIN>ESTUDI DE CONSUM
pg_actual = 1;
ssd1306_clearScreen();
ssd1306_createMenu(&menu, elements_estudideconsum, sizeof(elements_estudideconsum) / sizeof(elements_estudideconsum[0]));
ssd1306_showMenu(&menu);
} else if (selection == 1){ // MAIN>DADES
pg_actual = 2;
ssd1306_clearScreen();
ssd1306_createMenu(&menu, elements_dades, sizeof(elements_dades) / sizeof(elements_dades[0]));
ssd1306_showMenu(&menu);
}
} else if (pg_actual == 1){ // MAIN>ESTUDI DE CONSUM
musiqueta();
pg_actual = 5;
estatEstudi = true;
HoresEstudi = selection + 1;
ssd1306_clearScreen();
} else if (pg_actual == 2){ // MAIN>DADES
musiqueta();
if (selection == 0){ // MAIN>DADES>INTENSITAT
pg_actual = 3;
ssd1306_clearScreen();
} else if (selection == 1){ // MAIN>DADES>POTENCIA
pg_actual = 4;
ssd1306_clearScreen();
}
}
delay(200); // Debounce
} else if (!digitalRead(pols_home)){
musiqueta();
pg_actual = 0;
ssd1306_clearScreen();
ssd1306_createMenu(&menu, elements_main, sizeof(elements_main) / sizeof(elements_main[0]));
ssd1306_showMenu(&menu);
delay(200); // Debounce
}
}
void realTimeShow(){
if (pg_actual == 3){ // MAIN>DADES>INTENSITAT
console.setCursor(24, 16);
console.print("I = ");
console.print(Intensitat);
console.print("A");
} else if (pg_actual == 4){ // MAIN>DADES>POTENCIA
console.setCursor(24, 16);
console.print("P = ");
console.print(Potencia);
console.print("W");
}
delay(200);
}
El programa de l'script és el següent:
var IdFull = "^^zcjd3PBGwORLSSCea_3pgE-NEx3dMftXp2LnyOj8qY";
function doGet(e) {
if (!e || !e.parameter) {
return ContentService.createTextOutput("Error: no s'han rebut paràmetres.");
}
// Establir les variables principals.
var intensitat = e.parameter.Intensitat;
var horesestudi = e.parameter.HoresEstudi;
var resultat = ''
var camps = new Array(4);
// Obtenir hora actual.
var ara = new Date();
var Ho = ara.getHours();
var Min = ara.getMinutes();
var Seg = ara.getSeconds();
var Hora = ara.getHours().toString().padStart(2, '0') + ":" + ara.getMinutes().toString().padStart(2, '0');
Hora += ":" + ara.getSeconds().toString().padStart(2, '0');
var Data = ara.getDate() + "/" + (ara.getMonth()+1) + "/" + ara.getFullYear();
var potencia = (Number(intensitat)*230/1000).toFixed(2); //Calcular la potència en kW
// Obrir el document de Google Sheets.
var llibre = SpreadsheetApp.openById(IdFull);
var full = llibre.getSheets()[0];
// Comprovar si ja hi ha títols.
var primeraFila = full.getRange(1, 1, 1, 3).getValues()[0];
if (primeraFila[0] !== "Data" || primeraFila[1] !== "Hora" || primeraFila[2] !== "Intensitat (A)") {
full.clearContents(); // neteja el full si no té els títols correctes
full.appendRow(["Data", "Hora", "Intensitat (A)","Potència (kW)"]);
}
// Intentem llegir el valor guardat anteriorment (si n'hi ha)
var horesGuardades = full.getRange(1, 6).getValue();
// Si horesestudi és diferent de 0 i encara no hem guardat res, ho guardem
if (horesestudi !== 0 && horesGuardades === "") {
full.getRange(1, 6).clear()
var durada = String(horesestudi).replace('.',',');
full.getRange(1,6).setValue(durada);
}
if (horesestudi && Number(horesestudi) !== 0 && intensitat) {
camps[0]=String(Data)
camps[1]=String(Hora);
camps[2]=String(intensitat).replace('.', ',');
camps[3]=String(potencia).replace('.', ',');
// Comprovar si la gràfica ja existeix.
full.appendRow(camps); // Afegeix una columna amb la llista de dades en format matriu.
resultat = 'Oriol estaria orgullós';
}
// Començar el càlcul d'energies
if (Number(horesestudi) === 0){
calculEnergies()
resultat = 'Olé';
}
return ContentService.createTextOutput(resultat);
}
function calculEnergies() {
// Definir els fulls del Google Sheets.
var llibre = SpreadsheetApp.openById(IdFull);
var full1 = llibre.getSheets()[0];
var full2 = llibre.getSheets()[1];
var full3 = llibre.getSheets()[2];
// Llegir valors de Hora i Potència del full d'Intensitats.
var ultimafilafull1 = full1.getLastRow();
var filesvalors = ultimafilafull1 - 1
var columnaPot = full1.getRange(2,4,filesvalors,1).getValues();
var columnaHoMinSeg = full1.getRange(2,2,filesvalors,1).getValues();
var columnaHora = [];
// Obtenir la zona horaria perque llegeixi bé les hores del full 1.
var zonahoraria = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
// Cal assegurar que no hi ha errors en les lectures d'hora i afegim les hores.
for (var i = 0; i < columnaHoMinSeg.length; i++) {
var cel = columnaHoMinSeg[i][0];
if (cel instanceof Date && !isNaN(cel.getTime())) {
var horaString = Utilities.formatDate(cel, zonahoraria, "H"); // sense 0 inicial
columnaHora.push(parseInt(horaString));
} else {
columnaHora.push(null);
}
}
// Recorrer les dues llistes per tal de fer els sumatoris d'energies puntuals i classificar-les
// per hores. Després escriure els valors a la columna d'energia consumida.
for (let j = 2; j < 26; j++) {
var wh = 0;
var numvalors = 0
for (let i = 0; i < columnaHoMinSeg.length; i++) {
if (Number(columnaHora[i]) === j-2) {
var valor = columnaPot[i][0].toFixed(2);
var p = String(valor).replace(',', '.');
wh += parseFloat(p);
numvalors++
}
}
if (numvalors === 0) {
var kWh = 0;
}
else {
var kWh = String(wh/numvalors).replace('.', ',');
}
full2.getRange(j, 3).setValue(kWh);
}
// Omplir la taula de preus segons la energia consumida.
var energies = full2.getRange(2, 3, 24, 1).getValues();
for (let i = 2; i < 26; i++) {
var preusComa = full3.getRange(i, 2, 1, 5).getValues();
var preusHora = [];
for (let j = 0; j < 5; j++) {
var preuPunt = String(preusComa[0][j]).replace(',', '.');
var energiaPunt = String(energies[i-2][0]).replace(',', '.');
var preuXenergia = String((Number(preuPunt)*Number(energiaPunt)).toFixed(2)).replace('.', ',');
preusHora.push(preuXenergia);
}
full2.getRange(i, 4, 1, 5).setValues([preusHora]);
}
Utilities.sleep(5000);
creaDocument()
}
function creaDocument() {
var llibre = SpreadsheetApp.openById(IdFull);
var full1 = llibre.getSheets()[0];
var full2 = llibre.getSheets()[1];
var full3 = llibre.getSheets()[2];
var full4 = llibre.getSheets()[3];
// Obtenir les dades i gràfiques que volem introduïr al document.
var dadesEnergia_Preu = full2.getDataRange();
var grafics = full1.getCharts();
var taulaPreusGenerics = full3.getRange(28,9,25,7);
var ultimafilafull1 = full1.getLastRow();
var filesvalors = ultimafilafull1 - 1
// Calcular màx de la intensitat.
var columnaInt = full1.getRange(2,3,filesvalors,1).getValues().flat().map(val => Number(typeof val === 'string' ? val.replace(',', '.') : val));
var maximInt = Math.max(...columnaInt);
var indexosInt = columnaInt
.map((valor, i) => ({ valor, fila: i + 2 })) // +2 perquè comencem a D2
.filter(obj => obj.valor === maximInt)
.map(obj => obj.fila);
// Obtenir el valor màxim de potència i els dies i hores en què s'ha donat aquesta situació.
var maxPot = (maximInt*230/1000).toFixed(2); //Calcular la potència màxima en kW
// Mirar quants valors son major de 1, per tant, es considera que estan encessos
// i multipliquem per 10 (segons entre mesures).
var tempsActiu = (columnaInt.filter(valor => valor > 1).length) * 10;
var ho = Math.floor(tempsActiu / 3600);
var min = Math.floor((tempsActiu % 3600) / 60);
var seg = tempsActiu % 60;
var tempsEnces = String(ho).padStart(2, '0') + " hores " + String(min).padStart(2, '0') + " minuts i " + String(seg).padStart(2, '0') + " segons";
var preusTotal = full2.getRange(26,4,1,5).getValues().flat().map(val => Number(typeof val === 'string' ? val.replace(',', '.') : val));
var preuMin = Math.min(...preusTotal);
var celaPreuMin = (preusTotal.indexOf(preuMin))+4;
var companyiaPreuMin = full2.getRange(1,celaPreuMin).getValue();
// Crear un nou document de Google Docs
var doc = DocumentApp.create("Informe del teu estudi");
var pagina = doc.getBody();
// Obtenir el dia
// Obtenir hora actual
var ara = new Date();
var Data = ara.getDate() + "/" + (ara.getMonth()+1) + "/" + ara.getFullYear();
// Afegir el títol
pagina.appendParagraph(`Informe del teu consum elèctric (${Data})`).setHeading(DocumentApp.ParagraphHeading.HEADING1).setAlignment(DocumentApp.HorizontalAlignment.CENTER).setFontFamily('Times New Roman');
pagina.appendParagraph("(generat automàticament)").setAlignment(DocumentApp.HorizontalAlignment.CENTER).setFontFamily('Times New Roman');
pagina.appendParagraph("");
// Usuari
var ufila4 = full4.getLastRow();
var correu = full4.getRange(ufila4,2).getValue();
pagina.appendParagraph(`Usuari: ${correu}`).setFontFamily('Times New Roman').setFontSize(12).setBold(true);
pagina.appendParagraph("");
// Primer punt: resum
pagina.appendParagraph("Resum:").setFontFamily('Times New Roman').setFontSize(12).setBold(true);
pagina.appendParagraph("");
//Obtenir el valor de horesestudi adjuntat a la casella F1
var duradaestudi = full1.getRange(1,6).getValue();
pagina.appendParagraph(`La durada de l'estudi ha estat de ${duradaestudi} hora/es.`).setFontSize(10).setFontFamily('Times New Roman').setLineSpacing(1.5).setBold(false);
pagina.appendParagraph(`El dispositiu ha estat encès ${tempsEnces}.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
pagina.appendParagraph(`Intensitat màxima: ${maximInt} A.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
pagina.appendParagraph(`Potència màxima: ${maxPot} kW.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
// Si hi ha dos màxims s'ha d'indicar els dos moments de temps en què ha ocurregut el màxim
if (indexosInt.length > 1) {
var datesMax=[];
for (let i=0;i < indexosInt.length; i++) {
var r = full1.getRange(indexosInt[i],1,1,2).getValues();
// Convertim a Date i formatem
var data = new Date(r[0][0]);
var dia = data.getDate().toString().padStart(2, '0') + "/" + (data.getMonth()+1).toString().padStart(2, '0') + "/" + data.getFullYear().toString()
var hora = new Date(r[0][1]);
var horaescrita = hora.getHours().toString() + ":" + hora.getMinutes().toString().padStart(2, '0') + ":" + hora.getSeconds().toString().padStart(2, '0')
var s = dia + ' a les ' + horaescrita;
datesMax.push(s);
}
pagina.appendParagraph(`Aquests valors màxims han succeït: ${datesMax.join(';')}.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
} else {
var r = full1.getRange(indexosInt[0],1,1,2).getValues();
var data = new Date(r[0][0]);
var dia = data.getDate() + "/" + (data.getMonth()+1) + "/" + data.getFullYear();
var hora = new Date(r[0][1]);
var horaescrita = hora.getHours().toString() + ":" + hora.getMinutes().toString().padStart(2, '0') + ":" + hora.getSeconds().toString();
var s = dia + ' a les ' + horaescrita;
pagina.appendParagraph(`Aquest valor màxim ha succeït: ${s}.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
}
pagina.appendParagraph(`La companyia elèctrica més econòmica segons el teu consum es: ${companyiaPreuMin} amb el cost de ${preuMin.toFixed(2)}€.`).setFontFamily('Times New Roman').setLineSpacing(1.5);
pagina.appendPageBreak();
//Segon punt: gràfics
pagina.appendParagraph("Gràfica de intensitat:").setFontFamily('Times New Roman').setFontSize(12).setBold(true);
var imatgeGrafic1 = grafics[0].getAs('image/png');
pagina.appendImage(imatgeGrafic1);
pagina.appendParagraph("");
pagina.appendParagraph("Gràfica de potència:").setFontFamily('Times New Roman').setFontSize(12).setBold(true);
var imatgeGrafic2 = grafics[1].getAs('image/png');
pagina.appendImage(imatgeGrafic2);
pagina.appendPageBreak();
// Tercer punt: taules
// Taula de preus genèrics
pagina.appendParagraph("Taula de preus de companyies elèctriques més comuns a Catalunya (dia 02/03/2025):").setFontSize(12).setFontFamily('Times New Roman').setBold(true);
pagina.appendParagraph("");
var dadesTaula1 = taulaPreusGenerics.getValues();
var taula1 = pagina.appendTable();
var fons1 = taulaPreusGenerics.getBackgrounds();
// Omplir la taula i apliquem colors als fons:
for (let i = 0; i < taulaPreusGenerics.getValues().length; i++) {
var fila = taula1.appendTableRow();
for (let j = 0; j < dadesTaula1[i].length; j++) {
var cela = fila.appendTableCell(dadesTaula1[i][j].toString());
// Estil del text
const textStyle = {};
// Assignar estils
cela.setBackgroundColor(fons1[i][j]);
cela.setFontFamily('Times New Roman');
cela.setFontSize(8);
cela.setBold(false);
}
}
pagina.appendPageBreak();
// Taula d'energia i preus de l'usuari
pagina.appendParagraph(`Taula de consum d'energia i comparativa de preus de l'usuari (Dia ${Data}):`).setFontSize(13).setFontFamily('Times New Roman').setBold(true);
pagina.appendParagraph("");
var dadesTaula2 = dadesEnergia_Preu.getValues();
var taula2 = pagina.appendTable();
var fons2 = dadesEnergia_Preu.getBackgrounds();
// Omplir la taula i apliquem colors als fons:
for (let i = 0; i < dadesTaula2.length; i++) {
var fila = taula2.appendTableRow();
for (let j = 0; j < dadesTaula2[i].length; j++) {
if (typeof dadesTaula2[i][j] === 'number') {
num = Number(String(dadesTaula2[i][j]).replace(',', '.')).toFixed(2);
str = String(num.replace('.', ','));
var cela = fila.appendTableCell(str);
} else if (typeof dadesTaula2[i][j] === 'string') {
var cela = fila.appendTableCell(dadesTaula2[i][j].toString());
}
// Assignar estils
cela.setBackgroundColor(fons2[i][j]);
cela.setFontFamily('Times New Roman');
cela.setFontSize(9);
cela.setBold(false);
}
}
// Després de generar tot el document...
doc.saveAndClose();
// Convertir el document a PDF
var aPDF = DriveApp.getFileById(doc.getId());
var pDF = aPDF.getAs('application/pdf')
// Guardar el PDF amb un nom nou
var nomPDF = "Informe de consum - " + Data + ".pdf";
var arxiuPDF = DriveApp.createFile(pDF).setName(nomPDF);
// Fer públic el document
arxiuPDF.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
// Mostrar l'enllaç al PDF al log
Logger.log("Pots accedir al PDF aquí: " + arxiuPDF.getUrl());
Utilities.sleep(5000); //Esperar 5 segons
//Enviar PDF per correu electrònic
MailApp.sendEmail(correu, "Estudi energètic del teu dispositiu", `(Missatge generat automàticament)` + "\n\n" + `Aquí té el document amb tota la informació obtinguda sobre el seu estudi de consum energètic, esperem li sigui de gran ajut:` + "\n\n" + ` ${arxiuPDF.getUrl()}` + "\n\n" + `No respongui a aquest correu`);
Utilities.sleep(10000); //Esperar 10 segons
netejaFulls()
}
function netejaFulls() {
var llibre = SpreadsheetApp.openById(IdFull);
var full1 = llibre.getSheets()[0];
var full2 = llibre.getSheets()[1];
var full4 = llibre.getSheets()[3];
var ultimaFila1 = full1.getLastRow();
full1.getRange(2,1,ultimaFila1,4).clearContent();
full1.getRange(1,6).clear();
full2.getRange(2,3,24,6).clearContent();
var ultimafilafull4 = full4.getLastRow
//full4.getRange(2,1,ultimafilafull4,2).clear();
full4.clear();
}

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