温度の測定と表示(5)

今回は気温を測定してHPに表示します。前回からの変更箇所は以下の通り

  • LED オンオフ用ボタンの大きさと配置を変更。
  • その下に温度を表示。
  • 一番下の、”Measure”ボタンを押すと温度を測定し値た表示。

温度測定デバイス

温度測定デバイスは、”I2Cを使う” で説明した、”ADT7410″ を使用します。今回はI2Cアドレスを、0x48に固定しています。気温測定プログラムは下記の様になります。


import smbus

bus = smbus.SMBus(1)
# 13bit mode
bus.write_byte_data(0x48, 0x03, 0x00)
word_data = bus.read_word_data(0x48, 0x00)

data = (word_data & 0xff00) >> 8 | (word_data & 0xff) << 8
data /= 128 

以下その他のプログラムの説明をします。

HTMLプログラム(hello_05.html)

hello_05.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link rel="stylesheet" type="text/css" href="./http_server_05.css" >
        <title>http-server 1.0</title>
    </head>
    <body>
        <center>
            <div class="b_frame">
   	        <div class="t_font"><u>HTTP-Server 1.0</u></div><br>
		        <form method='get'>
                  <div style="display:flex; justify-content:space-evenly;"> 
        	        <button type='submit' name='1' value='0' >On</button>
        	        <button type='submit' name='2' value='0' >Clear</button>
                  </div>
                </form>
		        <div style="font-size:25px;" id='1'>XX'C</div>
    		    <form method='get'> <button type='submit' name='3' value='0' >Measure</button></form>
                <br>  
            </div>  
        </center>
      <script src="http_server_05.js"></script>
    </body>
</html>
  • 6行目: CSSファイルを、”http_server_05.css”に変更
  • 14から17行: LED オンオフ ボタン表示部
  • 19行目: 温度表示部。表示部のIDを、”1”としています。
  • 20行目: 測定開始用ボタン。name=’3’ としています。
  • 24行目:スクリプトファイルを、”http_server_05.js”に変更

pythonプログラム(hello_05.py)

hello_05.py

from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import urlparse,parse_qs
import RPi.GPIO as GPIO

import smbus

btn_stat = 0

GPIO.setmode(GPIO.BCM)      
GPIO.setup(17, GPIO.OUT)   
GPIO.output(17,0)        

class MyHandler(SimpleHTTPRequestHandler):
    bus = smbus.SMBus(1)

    def do_GET(self):
        global btn_stat

        fl = 1
        if self.chk_file() == 0:
            parsed = urlparse(self.path)
            params = parse_qs(parsed.query)
            a=next(iter(params))

        #-----  LED ON/OFF  --------------
            if a == "1":
                if btn_stat == 0:
                    GPIO.output(17,1)
                    print("LED_On\n")
                    btn_stat = 1
                else:
                    GPIO.output(17,0)
                    print("LED_Off\n")
                    btn_stat = 0

        #-----  Port Clear  -----------------
            elif a == "2":
                GPIO.cleanup()  
                print("IO_Clear\n")

        #-----  Measure temp  -----------------
            elif a == "3":
                print("Measurement\n")

        #-----  Data transfer  --------------
            elif a == "80":
                print("Data transfer\n")
                self.send_response(200)
                self.send_header('Content-type', "text/plain")
                self.end_headers()

                buf = str(btn_stat)
                buf += ','
                a = self.measure_temp()
                buf += str(f'{a:.1f}')
                buf += ','
                self.wfile.write(buf.encode())

                fl = 0
        #-------------------------------------

        else :
            fl = 0

        if fl == 1:
            f = open("index_05.html",'rb')
            self.send_response(200)
            self.send_header('Content-type', "text/html")
            self.end_headers()
            self.wfile.write(f.read())
            f.close()

    #-------------------------------------------------
    def chk_file(self):
        a=0
        if self.path == "/":
            self.path = "/index_05.html"
            dataType = "text/html"
            a=1
        if self.path.endswith(".css"):
            dataType = "text/css"
            a=1
    
        if self.path.endswith(".js"):
            dataType = "application/javascript"
            a=1
    
        if a == 1:
            self.path = "." + self.path
            f = open(self.path,'rb')
            self.send_response(200)
            self.send_header('Content-type', dataType)
            self.end_headers()
            self.wfile.write(f.read())
            f.close()
        return a

    #-------------------------------------------------
    def measure_temp(self):

        # 13bit mode
        self.bus.write_byte_data(0x48, 0x03, 0x00)
        word_data = self.bus.read_word_data(0x48, 0x00)

        data = (word_data & 0xff00) >> 8 | (word_data & 0xff) << 8
        data /= 128
        return(data) 

#---------------------------------------------------------

host = ''
port = 8080
httpd = HTTPServer((host, port), MyHandler)
print('serving at port', port)
httpd.serve_forever()
  • 5行目: import smbus
    • I2C用モジュールのインポート
  • 41から43行: 測定実行箇所
    • 追加した測定開始用ボタンが、name=’3’ としているので、ボタンを押すとここが実行されます。
    • クライアントに状態を送る直前に温度を測定する事にしたので実はここでは温度を測定していません
    • print(“Measurement\n”)でターミナルに、”Measurement”するだけです。
  • 52から56行: 送信データの作成
    • この部分でクライアントに送るデータを作成
    • 前回は、ボタンの状態を示すパラメターが1個でしたが、今回は温度のデータが加わり全部で2個
    • この送信データを文字列に変換しています。また各データの区切に”,”を使用しています。
    • 送信データは、”ボタンの状態,温度,”となります。

JavaScript(http_server_05.js)

http_server_05.js

    var url = "http://raspberrypi.local:8080/?80=0";
    var xhr = new XMLHttpRequest();	
    var str;
    var para=['0','0','0'];

    xhr.open('GET', url);
    xhr.send();
     
    xhr.onreadystatechange = function() 
    {
      if(xhr.readyState === 4 && xhr.status === 200) 
      {
        console.log( xhr.responseText );

        b=0;
        for(a = 0; a < 2; a++)
   		{
            para[a]='';
   		    while( xhr.responseText[b] != ',') 
            {
                para[a] += xhr.responseText[b];
   		        b ++;
            }
            b ++; 
        }

        str = "OFF";
        if(Number(para[0])) str = "ON";
        document.getElementsByName('1')[0].innerHTML = str;

        document.getElementById('1').innerHTML = para[1] + "℃";
      }
    }
  • 4行目: パラメター保存用配列の宣言
  • 13行目: console.log( xhr.responseText );
    • サーバから送信されたデータの確認
  • 15から25行: 送られて来た文字列からデータの取り出し
    • ”,”を区切りに送られて来たデータをパラメータ保存用配列に読み込んでいます。
  • 31行目: 温度の表示
    • document.getElementsByName(‘1’)[0].innerHTML= para[1] + “℃”; で温度を表示

CSSファイル(http_server_05.css)

ボタンの大きさを変更

http_server_05.css

@charset "UTF-8";

.t_font {
        font-size: 40px;
        font-weight:bold;
        font-style: italic;
        color: #0ff;
}

.b_frame {
        width: 400px;
        background: #363636;
        padding: 15px;
        border-radius: 10px;
        margin-top: -30px;
        margin-right: 10px;
        color: #EFEFEF;
}

button {
        display: block;
        margin: 10px;
        line-height: 30px;
        cursor: pointer;
        color: #fff;
        background: #228b22;
        border-radius: 10px;
        font-size: 24px;
	    width:120px;
}

温度が表示されるプロセスを簡単に説明

  1. クライアントから、温度測定のリクエストが発生。(measureボタンを押す)
  2. サーバはリクエストの状況(name=’3’)から — Measure temp —– 以下を実行
  3. ここでは、ターミナルに、”Measurement”するだけ
  4. flを変更していないので64行目から、”index_05.html”がクライアントに送信される
  5. 送信が完了すると、クライアントからデータの要求が発生
  6. サーバはこの要求を受けて、ボタンの状態と温度の値を文字列にしてクライアントに送信
  7. データを受けたクライアントはJavaScriptでボタンと温度の値を更新

プログラムの実行

いつもとおり、全てを同じディレクトリに保存して、”python3 hello_05.py”と実行して下さい。

ブラウザで、”raspberrypi.local:8080″と入力すれは、画面が出ます。

ブラウザの開発モード

どのブラウザでも同じような機能はあると思うのですが、FireFoxの場合

  1. 右上にある3本線をクリック
  2. 出て来たウインドウで、ウェブ開発をクリック
  3. 次のウインドウで、ウェブコンソールをクリック
  4. JavaScriptで使用した、console.log( xhr.responseText ); が、この箇所に表示されます。
    • サーバから送られて来たデータは、”0,21.7,”
    • 最初のデータはLEDボタン表示用で、0が”OFF”。1が”ON”になります。
    • 次が温度データ。今回は21.7。
    • これらの値をJavaScriptで処理しHPに反映する。

この開発モードには他にも色々便利な機能が有ります。例えば

  1. 画面中央のネットワークをクリック
  2. その後HPの、”Measure”ボタンをクリック
  3. 画面に通信の状態が表示される
    1. Measureボタンが押されると GETリクエストでクエリは、/?3=0
    2. GETリクエストでhttp_server_05.CSSファイルが要求され
    3. 同じ様にScriptファイルが要求される
    4. 最後に/?80でサーバにデータを要求