Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Sensor de pressão IoT:MKR GSM + Arduino Cloud + Planilhas Google

Componentes e suprimentos

Arduino UNO
× 1
Arduino MKR GSM 1400
× 1
Transdutor de pressão (0-150 psi)
× 1
Sensor de temperatura e umidade Adafruit DHT22
× 1
Módulo DS3231 RTC
× 1
Adafruit Logic Level Converter - BSS138 - 4 canais I2C-safe Bidirecional
× 1
Bateria LiPo Adafruit 3,7 V (2000 mAh ou superior)
× 2
Conversor de aumento de tensão
× 1
Kit básico para iniciantes com LEDs e resistores variados
× 1
Breadboard (genérico)
× 1

Aplicativos e serviços online

Planilhas Google
Arduino IoT Cloud
Arduino Web Editor
Arduino IDE

Sobre este projeto





Objetivo


O objetivo deste projeto foi criar um protótipo de um dispositivo de baixo custo para monitorar a pressão em equipamentos industriais em locais remotos usando dados celulares.












Passo a passo do projeto


A seguir, uma explicação passo a passo do projeto, seguindo o fluxo de dados do transdutor de pressão até a notificação por e-mail gerada pelo script anexado ao Planilhas Google.





Etapa 1:Transdutor de pressão para Uno


O transdutor de pressão converte a pressão em um sinal elétrico analógico.

O Arduino Uno converte o sinal analógico do transdutor de pressão em pressão (psi).





Etapa 2:Uno para MKR GSM 1400 via serial


Ao se comunicar entre dois dispositivos Arduino via serial:
  • Conecte RX no dispositivo nº 1 ao TX no dispositivo nº 2
  • Conecte TX no dispositivo nº 1 ao RX no dispositivo nº 2
  • Os dispositivos devem ter um terreno comum

Frequência de transmissão de dados (Uno para MKR GSM 1400)
  • NORMAL: A cada 30 minutos (transmitFrequency), o Uno fará a serial.print os dados para o MKR GSM 1400, que transmitirá os dados para a nuvem.
  • HIGH / LOW TRIGGER: Se a pressão ficar acima de 40 psi (highTrigger) ou abaixo de 20 psi (lowTrigger) e permanecer lá por mais de 2 minutos (dtLastTriggerLimit), o Uno irá serializar os dados de impressão para o MKR GSM 1400, que transmitirá os dados para a nuvem.
  • PESQUISA DE DEMANDA: Se o pino A1 no Uno for pressionado para cima, ele imprimirá os dados em série para o MKR GSM 1400, que transmitirá os dados para a nuvem. Nota:o pino A1 é denominado "buttonPin" no esboço do Uno. Existem 2 maneiras de o pino A1 no Uno ser empurrado para cima. (1) Há um botão de pressão na placa de ensaio. (2) Se o pino A3 no MKR GSM 1400 estiver alto, ele empurrará o pino A1 para cima. Como o pino A3 é controlado por uma entrada no Arduino Cloud, a pressão atual pode ser obtida remotamente a qualquer momento, sem ter que esperar por uma transmissão de dados programada regularmente.

Notas
  • O esboço do Uno pode ser modificado para que várias entradas como temperatura, umidade, voltagem da bateria, etc. possam ser monitoradas com pontos de ajuste altos e baixos, além da pressão na versão atual.
  • O código usado para converter o sinal analógico do transdutor de pressão em pressão (psi) é baseado nas instruções fornecidas no seguinte vídeo do YouTube:https://www.youtube.com/watch?v=AB7zgnfkEi4
  • A postagem a seguir no Fórum do Arduino cobrindo "Fundamentos da entrada serial" foi muito útil quando se tratou de escrever o código para se comunicar de um dispositivo para outro usando dados seriais:https://forum.arduino.cc/index. php? topic =288234.0

O código usado para o Arduino Uno neste projeto é anexado com comentários que explicam as principais informações.

Nome do arquivo:"InstrumentReader"





Etapa 3:MKR GSM 1400 para Arduino Cloud via celular


O MKR GSM 1400 processa dados seriais do Arduino Uno e os transmite para o Arduino Cloud usando dados de celular.

É importante notar que no código do MKR GSM 1400 você verá Serial1.read em oposição a Serial.read. O material de referência no site do Arduino oferece uma boa explicação. A tabela da imagem abaixo mostra que os pinos TX / RX nas placas MKR são acessados ​​via Serial1.

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

Arduino Cloud

Este projeto é configurado com 2 variáveis ​​no Arduino Cloud. A imagem abaixo mostra como essas variáveis ​​são exibidas no painel do Arduino Cloud.

A primeira variável chamada "dataStringCloud" é efetivamente um pacote de todos os dados do dispositivo. Essa abordagem foi usada em oposição a uma variável para cada valor para simplificar o processamento dos dados no Planilhas Google. Com nomes de variáveis ​​individuais, era difícil dizer a diferença entre um valor permanecer o mesmo e um valor que não foi atualizado. Os dados deste pacote são analisados ​​no Planilhas Google.

A segunda variável chamada "pinCloud" é usada para controlar o MKR GSM 1400 do Arduino Cloud. Há uma função de troca no esboço que controla a ação com base no valor de pinCloud. Quando pinCloud =1, o pino A1 é pressionado para cima, fazendo com que um LED na placa se acenda. Quando pinCloud =2, o pino A3 é empurrado para cima, o que leva o Arduino Uno a enviar os dados atuais conforme descrito acima.

O código usado para o Arduino MKR GSM 1400 neste projeto é anexado com comentários que explicam as principais informações.

Nome do arquivo:"CommunicationsDevice"





Etapa 4:Arduino Cloud para Planilhas Google via Webhook


Os dados são transferidos do Arduino Cloud para o Google Sheets usando um webhook.

O núcleo do webhook é a função doPost escrita no script de um arquivo do Planilhas Google.

Aqui está um rápido resumo de como configurar o webhook. Observe que o processo começa no Planilhas Google. Você não chega ao Arduino Cloud até o final. Para ir de A a B, comece em B.
  • Crie um novo arquivo do Planilhas Google
  • Clique em "Ferramentas" na barra de ferramentas e selecione "Editor de scripts" no menu suspenso
  • Escreva o código com uma função doPost (consulte GoogleSheetsScript.js anexado a este projeto)
  • Clique em "Publicar" na barra de ferramentas e selecione "Implementar como aplicativo da web ..." no menu suspenso
  • Uma caixa de diálogo aparecerá com 3 campos.
  • (1) Versão do projeto: Sempre use a lista suspensa para selecionar "Novo". Após a primeira atualização, o padrão será o # da versão atual; se você não usar o menu suspenso para selecionar "Novo", as alterações não entrarão em vigor.
  • (3) Quem tem acesso ao aplicativo: "Qualquer um, mesmo anônimo"
  • Pressione implantar após verificar os valores nos 3 campos
  • Uma segunda caixa de diálogo aparecerá com o "URL do aplicativo da web atual". Este é o URL que você copiará e colará na guia webhook no Arduino Cloud. Vale a pena notar que este URL permanece o mesmo, independentemente da versão do projeto.
  • Clique em ok e pronto!

Uma boa parte do código JavaScript usado neste projeto é modelado após o código usado em outro projeto chamado "Arduino IoT Cloud Google Sheets Integration". O link para o projeto está abaixo. Eu recomendo dar uma olhada.

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





Etapa 5:use o Planilhas Google para analisar dados


Use o Planilhas Google para analisar os valores individuais de dataStringCloud e exibir os registros exclusivos transferidos da nuvem Arduino

O link abaixo é para o arquivo do Planilhas Google usado para um teste recente do dispositivo. As células neste arquivo são coloridas com base em como foram preenchidas conforme indicado na legenda de cada folha.

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





Etapa 6:use o Planilhas Google para enviar notificações


Você deve ter notado que há duas funções no arquivo JavaScript para este projeto (GoogleSheetsScript.js) referenciado acima na etapa 4.
  • função doPost - Transmite dados do Arduino Cloud Webhook. Ele é executado quando há novos dados no Arduino Cloud.
  • função sendEmail - Envia e-mails com base em valores extraídos da planilha chamada "Dados" no arquivo do Planilhas Google para o projeto. Ele é executado uma vez a cada minuto com base nas configurações da configuração do acionador.

Passos para configurar um gatilho para a função sendEmail
  • Abra o arquivo do Planilhas Google
  • Clique em "Ferramentas" na barra de ferramentas
  • Selecione "Editor de scripts" no menu suspenso
  • Na janela do editor de scripts, prossiga para:
  • Clique em "Editar" na barra de ferramentas
  • Selecione "Gatilhos do projeto atual" no menu suspenso
  • Na janela do G Suite Developer Hub, prossiga para:
  • Selecione "Adicionar acionador" no canto inferior direito da janela
  • Na caixa de diálogo que aparece, faça as seleções para executar a função sendEmail.
  • Observação:a execução do gatilho com base no tempo possibilita a geração de notificações por e-mail quando o dispositivo para de atualizar.





Vida útil da bateria


~ 24 horas

Isso pode ser otimizado desligando ou removendo os visores. Outra opção seria remover sensores não essenciais como o DHT22 e o DS3231.





Uso de dados


~ 0,7 megabytes / dia

Isso pode ser otimizado reduzindo o tamanho ou a frequência das transmissões de dados. Por exemplo:Para reduzir o tamanho reduzido, envie apenas pressão, em vez de pressão, temperatura, umidade e tempo. Para reduzir a frequência, atualizações apenas de hora em hora, em vez de a cada 30 minutos.





Custo do projeto


Total =$ 241
  • Arduino MKR GSM 1400 ($ 70)
  • Arduino Uno ($ 22)
  • 2 baterias LiPo de 3,7 V ($ 30)
  • 2 x monitores LED (US $ 29)
  • Caixa de plástico resistente a intempéries (US $ 22)
  • Sensor de pressão ($ 19)
  • Sensor de temperatura / umidade - DHT22 (US $ 10)
  • Módulo RTC - DS3231 ($ 5)
  • Conversor de aumento de tensão ($ 5)
  • Conversor de nível lógico (US $ 4)
  • Diversos - LEDs, resistores, fiação, etc. (US $ 25)





Hardware / Ferramentas


Todo o hardware e ferramentas usados ​​para este projeto foram adquiridos do seguinte:
  • Arduino Online Store (https://store.arduino.cc/)
  • Adafruit (https://www.adafruit.com/)
  • Amazon (https://www.amazon.com/)
  • Frete portuário
  • Home Depot





Em conclusão ...


Obrigado por reservar um tempo para revisar este projeto.

Todas e quaisquer perguntas / feedback / comentários / sugestões são bem-vindos / apreciados.

Código

  • InstrumentReader - Sketch para Arduino Uno
  • GoogleSheetsScript.js
InstrumentReader - Sketch para Arduino Uno Arduino
 // Esboço 1 de 2 // Arduino Uno // Os dados são coletados por este dispositivo e transmitidos ao MKR 1400 via serial // O sensor DHT22 requer 2 bibliotecas, mas apenas uma é chamada no código. // (1):Biblioteca de sensores DHT:https://github.com/adafruit/DHT-sensor-library // (2):Biblioteca de sensores unificados Adafruit:https://github.com/adafruit/Adafruit_Sensor #include  #include  #include  // Módulo RTC # include  // DHT22 # ​​include "U8glib.h" // Velleman 128 x 64 OLED SPI Display // Nota:Outra biblioteca U8glib padrão não funcionou quando tentei usá-la para esta exibição. Funcionou quando usei a biblioteca recomendada pelo fabricante. // Biblioteca:https://www.velleman.eu/support/downloads/?code=VMA437 // Sintaxe:https://github.com/olikraus/u8glib/wiki/userreference &https://github.com/ olikraus / u8glib / wiki / thelloworld // # include  // Opção para salvar no cartão SD no Ethernet Shield para Arduino UnoRTClib RTC; #define DHTPIN 11 // Pino digital conectado ao 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 [, redefinir]) int y_pos =0; // variável global // const int chipSelect =10; // Opção para salvar no cartão SD no Ethernet Shield para Arduino Uno // float fileSizeSD =0.0; // Opção para salvar no cartão SD no Ethernet Shield para Arduino Unoint i =0; // Contar # de leituras feitas pelo Uno (igual a # loops no programa) const int ledPin =9; // indicador de transmissão (pisca quando ocorre uma transmissão de dados) const int ledPin2 =8; // empurra o indicador de transmissão (pressionado pelo botão manual no breadboard ou saída do MKR 1400 ativado da nuvem) const int buttonPin =A1; int buttonState =0; int transmitFrequency =30; // Frequência de impressão serial dataString para enviar dados para o segundo dispositivo (minutos) String pTransmitDateTime =""; int transmitCounter =0; int pTransmitMinute =0; int ptriggerTransmitAlertIndicator; float cRuntimeAtTriggerStart =0.0; float dtLastTrigger =0.0 int triggerCounter =0.0;; int triggerTransmitAlertCounter =0; // Variáveis ​​de entrada para controlar Triggerfloat lowTrigger =20,0; float highTrigger =40,0; float dtLastTriggerLimit =2,0; // Se a condição for atendida por esse período de tempo, um alerta será gerado para evitar a configuração (void) {Serial.begin (9600); Wire.begin (); dht.begin (); pinMode (ledPin, OUTPUT); pinMode (ledPin2, OUTPUT); pinMode (buttonPin, INPUT); u8g.setRot180 (); // virar a tela, se necessário (adicionar / remover comentários nesta linha para girar) // Opção para salvar no cartão SD no Ethernet Shield para Arduino Uno // Serial.print ("Inicializando o cartão SD ..."); // if (! SD.begin (chipSelect)) // veja se o cartão está presente e pode ser inicializado // {// Serial.println ("O cartão falhou ou não está presente"); // enquanto (1); // não faça mais nada //} // Serial.println ("cartão inicializado.");} void loop (void) {delay (5000); DateTime agora =RTC.now (); float cRuntime =millis () / 60000; float p =getPressure (); // Serial.println (p); buttonState =digitalRead (buttonPin); // Serial.print ("Button:"); // Serial.println (buttonState); if (buttonState ==1) {digitalWrite (ledPin2, HIGH); atraso (30000); // demora para permitir que o MKR1400 se prepare para receber dados se Uno:buttonPin for pressionado HIGH por MKR1400:pingPin} else {digitalWrite (ledPin2, LOW); } float h =dht.readHumidity (); float t =dht.readTemperature (true); // t =dht.readTemperature (true) -> temp se graus F &t =dht.readTemperature () -> temp se graus C int transmitIndicator =0; if (now.minute ()% transmitFrequency ==0 &&now.minute ()! =pTransmitMinute) {transmitIndicator =1; pTransmitMinute =now.minute (); pTransmitDateTime =String (now.hour ()) + String (":") + String (now.minute ()) + String (":") + String (now.second ()); } int triggerStatus =0; if (p <=lowTrigger || p>
 =highTrigger) {// Observação:a variável referenciada na condição para esta instrução if é avaliada em relação aos pontos de ajuste altos e baixos // É rápido alterar qual variável é avaliada - este é o único local onde a variável é especificada triggerStatus =1; triggerCounter ++; } else {triggerCounter =0; } if (triggerStatus ==1 &&triggerCounter ==1) {cRuntimeAtTriggerStart =cRuntime; } dtLastTrigger =cRuntime - cRuntimeAtTriggerStart; int triggerTransmitAlertIndicator =0; if ((dtLastTrigger> dtLastTriggerLimit) &&triggerStatus ==1) {triggerTransmitAlertIndicator =1; triggerTransmitAlertCounter ++; } else {triggerTransmitAlertCounter =0; } if (triggerTransmitAlertCounter> 0 &&triggerTransmitAlertCounter% 10 ==0) {flashLED (2.500); } int triggerPushTransmitAlertIndicator =0; if ((triggerTransmitAlertIndicator ==1 &&triggerTransmitAlertCounter ==1) || ptriggerTransmitAlertIndicator! =triggerTransmitAlertIndicator) // if (TriggerStatus existiu por tempo mínimo especificado para Alerta &Contagem =1 medindo que este é o primeiro loop em que o tempo excedeu o mínimo especificado time // OU as mudanças de status do triggerAlert - isto irá gerar um alerta push se o TriggerStatus voltar a 0, significando que as condições do Trigger não são mais atendidas.) {triggerPushTransmitAlertIndicator =1; flashLED (5.500); atraso (5000); } ptriggerTransmitAlertIndicator =triggerTransmitAlertIndicator; // indicador atual armazenado no indicador anterior. No próximo loop, o valor transferido aqui será comparado ao valor gerado com base nos novos valores. // Criar strings String dataString =""; String cDateTime =""; String cHumTemp =""; String cP =""; dataString + ="<" + String (i) + "," + String (triggerTransmitAlertIndicator) + "," + String (dtLastTrigger, 0) + "," + String (buttonState) + "," + String (now.month ()) + "," + String (now.day ()) + "," + String (now.year ()) + "," + String (now.hour ()) + "," + String (now .minute ()) + "," + String (now.second ()) + "," + String (h) + "," + String (t) + "," + String (p) + ">"; cDateTime + =String (now.month ()) + "/" + String (now.day ()) + "/" + String (now.year ()) + "" + String (now.hour ()) + ":" + String (now.minute ()) + ":" + String (now.second ()); cHumTemp + ="H:" + String (h) + "% T:" + String (t) + "degF"; cP + ="P:" + String (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); atraso (100); // espera um pouco até que toda a mensagem chegue // loop de imagem u8g.firstPage (); fazer {desenhar (cDateTime, cHumTemp, cP, i, transmitCounter, now.minute (), transmitFrequency, pTransmitMinute); } while (u8g.nextPage ()); atraso (1000); // writeToSD (dataString); // Opção para salvar no cartão SD em 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 ("nowMinute:"); 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 ("Restante:"); u8g.setPrintPos (70,48); u8g.print (DnowMinute% DtransmitFrequency);} float getPressure () {int sensorVal =analogRead (A2); // Serial.print ("Sensor Value:"); // Serial.print (sensorVal); tensão flutuante =(sensorVal * 5.0) /1023.0; // Serial.print ("Volts:"); // Serial.print (tensão); // Quando Pressão =0, Entrada Analógica =100 // Conversão de Entrada Analógica em Tensão:Entrada Analógica =100 -> Tensão =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); float pressure_psi =((m * voltagem) + b); // Serial.print ("Pressão ="); // Serial.print (pressure_psi); // Serial.println ("psi"); // atraso (200); return pressure_psi;} void flashLED (int num, int t) {for (int z =1; z <=num; z ++) {digitalWrite (ledPin, HIGH); atraso (t); digitalWrite (ledPin, LOW); atraso (t); }} // Opção para salvar no cartão SD no Ethernet Shield para Arduino Uno // void writeToSD (String dataToWrite) // {// // abre o arquivo. observe que apenas um arquivo pode ser aberto por vez, // // portanto, você deve fechar este antes de abrir outro. // Arquivo dataFile =SD.open ("datalog4.txt", FILE_WRITE); // fileSizeSD =dataFile.size (); // Retorna o tamanho do arquivo em bytes // fileSizeSD =fileSizeSD / 1000000; // Converte bytes em MB. 1 MB =1e6 bytes // // se o arquivo estiver disponível, escreva nele:// if (dataFile) // {// dataFile.println (dataToWrite); // dataFile.close (); // // imprime também na porta serial:// // Serial.println (dataToWrite); //} // // se o arquivo não estiver aberto, aparece um erro:// else // {// Serial.println ("erro ao abrir datalog1.txt"); //} //} 
GoogleSheetsScript.js JavaScript
 // Existem 2 funções neste código // função doPost - Transmite dados do Arduino Cloud Webhook. Ele é executado quando há novos dados na função Arduino Cloud.// sendEmail - Envia e-mails com base nos valores extraídos da planilha chamada "Dados" no arquivo do Planilhas Google para o projeto. Ele é executado uma vez a cada minuto com base nas configurações da configuração do acionador. Para obter instruções, consulte a parte da função sendEmail do hub do projeto post.// A maior parte desse código (além da função sendEmail) é modelada após o seguinte projeto no hub do projeto Arduino // https://create.arduino. cc / projecthub / Arduino_Genuino / arduino-iot-cloud-google-sheets-integration-71b6bc? f =1 // Este é um link para um repositório GitHub com o Google Script usado para o projeto mencionado acima no Project Hub. // Este link foi copiado da descrição do projeto no Project Hub.// https://github.com/arduino/arduino-iot-google-sheet-script/blob/master/Code.gs// get active spreasheetvar ss =SpreadsheetApp.getActiveSpreadsheet (); // obter a planilha chamada RawDatavar sheet =ss.getSheetByName ("RawData"); var sd =ss.getSheetByName ("Data"); var sref =ss.getSheetByName ("Referências"); var MAX_ROWS =1440; // número máximo de linhas de dados para exibir // 3600s / cloud_int (30s) * num_ore (12h) =(60 * 60 * 12) / 30 =(3600 * 12) / 30 =1440 leituras em 12 horas na atualização de 30 segundos intervalo // (60 * 24) / 15 =96 leituras em um período de 24 horas com intervalo de atualização de 15 minutos // 15 dias * 96 leituras / dia =1440 leituras // 90 dias * 96 leituras / dia =8640 leituras // 365 dias * 96 leituras / dia =35040 leiturasvar HEADER_ROW =1; // índice da linha do headervar TIMESTAMP_COL =1; // índice de coluna da função de coluna do carimbo de data / hora doPost (e) {var cloudData =JSON.parse (e.postData.contents); // este é um objeto json contendo todas as informações provenientes do IoT Cloud console.log (cloudData); // var webhook_id =cloudData.webhook_id; // realmente não usando esses três // var device_id =cloudData.device_id; // var thing_id =cloudData.thing_id; var values ​​=cloudData.values; // este é um array de objetos json console.log (valores); // Armazena nomes e valores da matriz de valores // Cada propriedade recebida tem um:// nome que se tornará os nomes das colunas // valor que será escrito nas linhas abaixo do cabeçalho da coluna var incLength =values.length; var incNames =[]; var incValues ​​=[]; para (var i =0; i  2018) {// descartar todas as mensagens que chegarem 'atrasado' if (sheet.getRange (HEADER_ROW + 1, 1) .getValue ()! ='') {// HEADER_ROW + 1 =Linha # 2 &Coluna # 1 -> este é o local do carimbo de data / hora mais recente na planilha // Se o carimbo de data / hora mais recente não estiver em branco =(''), então compare a hora atual com o carimbo de data / hora dos dados recebidos // Se o carimbo de data / hora mais recente estiver em branco, é provavelmente a primeira vez que o script é executado. // Neste caso, pule esta instrução if e prossiga para escrever nos cabeçalhos das colunas e dados. // Não importa se os dados estão chegando atrasados ​​(hora atual vs registro de data e hora dos dados de entrada). var agora =nova data (); // agora var COMM_TIME =120; // Observação:alterado para 120 para permitir que mais mensagens cheguem, previamente definido em 5 segundos e funcionou bem // superestimativa aproximada do tempo de comunicação entre a nuvem e o aplicativo if (now.getTime () - date.getTime ()> COMM_TIME * 1000) {// Se a diferença entre a hora atual e o carimbo de data / hora for maior que 5 segundos, descarte os dados. // Quando a condição nesta instrução If for avaliada como verdadeira, a função será interrompida devido à instrução return. Retorna; // "A instrução de retorno interrompe a execução de uma função e retorna um valor dessa função." }} // Esta seção grava valores na linha do cabeçalho com base nos nomes das propriedades de entrada // Em outras palavras, esta seção cria os nomes das colunas // Atribui um nome à célula que está na linha do cabeçalho e na primeira coluna =timestamp sheet.getRange (HEADER_ROW, 1) .setValue ('timestamp'); para (var i =0; i  é 2 // a coluna 1 é a coluna do carimbo de data / hora. if (lastCol ==1) {// escrever os nomes das colunas começando com a coluna após lastCol ==1 que é a coluna de carimbo de data / hora // incNames é uma matriz contendo os nomes de todas as propriedades de entrada // If lastCol ==1 , escreva o valor da 'i'ésima localização na matriz incNames na linha do cabeçalho na coluna # 2 =lastCol + 1 sheet.getRange (HEADER_ROW, lastCol + 1) .setValue (incNames [i]); } else {// avaliado se lastCol! =1 // verifique se o nome já está no cabeçalho var found =0; for (var col =2; col <=lastCol; col ++) {// começando com a coluna 2, iterar por todas as colunas até o lastCol avaliando a instrução if incluída if (sheet.getRange (HEADER_ROW, col) .getValue ( ) ==incNames [i]) {// a condição desta instrução If compara o valor na linha e coluna do cabeçalho # =col ao 'i'ésimo valor na matriz de nomes de propriedade recebidos // Esta instrução if é avaliada para cada iteração do loop for em que está incluído. // A condição é avaliada para todas as colunas da coluna # 2 à última coluna. // 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; pausa; // "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


Processo de manufatura

  1. ADLINK faz parceria com o Google Cloud para oferecer soluções prontas para IoT
  2. IoT básica - RaspberryPI HDC2010 como
  3. Sensor de pressão barométrica digital BMP180 I2C
  4. Python / MicroPython Sensor Logger com Planilhas Google
  5. Windows 10 IoT Core no Raspberry Pi 2 - Dados do sensor Adafruit
  6. Windows 10 IoT Core e SHT15
  7. UnifiedWater v1
  8. IOT - Jar inteligente usando ESP8266, Arduino e sensor ultrassônico
  9. Arduino Cloud Sensor Tower
  10. Arduino Apple Watch