用 Arduino + DHT22 + Raspberry Pi 做雲端溫度計

接線

接線基本上參考 這一篇 不過我手邊剛好沒有4.7K歐姆的電阻,就用10K的替代了,測出來結果感覺差不多。

線都亂接 (炸 線都亂接 (炸

Arduino程式

因為要讓後面的 Python Web Server 部分好接,所以直接輸出JSON,以下修改自 DHT Library 內附的範例

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain
// Edited by Ikaros <ikaros@hsexpert.net>

#include "DHT.h"

#define DHTPIN 2     // what digital pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

void setup() {  
  Serial.begin(9600);
  dht.begin();
}

void loop() {  
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
//    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
   Serial.print("{\"Humidity\": ");
   Serial.print(h);
   Serial.print(", \"Temperature\": ");
   Serial.print(t);
   Serial.print(", \"Heat_index\": ");
   Serial.print(hic);
   Serial.println("}");
}

Server 端程式部分

為了使用上方便,我把獲取資料和提供網頁介面寫成兩支程式。

獲取資料的程式就可以直接使用cron定時執行,寫入到檔案,Web Server再讀取檔案內容呈現出來就好,也可以避免大量request下,如果寫成有request才抓資料的話,中間的等待延遲問題。

抓取資料的程式

get_info.py

import serial  
import json

fields = ['Humidity', 'Temperature', 'Heat_index']

def main():  
    data = str()
    with serial.Serial('/dev/ttyACM0', baudrate=9600) as ser:
        data = ser.readline()
        data2 = ser.readline()

    try:
        data = json.loads(data)

        for field in fields:
            if field not in data:
                raise ValueError  # We got a wrong data.

    except ValueError:  # If the first is not complete, then the second one will be.
        data = json.loads(data2)

    with open("data.txt", "w") as file:
        file.write(json.dumps(data))

if __name__ == '__main__':  
    main()

在這裡會遇到一個問題,用 ser.readline() 讀出來的字串不一定會是完整的,為了避免這種問題,我就進行了兩次讀取,如果第一次JSON解析失敗 (代表是不完整的結果),就用第二次的。

再用一支小小的 shell script 來每5秒抓一次資料,其實也可以寫在 python script 裡面啦,只是我懶 XDD

#!/bin/bash

while [ 1=1 ]  
do  
    python ./get_info.py
    sleep 5
done  

接著就是弄支小小的Web Server來呈現資料就搞定了。我對 Python 寫後端的經驗不太多,所以這裡採用簡單好用又輕便的 Flask 來搞定這件事。

server.py

from flask import Flask, render_template  
import json

app = Flask(__name__)

@app.route("/")
def index():  
    with open("data.txt", "r") as datafile:
        data = datafile.read()
    data = json.loads(data)
    return render_template('index.html', data=data)

if __name__ == "__main__":  
    app.run(host='0.0.0.0')

Flask 的 template file 固定放在 templates 目錄下面,所以

templates/index.html

<html>  
    <head>
        <title>Environment Information</title>
    </head>

    <body>
        <h1>Environment Information</h1>
        <h2>Temperature: {{ data.Temperature }} °C</h2>
        <h2>Humidity: {{ data.Humidity }}%</h2>
        <h2>Heat index: {{ data.Heat_index }} °C</h2>
    </body>
</html>  

這樣跑起來就搞定一個簡單的溫度計了,就算出門在外也可以知道家中的溫度囉,也可以放在像機房之類的地方做監控,再遙控冷氣開關之類的,有數不清的應用。

Ikaros

Read more posts by this author.