ラズパイとDHT11を使って温度を測定する

概要

ラズパイとDHT11を使用して、周囲の温度を測定し、データベースに保存する

用意するもの

ラズパイ 3-4

DHT11 本体

自分の環境は ラズパイ 3 b+ に上のDHT11モジュールを使用しています。

参考サイト

https://www.souichi.club/raspberrypi/temperature-and-humidity/

DHT11とラズパイとの接続図

ピン配置は上の通り

プログラム

実はPythonにあまり触れたことがなく、知識も浅いのでとりあえずJSONにしてコマンドラインで出力を行うことにした。

import GPi.GPIO as GPIO
import dht11
import time
import datetime
import json

# ◆儀式◆
# 詳しくはわかりません
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)

# Output が GPIO 4 なので
# pin=4 になります
ins = dht11.DHT11(pin=4)

while True:
  result = ins.read()
  if result.is_valid():
    # JSON 出力用に辞書作成
    d = dict()
    # 日付
    d["date"] = str(datetime.datetime.now())
    # 温度
    d["temp"] = result.temperature
    # 湿度
    d["humi"] = result.humidity

    # 出力
    print(json.dumps(d, ensure_ascii=False, indent=2))
    break
  # 取得失敗
  # 1秒待って再度チャレンジ
  time.sleep(1)

GPIO.cleanup()

コマンドラインで実行すると

{
"date": "2021-06-18 20:29:05.163202",
"humi": 48.0,
"temp": 28.1,
}

というようなデータが取れるようになります。

データベースに保存するのにはPHPを使用します。

以下のようなコードでJSONを取得できます。

$raw = shell_exec("python output.py");
$json = json_decode($raw, true);

shell_exec でコマンドを実行して、出力データを $raw に代入し、

$raw を json_decode で配列に変換しています。

温度は $json[“temp”] で取得できるようになっています。

あとはこのデータをデータベースに保存するだけです。

C#でイベント機能を実装する方法

いままではActionなどを使用してコールバックを作成していたのですが、

イベントを活用することでできることのはばが広がったのでやり方を紹介します。

やり方

やり方はとても簡単で、

delegate でハンドル(?)を作って変数として event を追加するだけ()

// ハンドル
public delegate void MyEventHandler<T>(object sender, T args);
// イベント用
public event MyEventHandler<object, string> DebugEventHandler;

イベントの呼び出しは Invoke を利用してもいいですし、関数のように呼び出すこともできますが、起動直後はNULLのことがあるのでNULLチェックはした方がいいです。

DebugEventHandler?.Invoke(sender, string);
DebugEventHandler(sender, string);

 

ファイルデータを確実に送信する

条件

  • TCPを使用してファイルを相手に送る
  • UDP に置き換えても使用できるようにしたい

普通に読み込んで書き込み

FileTransfer v1.0 で使用した方式

ファイルを一定バイト読み込んでストリームの書き込み送信の繰り返し。

  • 場合によってはファイルデータが変わってしまう。
    UDP に置き換えた際データを確実に送れない。

ピースに分けて送信

本題はこれ。

ファイルデータを複数のピースに分けて送信する方式。

まず1ピースのデータは

とする。

全体のバイト数を X として、ハンドシェイク時に渡せばそれで完結する。

UDP に置き換えてもピースにナンバーがあるから大体どこらへんに来るデータかわかる。

暗号化する際や、SHA256データを必要とする際も1ピース毎に行えるからかなり効率的なはず。

そして最後のピースで余りが出ても1ピース毎にサイズを指定してあるから問題ない。

public class Piece
{
private const int HEADER_SIZE = 8; // Long to byte
private const int PIECE_N_SIZE = 4; // Int to byte
private int number = 0; // Piece Number
private int size = 1024; // piece size
private int writed = 0; // real byte
private byte[] buffer;

public Piece(int number, int size)
{
this.number = number;
this.size = size;
this.buffer = new byte[size];
}

public int Number { get { return number; } }
public int Size { get { return size; } }
public int Writed { get { return writed; } }

public void Write(byte[] buf)
{
Array.Copy(buf, 0, buffer, 0, buf.Length);
writed = buf.Length;
}

public void Read(byte[] buf)
{
Array.Copy(buffer, 0, buf, 0, buf.Length);
}
public byte[] toBuffer() {



int bufferedSize = piece.Size + HEADER_SIZE;
if (piece.Size > size)
{
throw new ArgumentOutOfRangeException("Size to large");
}

byte[] buf = new byte[piece.Size];
byte[] buffer = new byte[bufferedSize];
byte[] header1 = BitConverter.GetBytes(piece.Number);
byte[] header2 = BitConverter.GetBytes(piece.Writed); // or piece.Size

piece.Read(buf);
Array.Copy(header1, 0, buffer, 0, PIECE_N_SIZE);
Array.Copy(header2, 0, buffer, PIECE_N_SIZE, PIECE_N_SIZE);
Array.Copy(buf, 0, buffer, HEADER_SIZE, buf.Length);

//int offset = HEADER_SIZE + buf.Length;

return buffer;


}
}