📈

IoT実験:ラズパイで温度取得しグラフ表示 (1)ラズパイで温度取得

2023/06/12に公開

概要

Raspberry Pi(ラズベリーパイ、本記事では略して「ラズパイ」と呼ぶ)は、元々教育用に開発されたシングルボードコンピュータです。センサ等を接続して使用できるマイコン的な要素と、OSを搭載しネットワーク機能やPythonなどのプログラミング言語が使用できるPC的な要素をあわせ持っています。しかも、比較的安価に入手することができるため、様々な場面で用いられます。

今回は、ラズパイを使用してIoTの実験を行います。記事は何回かに分かれますが、最終目的は、ラズパイで温度取得したデータを、下図のように温度の時間的な変化としてグラフで見られるようにすることで、しかも、なるべく出来合いのソフトウエアを使用して、労力と時間を最小限に抑えます。(ラズパイで温度取得する部分は、プログラムが必要です。)

グラフによる可視化の例
グラフによる可視化の例

この温度データの可視化ができれば、これを応用して、他のセンサから取得したデータの可視化も、同じように行うことができます。

システム内の大まかな機能は以下の通りです。

  1. ラズパイ:温度センサから温度データを取得
  2. ラズパイ:取得した温度データをネットワークを介してサーバへ送信
  3. サーバ:受信した温度データをデータベースへ保存
  4. サーバ:ユーザの要望に応じて温度データを可視化

システム内の大まかな機能
システム内の大まかな機能

本記事では、このうちの1番目「ラズパイ:温度センサから温度データを取得」を行います。

実験環境

ラズパイ

項目 内容
本体 Raspberry Pi 3B+
OS Raspberry Pi OS Lite
Release date: May 3rd 2023
System: 64-bit
Kernel version: 6.1
Debian version: 11 (bullseye)
開発言語 Python 3.9.2
ホスト名 raspi01.local
IPアドレス DHCP (192.168.130.0/24)

ラズパイ本体は 3B+ を使用しました。特に負荷はかからないので、Zeroでも充分です。

OSは Lite版の64bitを使用しました。Lite版以外(デスクトップ版など)でも、32bitでも構いません。
Zeroは64bitが使用できませんので注意してください(Zero2は使用可)。

温度取得プログラムは、Python3 を使用しました。

ホスト名は「raspi01.local」としました。特にこの名前にこだわる必要はありませんが、データをデータベースに保存する際、ホスト名も同時に保存されますので、必ず自身で見分けられる名前にしてください。

IPアドレスは、自動取得(DHCP)としています。

温度センサ

項目 内容
型番 DS18B20
通信方式 1-wire
抵抗 4.7kΩ(プルアップ用)

温度センサは、1-wire方式のDS18B20というものを使用しました。センサやケーブルが防水処理がされているものでした。

使用した温度センサ
使用した温度センサ

温度センサの信号線はプルアップする(信号線を抵抗を介して電源に接続する)必要があります。マニュアルでは5kΩ程度とのことで、今回は 4.7kΩの抵抗を使用しました。

サーバ

次回以降となりますが、サーバOSはLinux(Ubuntu MATE)を使用し、データベースや可視化はInfluxDBというソフトウエアを使用します。

今回の実験では、「社内からしかアクセスしない」、「セキュリティをあまり考慮しなくてもよい」などの理由から、サーバマシンをLAN内に設置し、インターネットは使わないことを想定しています。もしインターネット上のクラウドにサーバを用意する場合は、そちらでも構いませんが、セキュリティを考慮したり、ラズパイからhttpやhttpsで通信ができる必要があります。

また、サーバとして別のマシンが用意できない場合、温度データを取得するラズパイにてデータベースソフトウエア(InfluxDB)を使用することも可能です(あまりお勧めはできませんが)。この場合、温度取得~可視化まで1台のラズパイで完結できます。

なお、本実験では、Windows 10上の仮想マシンをサーバとして利用しました。

接続

ブレッドボードを使用して、温度センサや抵抗を接続しました。

ブレッドボードでセンサや抵抗を接続
ブレッドボードでセンサや抵抗を接続

今回は、ラズパイのGPIO 26に温度センサの信号を入力しています。ラズパイの初期状態でGPIO 4が入力端子となりますので、GPIO 26を使う場合は設定変更が必要です。GPIO 4で問題なければ設定変更は不要です。(変更して使う場合はこうしましょう、という例となります。)

また、温度センサの電源は3.3Vを使用しますが、ラズパイから供給します。

今回使用したセンサは、赤、黄、黒の3本の線が出ていました。マニュアルより、次の意味となります。

  • 赤 ... 電源
  • 黄 ... 信号線
  • 黒 ... GND

ここから、下図のように接続しました。

温度センサの接続先
温度センサの接続先

実際の接続の様子
実際の接続の様子(あらかじめブレッドボードの赤線部は3.3V、青線部はGNDに接続済みです)

Raspberry Pi OS のインストール

Raspberry Pi OS のインストールに関しては、インターネット上に多くの記事がありますので、それらを参照してください。ここでは省略します。

参考:
Raspberry Pi OS – Raspberry Pi (https://www.raspberrypi.com/software/)

ラズパイの設定

1-wireの有効化

1-wireを有効化するには、raspi-config コマンドなら、以下のように実行し、

$ sudo raspi-config

以下のメニューをたどって有効化します。

「3 Interface Options」→「I7 1-Wire」→「はい」

また、デスクトップ環境なら「Raspberry Piの設定」ツールを使用します。

「Raspberry Piの設定」ツール
「Raspberry Piの設定」ツール

入力を GPIO26 へ

初期状態では、1-wire の入力は、GPIO 4 です。今回は、GPIO 26 を使用しようと思いますので、この変更が必要です。もし、GPIO 4 をそのまま使用する場合、この手順は不要です。
(GPIO 4 を別の用途で使用しないのであれば、GPIO 4 のままで問題ありません。変更する場合は、このようにしてください、という例となります。)

1-wireで使用する入力ポートの指定は、/boot/config.txt に記述します。このファイルへの書き込みは管理者権限が必要ですので、管理者権限を指定して、エディタで開きます。

以下は、エディタ vi にて、ファイル /boot/config.txt を、管理者権限で開いている例です。

$ sudo vi /boot/config.txt

ファイルを開いたら、以下の行を探してください。

dtoverlay=w1-gpio

そして、行の末尾に ,gpiopin=26 を追記します。

dtoverlay=w1-gpio,gpiopin=26

ファイルを上書き保存して終了したら、ラズパイを再起動してください。

$ sudo reboot

温度データの取得

上記設定を行うことで、1-wireのドライバが自動的に読み込まれます。1-wireのドライバでは、ファイルを経由してデータの読み取りが可能です。

以下では、1-wire用のファイルが作成されているか、そしてそのファイルを開いて温度が取得できるかの確認を行います。

なお、ファイルは /sys/bus/w1/devices/デバイスID/w1_slave となります。

(1) /sys/bus/w1 の確認

$ ls /sys/bus
... w1 ...

w1 ディレクトリが存在すれば、コマンドの実行結果に w1 が含まれます。

(2) /sys/bus/w1/devices の確認

$ ls /sys/bus/w1
... devices ...

devices ディレクトリが存在すれば、コマンドの実行結果に devices が含まれます。

(3) デバイスID の確認

$ ls /sys/bus/w1/devices
28-3c01d60775b9   w1_bus_master1

今回使用した温度センサ DS18B20 は、デバイスIDが「28-3c01d60775b9」でした。

(4) /sys/bus/w1/devices/デバイスID の確認

上でデバイスIDが確認できたので、以下を実行します。

$ ls /sys/bus/w1/devices/28-3c01d60775b9
... w1_slave ...

w1_slave が存在すれば、それが温度センサからデータ取得するファイルとなります。

(5) /sys/bus/w1/devices/デバイスID/w1_slave の内容表示

/sys/bus/w1/devices/デバイスID/w1_slave の内容を表示してみましょう。
これにより、温度データが取得できます。

$ cat /sys/bus/w1/devices/28-3c01d60775b9/w1_slave
88 01 55 05 7f a5 a5 66 ca : crc=ca YES
88 01 55 05 7f a5 a5 66 ca t=24500

ここで、末尾が「t=24500」と表示されていますが、これが取得した温度データとなります。実際には、下3桁が小数点以下となり「24.500℃」を意味します。

プログラム

実際のコード

以下は、上記のファイル /sys/bus/w1/devices/28-3c01d60775b9/w1_slave を読み込み、「t=xxxxx」の部分を温度として画面上に表示するPythonスクリプトです。

#!/usr/bin/env python

import os
import glob

BASE_DIR = "/sys/bus/w1/devices"
TEMP_FILE = "w1_slave"
DIR_HEAD = "28-"
TEMP_RATE = 1000

def read_temp_raw(temp_file):
    if not os.path.isfile(temp_file): return None
    f = open(temp_file, 'r')
    lines = f.readlines()
    f.close()
    return lines

def read_temp(temp_file):
    lines = read_temp_raw(temp_file)
    if lines is None: return None

    if len(lines) < 2: return None
    if lines[0].strip()[-3:] != 'YES': return None

    t_pos = lines[1].find('t=')
    if t_pos < 0: return None

    t_str = lines[1][t_pos+2:]
    try:
        t_val = float(t_str) / TEMP_RATE
        return t_val
    except Exception:
        return None

def main():
    base_subdir = BASE_DIR + "/" + DIR_HEAD + "*"
    ds_dirs = glob.glob(base_subdir)
    if len(ds_dirs) == 0:
        print("0.0")
    else:
        temp_file = ds_dirs[0] + "/" + TEMP_FILE
        temp_val = read_temp(temp_file)
        if temp_val is None: print("0.0")
        else: print(temp_val)

if __name__ == '__main__':
    main()

実行例

これを、たとえば「w1_temp.py」というファイル名で保存し、実行すると次のようになります。

$ python3 w1_temp.py
24.875

簡単な解説

関数 read_temp_raw(temp_file) は、引数で受け取ったファイル名のファイルの内容を読み込み、行ごとのリストとして返します。

関数 read_temp(temp_file) は、引数で受け取ったファイル名のファイル内容から、温度データを抽出し値を返します。

関数 main() は、スクリプト実行時に呼び出される関数で、read_temp(temp_file) を呼び出して温度データを取得後、画面上に出力します。

誰でも実行できるように

最後に、このスクリプトを誰でも実行できるように、別のディレクトリへコピーし、実行権を与えます。

$ sudo mkdir -p /usr/local/bin

$ sudo cp w1_temp.py /usr/local/bin/w1_temp.py

$ sudo chmod +x /usr/local/bin/w1_temp.py

実行してみます。

$ w1_temp.py
25.0

次回

今回は以上で終了です。
次回は、データを保存するサーバの構築を行います。

Discussion