Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Sensor de presión de IoT:MKR GSM + Arduino Cloud + Hojas de cálculo de Google

Componentes y suministros

Arduino UNO
× 1
Arduino MKR GSM 1400
× 1
Transductor de presión (0-150 psi)
× 1
Sensor de temperatura y humedad Adafruit DHT22
× 1
Módulo DS3231 RTC
× 1
Convertidor de nivel lógico Adafruit - BSS138 - 4 canales I2C-safe Bidireccional
× 1
Batería LiPo Adafruit de 3,7 V (2000 mAh o más)
× 2
Convertidor elevador de voltaje
× 1
Kit de inicio básico con varios LED y resistencias
× 1
Breadboard (genérico)
× 1

Aplicaciones y servicios en línea

Hojas de cálculo de Google
Arduino IoT Cloud
Arduino Web Editor
Arduino IDE

Acerca de este proyecto

Objetivo

El objetivo de este proyecto fue crear un prototipo de un dispositivo de bajo costo para monitorear la presión sobre equipos industriales en ubicaciones remotas utilizando datos celulares.

Tutorial del proyecto

El siguiente es un recorrido paso a paso del proyecto siguiendo el flujo de datos desde el transductor de presión hasta la notificación por correo electrónico generada por el script adjunto a la hoja de Google.

Paso 1:Transductor de presión a Uno

El transductor de presión convierte la presión en una señal eléctrica analógica.

El Arduino Uno convierte la señal analógica del transductor de presión en presión (psi).

Paso 2:Uno a MKR GSM 1400 a través de serie

Al comunicarse entre dos dispositivos Arduino a través de serie:

  • Conecte RX en el dispositivo n. ° 1 a TX en el dispositivo n. ° 2
  • Conecte TX en el dispositivo n. ° 1 a RX en el dispositivo n. ° 2
  • Los dispositivos deben tener un terreno común

Frecuencia de transmisión de datos (Uno a MKR GSM 1400)

  • NORMAL: Cada 30 minutos (frecuencia de transmisión), el Uno imprimirá datos en serie al MKR GSM 1400, que transmitirá los datos a la nube.
  • ACTIVADOR ALTO / BAJO: Si la presión sube por encima de 40 psi (highTrigger) o por debajo de 20 psi (lowTrigger) y permanece allí durante más de 2 minutos (dtLastTriggerLimit), el Uno imprimirá en serie los datos al MKR GSM 1400, que transmitirá los datos a la nube.
  • ENCUESTA DE DEMANDA: Si el pin A1 en el Uno se empuja hacia arriba, imprimirá en serie los datos al MKR GSM 1400, que transmitirá los datos a la nube. Nota:el pin A1 se llama "buttonPin" en el boceto del Uno. Hay 2 formas en que el pin A1 en el Uno puede elevarse. (1) Hay un botón en la placa de pruebas. (2) Si el pin A3 del MKR GSM 1400 está alto, empujará el pin A1 hacia arriba. Dado que el pin A3 está controlado por una entrada en Arduino Cloud, la presión actual se puede obtener de forma remota en cualquier momento sin tener que esperar una transmisión de datos programada regularmente.

Notas

  • El esquema para el Uno podría modificarse para que múltiples entradas como temperatura, humedad, voltaje de la batería, etc. puedan monitorearse con puntos de ajuste altos y bajos además de la presión en la versión actual.
  • El código utilizado para convertir la señal analógica del transductor de presión en presión (psi) se basa en las instrucciones dadas en el siguiente video de YouTube:https://www.youtube.com/watch?v=AB7zgnfkEi4
  • La siguiente publicación en el Foro Arduino que cubre "Conceptos básicos de entrada en serie" fue muy útil cuando se trataba de escribir el código para comunicarse de un dispositivo a otro utilizando datos en serie:https://forum.arduino.cc/index. php? topic =288234.0

El código utilizado para Arduino Uno en este proyecto se adjunta con comentarios que explican la información clave.

Nombre de archivo:"InstrumentReader"

Paso 3:MKR GSM 1400 a Arduino Cloud a través de celular

El MKR GSM 1400 procesa datos en serie del Arduino Uno y transmite los datos a Arduino Cloud utilizando datos móviles.

Vale la pena señalar que en el código del MKR GSM 1400 verá Serial1.read en lugar de Serial.read. El material de referencia en el sitio web de Arduino ofrece una buena explicación. La tabla de la siguiente imagen muestra que se accede a los pines TX / RX de las placas MKR a través de Serial1.

https://www.arduino.cc/reference/en/language/functions/communication/serial/

Arduino Cloud

Este proyecto está configurado con 2 variables en Arduino Cloud. La siguiente imagen muestra cómo se muestran estas variables en el tablero de Arduino Cloud.

La primera variable denominada "dataStringCloud" es efectivamente un paquete de todos los datos del dispositivo. Este enfoque se adoptó en lugar de una variable para cada valor para simplificar el procesamiento de los datos en Google Sheets. Con nombres de variables individuales, era difícil diferenciar entre un valor que permanecía igual y un valor que no se actualizaba. Los datos de este paquete se analizan en Hojas de cálculo de Google.

La segunda variable denominada "pinCloud" se utiliza para controlar el MKR GSM 1400 desde Arduino Cloud. Hay una función de cambio en el boceto que controla la acción según el valor de pinCloud. Cuando pinCloud =1, el pin A1 se empuja hacia arriba, lo que hace que se encienda un LED en la placa. Cuando pinCloud =2, el pin A3 se empuja hacia arriba, lo que hace que Arduino Uno envíe los datos actuales como se describe anteriormente.

El código utilizado para Arduino MKR GSM 1400 en este proyecto se adjunta con comentarios que explican la información clave.

Nombre de archivo:"CommunicationsDevice"

Paso 4:Arduino Cloud a Google Sheets a través de Webhook

Los datos se transfieren desde Arduino Cloud a Google Sheets mediante un webhook.

El núcleo del webhook es la función doPost escrita en el script de un archivo de Hojas de cálculo de Google.

A continuación, se muestra un resumen rápido de cómo configurar el webhook. Tenga en cuenta que el proceso se inicia en Hojas de cálculo de Google. No llegas a Arduino Cloud hasta el final. Para ir de A a B, comience en B.

  • Cree un nuevo archivo de Hojas de cálculo de Google
  • Haga clic en "Herramientas" en la barra de herramientas y seleccione "Editor de secuencias de comandos" en el menú desplegable.
  • Escriba código con una función doPost (consulte GoogleSheetsScript.js adjunto a este proyecto)
  • Haga clic en "Publicar" en la barra de herramientas y seleccione "Implementar como aplicación web ..." en el menú desplegable.
  • Aparecerá un cuadro de diálogo con 3 campos.
  • (1) Versión del proyecto: Utilice siempre el menú desplegable para seleccionar "Nuevo". Después de la primera actualización, el número predeterminado será el de la versión actual; si no utiliza el menú desplegable para seleccionar "Nuevo", los cambios no entrarán en vigor.
  • (3) Quién tiene acceso a la aplicación: "Cualquiera, incluso anónimo"
  • Presione implementar después de verificar los valores en los 3 campos
  • Aparecerá un segundo cuadro de diálogo con la "URL actual de la aplicación web". Esta es la URL que copiará y pegará en la pestaña webhook en Arduino Cloud. Cabe señalar que esta URL permanece igual independientemente de la versión del proyecto.
  • Haga clic en Aceptar y listo.

Una buena parte del código JavaScript utilizado en este proyecto se basa en el código utilizado en otro proyecto llamado "Arduino IoT Cloud Google Sheets Integration". El enlace al proyecto se encuentra a continuación. Recomiendo echarle un vistazo.

https://create.arduino.cc/projecthub/Arduino_Genuino/arduino-iot-cloud-google-sheets-integration-71b6bc?ref=part&ref_id=64347&offset=9

Paso 5:utilice Hojas de cálculo de Google para analizar datos

Utilice Google Sheets para analizar los valores individuales de dataStringCloud y mostrar los registros únicos transferidos desde Arduino Cloud

El enlace a continuación es al archivo de Hojas de cálculo de Google utilizado para una prueba reciente del dispositivo. Las celdas de este archivo están coloreadas según cómo se poblaron, como se indica en la leyenda de cada hoja.

https://docs.google.com/spreadsheets/d/1XwCir2Llw8RvGPGgZI3Yk6U5a3LeIfUACNuO1Gr_LFQ/edit?usp=sharing

Paso 6:usa Hojas de cálculo de Google para enviar notificaciones

Es posible que haya notado que hay dos funciones en el archivo JavaScript para este proyecto (GoogleSheetsScript.js) mencionado anteriormente en el paso 4.

  • Función doPost:transmite datos desde Arduino Cloud Webhook. Se ejecuta cuando hay nuevos datos en Arduino Cloud.
  • Función sendEmail:envía correos electrónicos basados ​​en valores extraídos de la hoja denominada "Datos" en el archivo de Hojas de cálculo de Google para el proyecto. Se ejecuta una vez por minuto según la configuración de la configuración del disparador.

Pasos para configurar un disparador para la función sendEmail

  • Abra el archivo de Hojas de cálculo de Google
  • Haga clic en "Herramientas" en la barra de herramientas.
  • Seleccione "Editor de secuencias de comandos" en el menú desplegable.
  • Desde la ventana del editor de secuencias de comandos, vaya a:
  • Haga clic en "Editar" en la barra de herramientas.
  • Seleccione "Activadores del proyecto actual" en el menú desplegable.
  • Desde la ventana del Centro de desarrolladores de G Suite, vaya a:
  • Seleccione "Agregar activador" en la esquina inferior derecha de la ventana
  • En el cuadro de diálogo que aparece, haga selecciones para ejecutar la función sendEmail.
  • Nota:ejecutar el activador según el tiempo permite generar notificaciones por correo electrónico cuando el dispositivo deja de actualizarse.

Duración de la batería

~ 24 horas

Esto podría optimizarse apagando o quitando las pantallas. Otra opción sería eliminar sensores no esenciales como el DHT22 y el DS3231.

Uso de datos

~ 0,7 megabytes / día

Esto podría optimizarse reduciendo el tamaño o la frecuencia de las transmisiones de datos. Por ejemplo:para reducir el tamaño, envíe solo presión en lugar de presión, temperatura, humedad y tiempo. Para reducir la frecuencia, solo se actualiza cada hora en lugar de cada 30 minutos.

Costo del proyecto

Total =$ 241

  • Arduino MKR GSM 1400 ($ 70)
  • Arduino Uno ($ 22)
  • 2 baterías LiPo de 3,7 V ($ 30)
  • 2 x pantallas LED ($ 29)
  • Caja de plástico resistente a la intemperie ($ 22)
  • Sensor de presión ($ 19)
  • Sensor de temperatura / humedad - DHT22 ($ 10)
  • Módulo RTC:DS3231 ($ 5)
  • Convertidor elevador de voltaje ($ 5)
  • Convertidor de nivel lógico ($ 4)
  • Varios:LED, resistencias, cableado, etc. ($ 25)

Hardware / Herramientas

Todo el hardware y las herramientas que se utilizaron para este proyecto se adquirieron de las siguientes empresas:

  • Tienda online de Arduino (https://store.arduino.cc/)
  • Adafruit (https://www.adafruit.com/)
  • Amazon (https://www.amazon.com/)
  • Carga portuaria
  • Home Depot

En conclusión ...

Gracias por tomarse el tiempo para revisar este proyecto.

Todas y cada una de las preguntas / comentarios / comentarios / sugerencias son bienvenidos / apreciados.

Código

  • InstrumentReader - Sketch para Arduino Uno
  • GoogleSheetsScript.js
InstrumentReader - Sketch para Arduino Uno Arduino
 // Sketch 1 of 2 // Arduino Uno // Los datos son recopilados por este dispositivo y transmitidos al MKR 1400 a través de serie // El sensor DHT22 requiere 2 bibliotecas, pero solo se llama a una en el código. // (1):Biblioteca de sensores DHT:https://github.com/adafruit/DHT-sensor-library // (2):Biblioteca de sensores unificados de Adafruit:https://github.com/adafruit/Adafruit_Sensor #include  #include  #include  // RTC module # include  // DHT22 # ​​include "U8glib.h" // Velleman 128 x 64 OLED SPI Display // Nota:Otra biblioteca estándar de U8glib no funcionó cuando intenté usarla para esta pantalla. Funcionó cuando usé la biblioteca recomendada por el fabricante. // Biblioteca:https://www.velleman.eu/support/downloads/?code=VMA437 // Sintaxis:https://github.com/olikraus/u8glib/wiki/userreference &https://github.com/ olikraus / u8glib / wiki / thelloworld // # include  // Opción para guardar en la tarjeta SD en Ethernet Shield para Arduino UnoRTClib RTC; #define DHTPIN 11 // Pin digital conectado al sensor DHT # define DHTTYPE DHT22 / / DHT 22 (AM2302), AM2321DHT dht (DHTPIN, DHTTYPE); U8GLIB_SH1106_128X64 u8g (3, 4, 6, 7); // (CLK / SCK:3, MOSI:4, CS:6, DC (A0):7) // u8g (sck, mosi, cs, a0 [, reset]) int y_pos =0; // variable global // const int chipSelect =10; // Opción para guardar en la tarjeta SD en Ethernet Shield para Arduino Uno // float fileSizeSD =0.0; // Opción para guardar en tarjeta SD en Ethernet Shield para Arduino Unoint i =0; // Contar el número de lecturas tomadas por el Uno (igual que el número de bucles en el programa) const int ledPin =9; // indicador de transmisión (parpadea cuando se produce una transmisión de datos) const int ledPin2 =8; // empujar el indicador de transmisión (empujado hacia arriba con el botón manual en la placa de pruebas o la salida de MKR 1400 activada desde la nube) const int buttonPin =A1; int buttonState =0; int transmitFrequency =30; // Frecuencia de la cadena de datos de impresión en serie para enviar datos al segundo dispositivo (minutos) Cadena pTransmitDateTime =""; int transmitCounter =0; int pTransmitMinute =0; int ptriggerTransmitAlertIndicator; float cRuntimeAtTriggerStart =0.0; float dtLastTrigger =0.0;; int triggerTransmitAlertCounter =0; // Variables de entrada para controlar Triggerfloat lowTrigger =20.0; float highTrigger =40.0; float dtLastTriggerLimit =2.0; // Si la condición se cumple durante este período de tiempo, se generará una alertavoid setup (void) {Serial.begin (9600); Wire.begin (); dht.begin (); pinMode (ledPin, SALIDA); pinMode (ledPin2, SALIDA); pinMode (buttonPin, INPUT); u8g.setRot180 (); // voltear la pantalla, si es necesario (agregar / eliminar comentarios en esta línea para rotar) // Opción para guardar en la tarjeta SD en Ethernet Shield para Arduino Uno // Serial.print ("Inicializando tarjeta SD ..."); // if (! SD.begin (chipSelect)) // ver si la tarjeta está presente y se puede inicializar // {// Serial.println ("Tarjeta fallida o no presente"); // mientras (1); // no hagas nada más //} // Serial.println ("tarjeta inicializada.");} void loop (void) {delay (5000); DateTime ahora =RTC.now (); flotador cRuntime =millis () / 60000; float p =getPressure (); // Serial.println (p); buttonState =digitalRead (buttonPin); // Serial.print ("Botón:"); // Serial.println (buttonState); if (buttonState ==1) {digitalWrite (ledPin2, HIGH); retraso (30000); // demora para permitir que MKR1400 se prepare para recibir datos si MKR1400:pingPin presiona ALTO Uno:buttonPin} else {digitalWrite (ledPin2, LOW); } float h =dht.readHumidity (); flotar t =dht.readTemperature (verdadero); // t =dht.readTemperature (verdadero) -> temp si grados F &t =dht.readTemperature () -> temp si grados C int transmitIndicator =0; if (ahora.minuto ()% transmisiónFrecuencia ==0 &&ahora.minuto ()! =pTransmitMinuto) {transmitIndicator =1; pTransmitMinute =ahora.minuto (); pTransmitDateTime =Cadena (ahora.hora ()) + Cadena (":") + Cadena (ahora.minuto ()) + Cadena (":") + Cadena (ahora.segundo ()); } int triggerStatus =0; if (p <=lowTrigger || p>
 =highTrigger) {// Nota:la variable a la que se hace referencia en la condición para esto si la declaración se evalúa contra los puntos de ajuste altos y bajos // Es rápido para cambiar qué variable se evalúa - esta es la única ubicación donde se especifica la variable triggerStatus =1; triggerCounter ++; } más {triggerCounter =0; } if (triggerStatus ==1 &&triggerCounter ==1) {cRuntimeAtTriggerStart =cRuntime; } dtLastTrigger =cRuntime - cRuntimeAtTriggerStart; int triggerTransmitAlertIndicator =0; if ((dtLastTrigger> dtLastTriggerLimit) &&triggerStatus ==1) {triggerTransmitAlertIndicator =1; triggerTransmitAlertCounter ++; } más {triggerTransmitAlertCounter =0; } if (triggerTransmitAlertCounter> 0 &&triggerTransmitAlertCounter% 10 ==0) {flashLED (2500); } int triggerPushTransmitAlertIndicator =0; if ((triggerTransmitAlertIndicator ==1 &&triggerTransmitAlertCounter ==1) || ptriggerTransmitAlertIndicator! =triggerTransmitAlertIndicator) // if (TriggerStatus existió durante el tiempo mínimo especificado para Alert &Count =1 porque este es el primer ciclo mínimo especificado en el que el tiempo excedió el tiempo especificado time // O el estado de triggerAlert cambia - esto generará una alerta push si el TriggerStatus vuelve a 0, lo que significa que las condiciones de Trigger ya no se cumplen.) {triggerPushTransmitAlertIndicator =1; flashLED (5.500); retraso (5000); } ptriggerTransmitAlertIndicator =triggerTransmitAlertIndicator; // indicador actual almacenado en el indicador anterior. En el siguiente ciclo, el valor transferido aquí se comparará con el valor generado en función de los nuevos valores. // Crear cadenas String dataString =""; String cDateTime =""; String cHumTemp =""; String cP =""; dataString + ="<" + String (i) + "," + String (triggerTransmitAlertIndicator) + "," + String (dtLastTrigger, 0) + "," + String (buttonState) + "," + String (now.month ()) + "," + Cadena (ahora.día ()) + "," + Cadena (ahora.año ()) + "," + Cadena (ahora.hora ()) + "," + Cadena (ahora .minuto ()) + "," + Cadena (ahora.segundo ()) + "," + Cadena (h) + "," + Cadena (t) + "," + Cadena (p) + ">"; cDateTime + =String (now.month ()) + "/" + String (ahora.day ()) + "/" + String (ahora.year ()) + "" + String (ahora.hora ()) + ":" + Cadena (ahora.minuto ()) + ":" + Cadena (ahora.segundo ()); cHumTemp + ="H:" + Cadena (h) + "% T:" + Cadena (t) + "degF"; cP + ="P:" + Cadena (p) + "psi"; if (transmitIndicator ==1 || triggerPushTransmitAlertIndicator ==1 || buttonState ==1) {char dataArray [100]; dataString.toCharArray (dataArray, 100); Serial.println (dataArray); flashLED (10.500); transmitCounter ++; } // Serial.print ("T:"); // Serial.println (triggerStatus); retraso (100); // esperar un poco a que llegue el mensaje completo // bucle de imagen u8g.firstPage (); do {dibujar (cDateTime, cHumTemp, cP, i, transmitCounter, now.minute (), transmitFrequency, pTransmitMinute); } while (u8g.nextPage ()); retraso (1000); // writeToSD (dataString); // Opción para guardar en la tarjeta SD en Ethernet Shield para Arduino Uno i ++;} void draw (String DcDateTime, String DcHumTemp, String DcP, int Di, int DtransmitCounter, int DnowMinute, int DtransmitFrequency, int DpTransmitMinute) {u8g.begin (); u8g.setFont (u8g_font_5x7); // u8g_font_micro // u8g_font_5x7 // u8g_font_5x8 // u8g_font_6x10 u8g.setFontPosTop (); u8g.setPrintPos (0,0); u8g.print (DcDateTime); u8g.setPrintPos (0,8); u8g.print (2); u8g.setPrintPos (10,8); u8g.print (DcHumTemp); u8g.setPrintPos (0,16); u8g.print ("3 #:"); u8g.setPrintPos (30,16); u8g.print (Di); u8g.setPrintPos (50,16); u8g.print (DcP); u8g.setPrintPos (0,24); u8g.print ("4 #t:"); u8g.setPrintPos (30,24); u8g.print (DtransmitCounter); u8g.setPrintPos (50,24); u8g.print ("tFreq:"); u8g.setPrintPos (83,24); u8g.print (DtransmitFrequency); u8g.setPrintPos (0,32); u8g.print (5); u8g.setPrintPos (10,32); u8g.print ("ahoraMinuto:"); u8g.setPrintPos (70,32); u8g.print (DnowMinute); u8g.setPrintPos (0,40); u8g.print (6); u8g.setPrintPos (10,40); u8g.print ("pTransmitMinute:"); u8g.setPrintPos (95,40); u8g.print (DpTransmitMinute); u8g.setPrintPos (0,48); u8g.print (7); u8g.setPrintPos (10,48); u8g.print ("Resto:"); u8g.setPrintPos (70, 48); u8g.print (DnowMinute% DtransmitFrequency);} float getPressure () {int sensorVal =analogRead (A2); // Serial.print ("Valor del sensor:"); // Serial.print (sensorVal); voltaje de flotación =(sensorVal * 5.0) /1023.0; // Serial.print ("Voltios:"); // Serial.print (voltaje); // Cuando Presión =0, Entrada Analógica =100 // Conversión de Entrada Analógica a Voltaje:Entrada Analógica =100 -> Voltaje =100 * (5/1023) =0.4889 float m =((150-0) / (4.5- 0,4889)); float b =150 - (m * 4.5); // Serial.print ("m ="); // Serial.print (m); // Serial.print ("b ="); // Serial.print ( B); flotador presión_psi =((m * voltaje) + b); // Serial.print ("Presión ="); // Serial.print (presión_psi); // Serial.println ("psi"); // retraso (200); return presión_psi;} void flashLED (int num, int t) {for (int z =1; z <=num; z ++) {digitalWrite (ledPin, HIGH); retraso (t); digitalWrite (ledPin, BAJO); retraso (t); }} // Opción para guardar en la tarjeta SD en Ethernet Shield para Arduino Uno // void writeToSD (String dataToWrite) // {// // abre el archivo. tenga en cuenta que solo se puede abrir un archivo a la vez, // // por lo que debe cerrar este antes de abrir otro. // Archivo dataFile =SD.open ("datalog4.txt", FILE_WRITE); // fileSizeSD =dataFile.size (); // Devuelve el tamaño del archivo en bytes // fileSizeSD =fileSizeSD / 1000000; // Convierte bytes a MB. 1 MB =1e6 bytes // // si el archivo está disponible, escríbalo:// if (dataFile) // {// dataFile.println (dataToWrite); // dataFile.close (); // // imprime también en el puerto serie:// // Serial.println (dataToWrite); //} // // si el archivo no está abierto, aparece un error:// else // {// Serial.println ("error al abrir datalog1.txt"); //} //} 
GoogleSheetsScript.js JavaScript
 // Hay 2 funciones en este código // Función doPost - Transmite datos desde Arduino Cloud Webhook. Se ejecuta cuando hay nuevos datos en Arduino Cloud.// función sendEmail - Envía correos electrónicos basados ​​en valores extraídos de la hoja llamada "Datos" en el archivo de Google Sheets para el proyecto. Se ejecuta una vez por minuto según la configuración de la configuración del disparador. Para obtener instrucciones, consulte la parte de la función sendEmail de la publicación del centro del proyecto .// La mayoría de este código (aparte de la función sendEmail) se basa en el siguiente proyecto en el Centro de proyectos de Arduino // https://create.arduino. cc / projecthub / Arduino_Genuino / arduino-iot-cloud-google-sheets-integration-71b6bc? f =1 // Este es un enlace a un repositorio de GitHub con el script de Google utilizado para el proyecto mencionado anteriormente en Project Hub. // Este enlace fue copiado de la descripción del proyecto en Project Hub.// https://github.com/arduino/arduino-iot-google-sheet-script/blob/master/Code.gs// ponerse activo spreasheetvar ss =SpreadsheetApp.getActiveSpreadsheet (); // obtener la hoja llamada RawDatavar sheet =ss.getSheetByName ("RawData"); var sd =ss.getSheetByName ("Data"); var sref =ss.getSheetByName ("References"); var MAX_ROWS =1440; // número máximo de filas de datos para mostrar // 3600s / cloud_int (30s) * num_ore (12h) =(60 * 60 * 12) / 30 =(3600 * 12) / 30 =1440 lecturas en 12 horas a 30 segundos de actualización intervalo // (60 * 24) / 15 =96 lecturas en un período de 24 horas con un intervalo de actualización de 15 minutos // 15 días * 96 lecturas / día =1440 lecturas // 90 días * 96 lecturas / día =8640 lecturas // 365 días * 96 lecturas / día =35040 lecturas var HEADER_ROW =1; // índice de fila de headervar TIMESTAMP_COL =1; // índice de columna de la función de columna de marca de tiempo doPost (e) {var cloudData =JSON.parse (e.postData.contents); // este es un objeto json que contiene toda la información proveniente de IoT Cloud console.log (cloudData); // var webhook_id =cloudData.webhook_id; // realmente no utilizo estos tres // var device_id =cloudData.device_id; // var id_objetivo =cloudData.thing_id; var valores =cloudData.values; // esta es una matriz de objetos json console.log (valores); // Almacenar nombres y valores de la matriz de valores // Cada propiedad entrante tiene un:// nombre que se convertirá en los nombres de columna // valor que se escribirá en las filas debajo del encabezado de columna var incLength =values.length; var incNames =[]; var incValues ​​=[]; for (var i =0; i  2018) {// descartar todos los mensajes que lleguen 'tarde' if (sheet.getRange (HEADER_ROW + 1, 1) .getValue ()! ='') {// HEADER_ROW + 1 =Fila # 2 &Columna # 1 -> esta es la ubicación de la marca de tiempo más reciente en la hoja // Si la marca de tiempo más reciente no está en blanco =(''), compare la hora actual con la marca de tiempo de los datos entrantes // Si la marca de tiempo más reciente está en blanco, lo más probable es que sea la primera vez que el script se ejecuta. // En este caso, omita esta instrucción if y proceda a escribir en los encabezados y datos de las columnas. // No importa si los datos llegan tarde (hora actual frente a la marca de tiempo de los datos entrantes). var ahora =nueva fecha (); // ahora var COMM_TIME =120; // Nota:cambiado a 120 para permitir que lleguen más mensajes, previamente establecido en 5 segundos y funcionó bien // Sobreestimación aproximada del tiempo de comunicación entre la nube y la aplicación if (now.getTime () - date.getTime ()> COMM_TIME * 1000) {// Si la diferencia entre la hora actual y la marca de tiempo es superior a 5 segundos, descarte los datos. // Cuando la condición en esta declaración If se evalúa como verdadera, la función se detendrá debido a la declaración de retorno. regreso; // "La declaración de retorno detiene la ejecución de una función y devuelve un valor de esa función". }} // Esta sección escribe valores en la fila del encabezado según los nombres de las propiedades entrantes // En otras palabras, esta sección crea los nombres de las columnas // Asigna un nombre a la celda que está en la fila del encabezado y en la primera columna =hoja de marca de tiempo.getRange (HEADER_ROW, 1) .setValue ('marca de tiempo'); for (var i =0; i  es 2 // la columna 1 es la columna de marca de tiempo. if (lastCol ==1) {// escribe los nombres de las columnas que comienzan con la columna después de lastCol ==1 que es la columna de marca de tiempo // incNames es una matriz que contiene los nombres de todas las propiedades entrantes // Si lastCol ==1 , escriba el valor de la 'i' ubicación en la matriz incNames a la fila del encabezado en la columna # 2 =lastCol + 1 sheet.getRange (HEADER_ROW, lastCol + 1) .setValue (incNames [i]); } else {// evaluado si lastCol! =1 // verifica si el nombre ya está en el encabezado var found =0; for (var col =2; col <=lastCol; col++) { // starting with column 2, iterate through all of the columns up to the lastCol evaluating the if statement enclosed if (sheet.getRange(HEADER_ROW, col).getValue() ==incNames[i]) { // the condition of this If statement compares the value in the header row &column # =col to the 'i'th value in the array of incoming property names // This if statement is evaulated for each iteration of the for loop that it is enclosed in. // The condition is evaluated for all of the columns from column #2 to the last column. // It is checking to see if the 'i'th value in the incNames array exists in any of the columns in the header row. // If the 'i'th value in the incNames array finds a match to any of the values in the header row, set found =1 &exit the for loop with the break statment. found =1; descanso; // "The break statement breaks the loop and continues executing the code after the loop" } // close if statement evaluated for each iteration of the for loop that it is enclosed in. } // close for loop to check the 'i'th value in the incNames array to the values in the header row. if (found ==0) { // This If statemnt will be evaluated after the preceeding for loop has completed. // If found ==0 it means that the 'i'th value in the incNames array did not match any of the existing values in the header row. // If found ==0, write the 'i'th value in the incNames array to the column after the last column. // If new properties are added to the incoming data over time, the existing columns will not be impacted. The new property will be added to the column after the last column. sheet.getRange(HEADER_ROW, lastCol+1).setValue(incNames[i]); } // close if statement } // close else, since this is the end of the code block inside the main for loop, the next i will be evaluated up to i =incLength // The block of code inside this for loop is evaluated for each value at location i in the incNames array. // The values of i range from 0 to incLength (the number of values in the names array) // In JavaScript the index in arrays starts at 0. In other words, the 1st value in the array is at location =0. } // close main for loop used to write column names (assigning values from names array to header row) // redefine last coloumn and last row since new names could have been added var lastCol =sheet.getLastColumn(); var lastRow =sheet.getLastRow(); // delete last row to maintain constant the total number of rows if (lastRow> MAX_ROWS + HEADER_ROW - 1) { sheet.deleteRow(lastRow); } // insert new row after deleting the last one sheet.insertRowAfter(HEADER_ROW); // reset style of the new row, otherwise it will inherit the style of the header row var range =sheet.getRange('A2:Z2'); //range.setBackground('#ffffff'); range.setFontColor('#000000'); range.setFontSize(10); range.setFontWeight('normal'); // write the timestamp sheet.getRange(HEADER_ROW+1, TIMESTAMP_COL).setValue(date).setNumberFormat("yyyy-MM-dd HH:mm:ss"); // write values in the respective columns for (var col =1+TIMESTAMP_COL; col <=lastCol; col++) { // for loop to assign the value from incValues to the approrpriate column // This block of code was replaced by an if statement checking for blank values after the incoming data is populated. // Copy previous values // This is to avoid empty cells if not all properties are updated at the same time // sheet.getRange(HEADER_ROW+1, col).setValue(sheet.getRange(HEADER_ROW+2, col).getValue()); for (var i =0; i  2018), used to eliminate dupicate messages from the Arduino Cloud} // close doPost functionfunction sendEmail (){ var emailAddress =sd.getRange("V3").getValue(); var lastPressure =sd.getRange("K3").getValue(); // pressure at last update var lastUpdate =sd.getRange("A3").getValue(); // datetime of last update var ssLink ="https://docs.google.com/spreadsheets/d/1XwCir2Llw8RvGPGgZI3Yk6U5a3LeIfUACNuO1Gr_LFQ/edit#gid=1123486497"; var triggerAlertCount =sd.getRange("L6").getValue(); var triggerMonitor =sd.getRange("M3").getValue(); var dtLastStatusChange =sd.getRange("P3").getValue(); var dtLastDeviceUpdate1 =sd.getRange("S3").getValue(); var dtLastDeviceUpdate2 =sd.getRange("S4").getValue(); var emailSentNoUpdate =sd.getRange("T3").getValue(); var emailSentStartedReading =sd.getRange("U3").getValue(); var message ="Last Device Update:" + "\n" + lastUpdate + "\n\n" + " Last Pressure:" + "\n\t" + lastPressure.toFixed(2) + " psi" + "\n\n" + " Link to Spreadsheet:" + "\n\t" + ssLink; if(triggerMonitor ==0){ sd.getRange("L5").setValue(0); sd.getRange("L6").setValue(0); } if(triggerMonitor ==-1 &&triggerAlertCount <=4){ sd.getRange("L3").setValue(lastUpdate); // emailSent sd.getRange("L5").setValue(-1); sd.getRange("L6").setValue(triggerAlertCount + 1); var subject ="Status Change Alert - Outside Setpoints"; MailApp.sendEmail(emailAddress, subject, message); } if(triggerMonitor ==1 &&triggerAlertCount <=4){ sd.getRange("L3").setValue(lastUpdate); // emailSent sd.getRange("L5").setValue(1); sd.getRange("L6").setValue(triggerAlertCount + 1); var subject ="Status Change Alert - Normal"; MailApp.sendEmail(emailAddress, subject, message); } if(emailSentNoUpdate ==0 &&dtLastDeviceUpdate1> 60 &&dtLastDeviceUpdate2> 60){ sd.getRange("T3").setValue(1); // emailSentNoUpdate sd.getRange("U3").setValue(0); // emailSentStartedReading sd.getRange("T4").setValue(now.getTime()); // emailSentNoUpdate var subject ="Alert - Over 60 minutes Since Last Device Update"; MailApp.sendEmail(emailAddress, subject, message); } if(emailSentNoUpdate ==1 &&dtLastDeviceUpdate1 <60){ // removed the following from the condition:&&dtLastDeviceUpdate2> 60 sd.getRange("T3").setValue(0); // emailSentNoUpdate sd.getRange("U3").setValue(1); // emailSentStartedReading sd.getRange("U4").setValue(now.getTime()); // emailSentStartedReading var subject ="Alert - Device Started Updating"; MailApp.sendEmail(emailAddress, subject, message); }} 
CommunicationsDevice - Sketch for MKR 1400

Esquemas


Proceso de manufactura

  1. ADLINK se asocia con Google Cloud para ofrecer soluciones listas para IoT
  2. IoT básico - RaspberryPI HDC2010 cómo
  3. Sensor de presión barométrica digital BMP180 I2C
  4. Python / MicroPython Sensor Logger con Google Sheets
  5. Windows 10 IoT Core en Raspberry Pi 2 - Datos del sensor Adafruit
  6. Windows 10 IoT Core y SHT15
  7. UnifiedWater v1
  8. IOT - Smart Jar usando ESP8266, Arduino y sensor ultrasónico
  9. Torre de sensores de nubes Arduino
  10. Arduino Apple Watch
  11. Control total de su televisor con Alexa y Arduino IoT Cloud