Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Компоненты и материалы

Pycom SiPy×1
Raspberry Pi 3 Model B×1
Arduino Nano R3×1
Logic Level Converter (бидирекциональный)×1
NFC RFID-RC522×1
Датчик расстояния Sharp GP2Y0A41SK0F (4–30 см)×1
ИК-термометр MLX90614-DCI (I2C)×1
I2C LCD 16×2 (DFRobot)×1
Светодиод×1
Резисторы 330 Ом (×2)×2
Пьезо-зумер×1

Программное обеспечение и сервисы

О проекте

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Проблема

В Азии из-за жары и SARS (2003) школьники ежеквартально измеряют температуру. Приносят личные термометры, но некоторые забывают, ломают, не могут купить новые. Общий термометр гигиенично недопустим. Учителя вручную вносят данные 40 учеников — трудоёмко.

Решение

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Тема: Social Impact (SqwidNet), SDG: Good Health and Well-being. Автоматическое измерение температуры авторизованных пользователей, алерт при превышении порога.

Как работает: Raspberry Pi + Arduino

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Как работает: Sigfox (SiPy)

SiPy получает от Arduino userID и температуру, разделяет на целую и дробную части, отправляет байтами в Sigfox Backend (для совместимости с Ubidots и ThingSpeak).

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

В Sigfox Backend (CALLBACKS) настраивается форвардинг в ThingSpeak: Custom Payload должен точно соответствовать порядку полей (userID, temp_H, temp_L).

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Облако (ThingSpeak + MATLAB + IFTTT)

  • Два канала: Private (сырые байты) и Public (обработанные данные).
  • MATLAB Analysis на Private канале объединяет целую и дробную части температуры, переносит userID в Public канал.
  • React триггерит MATLAB при появлении данных (Field 3 ≠ 0).
  • Если температура ≥ 38 °C — MATLAB вызывает Webhook IFTTT → email уведомление персоналу.
  • Public канал имеет автообновляемую таблицу для админов.
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

1. Подключение Arduino Nano

Пины (Nano и Uno одинаковые):

RFID RC522:    SDA-D10, SCK-D13, MOSI-D11, MISO-D12, IRQ-NC, GND-GND, RST-D9, 3.3V-3.3V
LCD I2C:       SDA-A4, SCL-A5, GND-GND, 5V-5V
Distance:      5V-5V, GND-GND, Out-A0
Buzzer:        GND-GND, Out-D6
MLX90614:      SDA-A4, SCL-A5, GND-GND, 5V-5V
LED:           Cathode-GND, Anode-D7

2. Настройка Raspberry Pi

  1. Установка Raspbian (balenaEtcher → образ → SD).
  2. Включение SSH/VNC в raspi-config. Опционально: статический IP в /etc/dhcpcd.conf.

3. MySQL Database

sudo apt update && sudo apt upgrade
sudo apt install apache2 php php-mbstring mariadb-server php-mysql
sudo mysql --user=root
DROP USER 'root'@'localhost';
CREATE USER 'root'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES; exit;
mysql --user=root --password=yourpassword
sudo apt install phpmyadmin
sudo phpenmod mysqli
sudo /etc/init.d/apache2 restart

Доступ: https:///phpmyadmin

4. SiPy Expansion Board 2.0

  • Вставьте SiPy с кнопкой ресета к USB.
  • Обновите прошивку (Pycom Firmware Updater) — выберите правильный RCZ Region (RCZ4 для Азии).
  • Установите VS Code + Pymakr + Node.js.
  • Создайте папку, файл main.py.
  • Бесконечные циклы загружаются в флеш — для удаления используйте FileZilla (FTP: plain, passive, 1 соединение). Хост/юзер/пасс из Pymakr Global Settings. SSID SiPy — уникальный, пароль: www.pycom.io.

5. Регистрация в Sigfox Backend

Получите Device ID и PAC через код в терминале или файле. Зарегистрируйте на backend.sigfox.com (выберите страну). Тест отправки байтов.

6. Настройка облака (IFTTT + ThingSpeak)

  • IFTTT: Webhooks (Receive web request, event name «fever») → Email (Send me an email, Body с {{Value1}}, {{Value2}}).
  • ThingSpeak: создайте каналы Private и Public. Настройте React на Private: условие Field 3 ≠ 0 → MATLAB Analysis (код объединения температуры и отправки в Public + IFTTT webhook).

Участники

  • Aden — Raspberry Pi + Arduino + ThingSpeak (MATLAB/Setup)
  • Reginald — Sigfox + ThingSpeak Data Collection + Схемы
  • Bo Sheng — IFTTT Setup

Исходный код

[C] ARDUINO NANO

/* 90% coded by Aden (https://www.astero.me), 10% open libraries (RFID, MLX90614) */
#include <SPI.h>
#include <MFRC522.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <SoftwareSerial.h>
#include <Adafruit_MLX90614.h>

#define RST_PIN 9
#define SS_PIN 10
#define BUZZER_PIN 7
#define LED_PIN 6
#define dist_sensePin A0

MFRC522 mfrc522(SS_PIN, RST_PIN);
LiquidCrystal_I2C lcd(0x27, 16, 2);
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
SoftwareSerial unoSerial(2, 3);

boolean tapped = true;
boolean confirmation = false;

String GetUID() {
  String card_UID = "", card_UID_no_space = "";
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    card_UID.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
    card_UID.concat(String(mfrc522.uid.uidByte[i], HEX));
  }
  card_UID_no_space.concat(card_UID.charAt(1));
  card_UID_no_space.concat(card_UID.charAt(2));
  card_UID_no_space.concat(card_UID.charAt(4));
  card_UID_no_space.concat(card_UID.charAt(5));
  card_UID_no_space.concat(card_UID.charAt(7));
  card_UID_no_space.concat(card_UID.charAt(8));
  card_UID_no_space.concat(card_UID.charAt(10));
  card_UID_no_space.concat(card_UID.charAt(11));
  return card_UID_no_space;
}

void setup() {
  Serial.begin(9600);
  while (!confirmation) { Serial.println("ARDUINO"); confirmation = Serial.readString() == "RAPI"; delay(1000); }
  SPI.begin(); mfrc522.PCD_Init(); mlx.begin(); unoSerial.begin(9600);
  pinMode(BUZZER_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT);
  lcd.init(); lcd.backlight();
}

void loop() {
  boolean readySignal = Serial.readString() == "READY";
  if (readySignal) { tapped = true; Serial.println("RECEIVED"); }
  if (tapped) {
    digitalWrite(BUZZER_PIN, 0); digitalWrite(LED_PIN, 0);
    lcd.clear(); lcd.setCursor(0,0); lcd.print(" Please tap"); lcd.setCursor(0,1); lcd.print(" your card.");
    delay(500); tapped = false;
  } else {
    String card_UID = "";
    if (!mfrc522.PICC_IsNewCardPresent()) return;
    if (!mfrc522.PICC_ReadCardSerial()) return;
    card_UID = GetUID(); card_UID.toUpperCase();
    Serial.print(card_UID); Serial.print("\n");
    String rawData = Serial.readString();
    int commaPos = rawData.indexOf(',');
    String userInitial = rawData.substring(0, commaPos);
    int userID = rawData.substring(commaPos + 1).toInt();
    lcd.clear();
    if (userID != 0 && userInitial != "0") {
      lcd.setCursor(0,0); lcd.print("Welcome, "); lcd.setCursor(0,1); lcd.print(userInitial);
      int dist_senseValue = analogRead(dist_sensePin);
      byte temp_Hbyte = 0, temp_Lbyte = 0;
      float meas_temp = 0.0;
      delay(2000);
      while ((dist_senseValue < 170) || (dist_senseValue > 200)) {
        dist_senseValue = analogRead(dist_sensePin);
        lcd.setCursor(0,0); lcd.print("Please take"); lcd.setCursor(0,1); lcd.print("your temperature.");
      }
      digitalWrite(BUZZER_PIN, 1); digitalWrite(LED_PIN, 1); lcd.clear();
      meas_temp = (float)mlx.readObjectTempC();
      temp_Hbyte = floor(meas_temp);
      temp_Lbyte = (meas_temp - temp_Hbyte) * 100;
      String sMeasTemp = ""; sMeasTemp += userID; sMeasTemp += ","; sMeasTemp += temp_Hbyte; sMeasTemp += ","; sMeasTemp += temp_Lbyte;
      Serial.println("TEMP"); Serial.println(meas_temp);
      if ((meas_temp >= 28) && (meas_temp <= 42)) unoSerial.print(sMeasTemp);
      lcd.setCursor(0,0); lcd.print("Temperature: "); lcd.setCursor(0,1); lcd.print(" " + String(meas_temp));
    } else {
      lcd.setCursor(0,0); lcd.print("Error!"); lcd.setCursor(0,1); lcd.print("Invalid User.");
    }
    rawData = Serial.readString();
    commaPos = rawData.indexOf(',');
    userInitial = rawData.substring(0, commaPos);
    if (userInitial == "0") { lcd.clear(); lcd.setCursor(0,0); lcd.print("Error!"); lcd.setCursor(0,1); lcd.print("Invalid Temperature."); }
    Serial.println("STANDBY"); delay(1000);
    mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1();
  }
}

[PYTHON] Raspberry Pi

''' Coded by Aden for Hackster.io Sigfox competition. https://www.astero.me '''
import mysql.connector, serial, os, time

def queryConnection():
    cursor = conn.cursor(buffered=True)
    cursor.execute("USE `" + databaseName + "`")
    return cursor

host = "localhost"; user = "root"; password = "password"; databaseName = "smartTemp"
conn = mysql.connector.connect(host=host, user=user, passwd=password)
comPort = 'ttyUSB0'; baudRate = 9600
ser = serial.Serial('/dev/' + comPort, baudRate, timeout=0)

print("Confirming USB Serial Port now, please wait")
connected = False
for x in range(2):
    time.sleep(2); ser.write("RAPI")
    if not connected:
        serialConfirmation = ser.readline().strip() == "ARDUINO"
        print(serialConfirmation)
        if not serialConfirmation: comPort = 'ttyUSB1'; connected = True
        else: comPort = 'ttyUSB0'; connected = True
    print(comPort)
ser = serial.Serial('/dev/' + comPort, baudRate)
print("COM PORT confirmed, using " + comPort)

countFile = open("count.txt", "a++")
tapRFID = False
cursor = queryConnection()

if os.stat("count.txt").st_size == 0:
    print("Count has not been set, setting to 1 now."); count = 1
else:
    for countNumber in countFile: count = int(countNumber)
    print("Count restored: " + str(count))

try:
    print("Creating " + databaseName + " database now..")
    cursor.execute("CREATE DATABASE " + databaseName)
    print("Database created.")
except mysql.connector.errors.DatabaseError:
    print(databaseName + " database already exists.")
    cursor.execute("CREATE TABLE IF NOT EXISTS `userInfo` (id int, cardID VARCHAR(9), userID VARCHAR(4), userInitial VARCHAR(8))")
    cursor.execute("CREATE TABLE IF NOT EXISTS `tempData` (id int, userID VARCHAR(4), dateMeas date, timeMeas time, tempMeasure decimal(5,2))")

while True:
    cursor = queryConnection()
    cardID = str(ser.readline().strip())
    cursor.execute("SELECT * FROM userInfo WHERE cardID = '" + cardID + "'")
    items = cursor.fetchone()
    if items:
        print(cardID)
        userID = str(items[2])
        userDetails = str(items[3] + ", " + items[2])
        currentDate = time.strftime("%Y-%m-%d", time.gmtime())
        currentTime = time.strftime("%H:%M:%S", time.gmtime())
        print(items)
        ser.write(b'' + userDetails)
        countFile.close()
        countFile = open("count.txt", 'w')
        tempSignal = False
        while not tempSignal:
            print("Getting Temperature")
            tempSignal = ser.readline().strip() == "TEMP"
            tempData = float(ser.readline().strip())
            print(tempData)
            if 28 <= tempData <= 42:
                cursor.execute("INSERT INTO `tempData`(`id`,`userID`,`dateMeas`,`timeMeas`,`tempMeasure`) VALUES (" + str(count) + ",'" + userID + "','" + currentDate + "','" + currentTime + "','" + str(tempData) + "')")
                conn.commit()
                count += 1; countFile.write(str(count))
            else:
                ser.write(b'' + "0, 0")
    else:
        ser.write(b'' + ", 0"); print("Nothing found")
    readySignal = ser.readline().strip() == "STANDBY"
    while readySignal:
        ser.write(b'' + "READY"); print("sending")
        receivedSignal = ser.readline().strip() == "RECEIVED"
        if receivedSignal: readySignal = False; print("received")
    cursor.close(); conn.close()

[MicroPython] Sigfox (Pycom)

''' 100% coded by Reginald '''
from machine import UART
from network import Sigfox
import binascii, socket, time, pycom, sys

pycom.heartbeat(False)
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ4)
uart1 = UART(1, baudrate=9600)
uart1.init(9600, bits=8, parity=None, stop=1, pins=('P3','P4'), timeout_chars=20)

while True:
    try:
        recv = uart1.readline()
        if recv:
            print(binascii.hexlify(sigfox.id()))
            print(binascii.hexlify(sigfox.pac()))
            sk1 = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
            sk1.setblocking(False)
            sk1.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False)
            dataList = recv.decode("utf-8")
            print("dataList : %s" % dataList)
            split_val = dataList.split(",")
            userID = int(split_val[0])
            temp_H = int(split_val[1])
            temp_L = int(split_val[2])
            print("userID : %d temp_H : %d temp_L : %d" % (userID, temp_H, temp_L))
            bData = [userID, temp_H, temp_L]
            meas_temp = temp_H + (temp_L * 0.01)
            print("measure temperature : %.2f" % meas_temp)
            sk1.send(bytes(bData))
            sk1.close()
            time.sleep(5)
    except KeyboardInterrupt:
        sys.exit()

[ThingSpeak] MATLAB SCRIPT

%% Made by Aden for Hackster.io Sigfox Competition. https://www.astero.me
readChannelID = 870479;
webhookTrigger = 'https://maker.ifttt.com/trigger/student_fever/with/key/h10MdSGwjSPtZQ43wH-AgoiKI0pwaljBNnGUEu4Yecn';
readAPIKey = 'QGHINBPNJQKULBH2';
writeChannelID = 870482;
writeAPIKey = 'R6NJIM8NT5A42R9N';

wholeNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 1);
decimalNumber = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 2) / 100;
userID = thingSpeakRead(readChannelID, 'ReadKey', readAPIKey, 'Fields', 3);

display(wholeNumber, 'BEFORE')
analyzedData = wholeNumber + decimalNumber;
display(analyzedData, 'AFTER')
display(userID, 'USERID')

thingSpeakWrite(writeChannelID, 'Fields', [1,2], 'Values', {analyzedData, userID}, 'WriteKey', writeAPIKey)

if analyzedData >= 38
    webwrite(webhookTrigger, 'value1', analyzedData, 'value2', userID);
end

Схемы подключения

Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно
Умная система мониторинга температуры для школ: точно, в реальном времени, безопасно

Производственный процесс

  1. Профессиональный мониторинг температуры на Raspberry Pi с датчиком DS18B20
  2. Точный мониторинг температуры в серверной на Raspberry Pi
  3. Самодельная система термостатирования для домашнего пивоварения: мониторинг и регулирование на Arduino
  4. Датчик CO2 K30: мониторинг качества воздуха в реальном времени на Arduino
  5. Умные шторы: автоматическое управление светом на Arduino с солнечной энергией
  6. Бесконтактный термометрический шлюз для быстрого и точного скрининга
  7. Arduino UNO + WiFi Shield: реальный график температуры в вебе через Serial
  8. Библиотека 8-битного порта ввода-вывода для Arduino — расширение цифрового управления
  9. Health Band: умный браслет для мониторинга пожилых людей на Arduino Nano и DPS310
  10. Умное фермерство: комплексный IoT-мониторинг для будущего аграриа