Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Onderdelen en benodigdheden

Onderdeel Aantal
Arduino UNO 1
Arduino MKR GSM 1400 1
Druksensor (0-150 psi) 1
Adafruit DHT22 Temperatuur & Vochtigheid Sensor 1
DS3231 RTC Module 1
Adafruit Logic Level Converter - BSS138 - 4-kanaals I2C-safe Bidirectioneel 1
Adafruit 3.7V LiPo Batterij (2000 mAh of meer) 2
Spanningsopwaartsconverter 1
Basis Starter Kit met diverse LEDs & Weerstanden 1
Breadboard (generiek) 1

Apps en online diensten

  • Google Sheets
  • Arduino IoT Cloud
  • Arduino Web Editor
  • Arduino IDE

Over dit project

Doelstelling

Het doel was een prototype te maken van een laagprijs apparaat om druk op industriële apparatuur op afgelegen locaties te monitoren via cellulair netwerk.

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Project Walkthrough

Stap-voor-stap doorloop van de datastroom van de druksensor naar de e-mailnotificatie gegenereerd door het script in Google Sheets.

Stap 1: Druksensor naar Uno

De druksensor converteert druk naar een analoog elektrisch signaal. De Arduino Uno converteert dit analoog signaal naar druk in psi.

Stap 2: Uno naar MKR GSM 1400 via Serial

Bij seriële communicatie tussen twee Arduino's:

  • RX op Apparaat #1 verbinden met TX op Apparaat #2
  • TX op Apparaat #1 verbinden met RX op Apparaat #2
  • Beide apparaten moeten een gemeenschappelijke ground hebben

Data-overdrachtsfrequentie (Uno naar MKR GSM 1400)

  • NORMAAL: Elke 30 minuten (transmitFrequency) stuurt de Uno seriële data naar de MKR GSM 1400 die het naar de cloud stuurt.
  • HOOG/LAAG TRIGGER: Als druk boven 40 psi (highTrigger) of onder 20 psi (lowTrigger) blijft voor meer dan 2 minuten (dtLastTriggerLimit), stuurt de Uno data naar de MKR GSM 1400.
  • DEMAND POLL: Als pin A1 op de Uno hoog wordt getrokken, stuurt de Uno data naar de MKR GSM 1400. Pin A1 heet "buttonPin" in de sketch. Twee manieren: (1) drukknop op breadboard, (2) als pin A3 op MKR GSM 1400 hoog is, duwt het pin A1 hoog. Pin A3 wordt bestuurd door een input in Arduino Cloud, zodat de huidige druk op afstand opgevraagd kan worden zonder te wachten op geplande transmissie.

Opmerkingen: De Uno-sketch kan uitgebreid worden om meerdere inputs (temperatuur, vochtigheid, batterijspanning) te monitoren met drempelwaarden. De conversiecode voor de druksensor is gebaseerd op deze YouTube-video. Het Arduino Forum-bericht over Serial Input Basics was heel nuttig.

Bestandsnaam: "InstrumentReader"

Stap 3: MKR GSM 1400 naar Arduino Cloud via Cellulair

De MKR GSM 1400 verwerkt seriële data van de Uno en stuurt het via cellulair naar Arduino Cloud. Let op: in de code zie je Serial1.read in plaats van Serial.read. Op MKR-boards zijn TX/RX-pinnen bereikbaar via Serial1. Zie Arduino referentie.

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Arduino Cloud

Project heeft 2 variabelen in Arduino Cloud. Het dashboard toont:

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
  • dataStringCloud: een pakket met alle data van het apparaat. Deze aanpak vereenvoudigt verwerking in Google Sheets. Individuele variabelen maakten het moeilijk om onderscheid te maken tussen ongewijzigde waarden en niet-geüpdate waarden. Data wordt in Google Sheets geparsed.
  • pinCloud: bestuurt de MKR GSM 1400 vanuit Arduino Cloud. Switch-functie in sketch: pinCloud=1 zet pin A1 hoog (LED brandt), pinCloud=2 zet pin A3 hoog wat leidt tot dataverzending van de Uno.

Bestandsnaam: "CommunicationsDevice"

Stap 4: Arduino Cloud naar Google Sheets via Webhook

Dataoverdracht via webhook. De kern is de doPost functie in het script van een Google Sheets-bestand.

Webhook setup (begin in Google Sheets!):

  1. Nieuw Google Sheets-bestand aanmaken
  2. Tools > Script editor
  3. Code met doPost functie schrijven (zie GoogleSheetsScript.js)
  4. Publish > Deploy as web app...
  5. Dialoogvelden: (1) Project Version: "New" selecteren, (2) Execute as: "me (jouw email)", (3) Who has access: "Anyone, even anonymous"
  6. Deploy klikken, URL kopiëren naar webhook-tab in Arduino Cloud. URL blijft constant.

Gedeelte van de JavaScript-code is gemodelleerd na Arduino IoT Cloud Google Sheets Integration.

Stap 5: Google Sheets Data Parsen

Google Sheets parseert individuele waarden uit dataStringCloud en toont unieke records.

Testbestand: Google Sheets testbestand. Cellen gekleurd op basis van vulling (zie legenda per sheet).

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Stap 6: Google Sheets Notificaties Sturen

Twee functies in GoogleSheetsScript.js:

  • doPost: ontvangt data van Arduino Cloud webhook. Draait bij nieuwe data.
  • sendEmail: stuurt e-mails op basis van waarden uit sheet "Data". Draait elke minuut via trigger.

Trigger setup voor sendEmail:

  1. Google Sheets openen > Tools > Script Editor
  2. Edit > Current project's triggers
  3. Add Trigger > selecteer sendEmail functie
  4. Time-Driven basis maakt notificaties mogelijk wanneer apparaat stopt met updaten
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Batterijduur

~24 uur. Optimaliseer door displays uit te schakelen/verwijderen of non-essentiële sensoren (DHT22, DS3231) weg te laten.

Dataverbruik

~0.7 MB/dag. Optimaliseer door grootte/frequentie van transmissies te verminderen (bijv. alleen druk sturen, of elk uur ipv 30 min).

Projectkosten

Totaal = $241

  • Arduino MKR GSM 1400 ($70)
  • Arduino Uno ($22)
  • 2x 3.7V LiPo Batterijen ($30)
  • 2x LED Displays ($29)
  • Weerbestendige Kunststof Doos ($22)
  • Druksensor ($19)
  • DHT22 Temperatuur/Vochtigheid Sensor ($10)
  • DS3231 RTC Module ($5)
  • Spanningsopwaartsconverter ($5)
  • Logic Level Converter ($4)
  • Diverse - LEDs, Weerstanden, Bedrading, etc. ($25)

Hardware / Tools

Alle hardware gekocht bij:

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets
Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Conclusie

Dank voor het bekijken van dit project. Alle vragen, feedback, opmerkingen en suggesties zijn welkom en gewaardeerd.

Code

InstrumentReader - Sketch voor Arduino Uno

// Sketch 1 of 2 // Arduino Uno
// Data wordt verzameld en via serial naar MKR 1400 gestuurd
// DHT22 Sensor vereist 2 libraries, maar alleen 1 wordt aangeroepen in code.
// (1): DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// (2): Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor
#include <SPI.h>
#include <Wire.h>
#include <DS3231.h> // RTC module
#include <DHT.h> // DHT22
#include "U8glib.h" // Velleman 128x64 OLED SPI Display
// Note: Een andere standaard U8glib library werkte niet voor dit display. Werkte wel met de door fabrikant aanbevolen library.
// Library: https://www.velleman.eu/support/downloads/?code=VMA437
// Syntax: https://github.com/olikraus/u8glib/wiki/userreference & https://github.com/olikraus/u8glib/wiki/thelloworld
//#include <SD.h> // Optie om op SD-kaart in Ethernet Shield op te slaan
RTClib RTC;
#define DHTPIN 11
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
U8GLIB_SH1106_128X64 u8g(3, 4, 6, 7); // (CLK/SCK: 3, MOSI: 4, CS: 6, DC(A0): 7)
int y_pos = 0;
//const int chipSelect = 10; // SD card optie
//float fileSizeSD = 0.0; // SD card optie
int i = 0; // Aantal metingen
const int ledPin = 9; // transmit indicator
const int ledPin2 = 8; // push transmit indicator
const int buttonPin = A1;
int buttonState = 0;
int transmitFrequency = 30; // minuten
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;
float lowTrigger = 20.0;
float highTrigger = 40.0;
float dtLastTriggerLimit = 2.0;

void setup(void) {
  Serial.begin(9600);
  Wire.begin();
  dht.begin();
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(buttonPin, INPUT);
  u8g.setRot180();
  // SD card init code (optioneel)
}

void loop(void) {
  delay(5000);
  DateTime now = RTC.now();
  float cRuntime = millis()/60000;
  float p = getPressure();
  buttonState = digitalRead(buttonPin);
  if(buttonState == 1) {
    digitalWrite(ledPin2, HIGH);
    delay(30000);
  } else {
    digitalWrite(ledPin2, LOW);
  }
  float h = dht.readHumidity();
  float t = dht.readTemperature(true); // true = Fahrenheit
  int transmitIndicator = 0;
  if(now.minute() % transmitFrequency == 0 && now.minute() != pTransmitMinute) {
    transmitIndicator = 1;
    pTransmitMinute = now.minute();
    pTransmitDateTime = String(now.hour())+":"+String(now.minute())+":"+String(now.second());
  }
  int triggerStatus = 0;
  if(p <= lowTrigger || p >= highTrigger) {
    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) {
    triggerPushTransmitAlertIndicator = 1;
    flashLED(5,500);
    delay(5000);
  }
  ptriggerTransmitAlertIndicator = triggerTransmitAlertIndicator;
  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++;
  }
  delay(100);
  u8g.firstPage();
  do {
    draw(cDateTime,cHumTemp, cP,i,transmitCounter,now.minute(),transmitFrequency,pTransmitMinute);
  } while(u8g.nextPage());
  delay(1000);
  // writeToSD(dataString); // SD card optie
  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.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("Remainder:"); u8g.setPrintPos(70,48); u8g.print(DnowMinute % DtransmitFrequency);
}

float getPressure() {
  int sensorVal=analogRead(A2);
  float voltage = (sensorVal*5.0)/1023.0;
  float m = ((150-0)/(4.5-0.4889));
  float b = 150 - (m*4.5);
  float pressure_psi = ((m*voltage)+ b);
  return pressure_psi;
}

void flashLED(int num, int t) {
  for (int z = 1; z <= num; z++) {
    digitalWrite(ledPin, HIGH); delay(t);
    digitalWrite(ledPin, LOW); delay(t);
  }
}

GoogleSheetsScript.js

// 2 functies: doPost (webhook ontvangst) en sendEmail (notificaties)
// Gemodelleerd na: https://create.arduino.cc/projecthub/Arduino_Genuino/arduino-iot-cloud-google-sheets-integration-71b6bc?f=1
// GitHub repo: https://github.com/arduino/arduino-iot-google-sheet-script/blob/master/Code.gs

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("RawData");
var sd = ss.getSheetByName("Data");
var sref = ss.getSheetByName("References");
var MAX_ROWS = 1440;
var HEADER_ROW = 1;
var TIMESTAMP_COL = 1;

function doPost(e) {
  var cloudData = JSON.parse(e.postData.contents);
  console.log(cloudData);
  var values = cloudData.values;
  console.log(values);
  var incLength = values.length;
  var incNames = [];
  var incValues = [];
  for (var i = 0; i < incLength; i++) {
    incNames[i] = values[i].name;
    incValues[i] = values[i].value;
  }
  console.log(incNames); console.log(incValues);
  var timestamp = values[0].updated_at;
  var date = new Date(Date.parse(timestamp));
  if (date.getYear() > 2018) {
    if (sheet.getRange(HEADER_ROW+1, 1).getValue() != '') {
      var now = new Date();
      var COMM_TIME = 120;
      if (now.getTime() - date.getTime() > COMM_TIME * 1000) return;
    }
    sheet.getRange(HEADER_ROW, 1).setValue('timestamp');
    for (var i = 0; i < incLength; i++) {
      var lastCol = sheet.getLastColumn();
      if (lastCol == 1) {
        sheet.getRange(HEADER_ROW, lastCol + 1).setValue(incNames[i]);
      } else {
        var found = 0;
        for (var col = 2; col <= lastCol; col++) {
          if (sheet.getRange(HEADER_ROW, col).getValue() == incNames[i]) { found = 1; break; }
        }
        if (found == 0) sheet.getRange(HEADER_ROW, lastCol+1).setValue(incNames[i]);
      }
    }
    var lastCol = sheet.getLastColumn();
    var lastRow = sheet.getLastRow();
    if (lastRow > MAX_ROWS + HEADER_ROW - 1) sheet.deleteRow(lastRow);
    sheet.insertRowAfter(HEADER_ROW);
    var range = sheet.getRange('A2:Z2');
    range.setFontColor('#000000'); range.setFontSize(10); range.setFontWeight('normal');
    sheet.getRange(HEADER_ROW+1, TIMESTAMP_COL).setValue(date).setNumberFormat("yyyy-MM-dd HH:mm:ss");
    for (var col = 1+TIMESTAMP_COL; col <= lastCol; col++) {
      for (var i = 0; i < incLength; i++) {
        var currentName = sheet.getRange(HEADER_ROW, col).getValue();
        if (currentName == incNames[i]) {
          if (incValues[i] == true) incValues[i] = 1;
          else if (incValues[i] == false) incValues[i] = 0;
          sheet.getRange(HEADER_ROW+1, col).setValue(incValues[i]);
        }
      }
      if(sheet.getRange(HEADER_ROW+1, col).getValue() == '') {
        sheet.getRange(HEADER_ROW+1, col).setValue("-");
      }
    }
  }
}

function sendEmail() {
  var emailAddress = sd.getRange("V3").getValue();
  var lastPressure = sd.getRange("K3").getValue();
  var lastUpdate = sd.getRange("A3").getValue();
  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);
    sd.getRange("L5").setValue(-1);
    sd.getRange("L6").setValue(triggerAlertCount + 1);
    MailApp.sendEmail(emailAddress, "Status Change Alert - Outside Setpoints", message);
  }
  if(triggerMonitor == 1 && triggerAlertCount <= 4){
    sd.getRange("L3").setValue(lastUpdate);
    sd.getRange("L5").setValue(1);
    sd.getRange("L6").setValue(triggerAlertCount + 1);
    MailApp.sendEmail(emailAddress, "Status Change Alert - Normal", message);
  }
  if(emailSentNoUpdate == 0 && dtLastDeviceUpdate1 > 60 && dtLastDeviceUpdate2 > 60){
    sd.getRange("T3").setValue(1);
    sd.getRange("U3").setValue(0);
    sd.getRange("T4").setValue(new Date().getTime());
    MailApp.sendEmail(emailAddress, "Alert - Over 60 minutes Since Last Device Update", message);
  }
  if(emailSentNoUpdate == 1 && dtLastDeviceUpdate1 < 60){
    sd.getRange("T3").setValue(0);
    sd.getRange("U3").setValue(1);
    sd.getRange("U4").setValue(new Date().getTime());
    MailApp.sendEmail(emailAddress, "Alert - Device Started Updating", message);
  }
}

CommunicationsDevice - Sketch voor MKR 1400

Code niet beschikbaar in preview (download only).

Schema's

Real-Time IoT Drukmonitoring met MKR GSM, Arduino Cloud en Google Sheets

Productieproces

  1. Raspberry Pi & HDC2010: Complete I2C Temperatuur & Vochtigheid Sensor Setup Gids
  2. BMP180 I2C Barometrische Druksensor – Raspberry Pi Integratiehandleiding
  3. Python/MicroPython Sensor Logger: Naadloos Sensordata Opslaan in Google Sheets
  4. Adafruit 10DOF IMU-data van Raspberry Pi 2 naar Azure Event Hubs Sturen met Windows 10 IoT Core
  5. Nauwkeurige Temperatuur- & Vochtigheidsmonitoring met SHT15 op Windows 10 IoT Core
  6. UnifiedWater v1 – Complete Arduino Waterkwaliteit Sensor Kit
  7. Bouw een Slimme IoT Pot met ESP8266, Arduino & Ultrasonische Sensor – Real-time Monitoring
  8. Bouw een Sensor Toren met Arduino Cloud: Temperatuur, Beweging & Gas Monitoring
  9. DIY Arduino Smartwatch: Bouw Je Eigen Apple Watch-stijl Tijdwijzer
  10. Je TV bedienen met Alexa via Arduino IoT Cloud – stapsgewijze handleiding
  11. ADLINK & Google Cloud collaboreren voor naadloze IoT-oplossingen