LoginSignup
1
4

More than 5 years have passed since last update.

【Python + PHP】 Raspberry Piで気温・湿度・気圧モニターを作る

Posted at

 以前使っていたセンサーモジュール AE-BME280 が手元にあったので、ネットワーク内から簡単に参照できるようにしてみました。

 検証環境

 ・Raspberry Pi 2 Model B
 ・Raspbian Jessie Lite January 2017
 ・Apache 2.4.10
 ・PHP 5.6.29
 ・Python 2.7.9

 準備

 必要となるパッケージをインストールします。

$ sudo aptitude update
$ sudo apt-get install i2c-tools python-smbus apache2 php5

 ちなみに、なぜPython単体ではなくApacheとPHPを使用するかですが、単にPythonでWebホストする方法がわからなかっただけです。
 なのでセキュリティはガバガバです。あらかじめご了承ください。
 ローカル向けなのでポート開放をしてはいけない(戒め)

 センサーの接続

 http://deviceplus.jp/hobby/raspberrypi_entry_039/
 こ↑こ↓ を参考にRaspberry Piに接続します。

 Python側

 上記URL内のサンプルコードを少しいじっただけです。Python ワッカリマセーン

bme280.py
#coding: utf-8

import smbus
import time

bus_number  = 1
i2c_address = 0x76

bus = smbus.SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0


def writeReg(reg_address, data):
  bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
  calib = []

  for i in range (0x88,0x88+24):
    calib.append(bus.read_byte_data(i2c_address,i))
  calib.append(bus.read_byte_data(i2c_address,0xA1))
  for i in range (0xE1,0xE1+7):
    calib.append(bus.read_byte_data(i2c_address,i))

  digT.append((calib[1] << 8) | calib[0])
  digT.append((calib[3] << 8) | calib[2])
  digT.append((calib[5] << 8) | calib[4])
  digP.append((calib[7] << 8) | calib[6])
  digP.append((calib[9] << 8) | calib[8])
  digP.append((calib[11]<< 8) | calib[10])
  digP.append((calib[13]<< 8) | calib[12])
  digP.append((calib[15]<< 8) | calib[14])
  digP.append((calib[17]<< 8) | calib[16])
  digP.append((calib[19]<< 8) | calib[18])
  digP.append((calib[21]<< 8) | calib[20])
  digP.append((calib[23]<< 8) | calib[22])
  digH.append( calib[24] )
  digH.append((calib[26]<< 8) | calib[25])
  digH.append( calib[27] )
  digH.append((calib[28]<< 4) | (0x0F & calib[29]))
  digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
  digH.append( calib[31] )

  for i in range(1,2):
    if digT[i] & 0x8000:
      digT[i] = (-digT[i] ^ 0xFFFF) + 1

  for i in range(1,8):
    if digP[i] & 0x8000:
      digP[i] = (-digP[i] ^ 0xFFFF) + 1

  for i in range(0,6):
    if digH[i] & 0x8000:
      digH[i] = (-digH[i] ^ 0xFFFF) + 1  

def readData():
  data = []
  for i in range (0xF7, 0xF7+8):
    data.append(bus.read_byte_data(i2c_address,i))

  pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
  temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
  hum_raw  = (data[6] << 8)  |  data[7]

  return [compensate_T(temp_raw), compensate_H(hum_raw), compensate_P(pres_raw)]

def compensate_P(adc_P):
    global  t_fine
    pressure = 0.0

    v1 = (t_fine / 2.0) - 64000.0
    v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
    v2 = v2 + ((v1 * digP[4]) * 2.0)
    v2 = (v2 / 4.0) + (digP[3] * 65536.0)
    v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
    v1 = ((32768 + v1) * digP[0]) / 32768

    if v1 == 0:
        return 0
    pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
    if pressure < 0x80000000:
        pressure = (pressure * 2.0) / v1
    else:
        pressure = (pressure / v1) * 2
    v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
    v2 = ((pressure / 4.0) * digP[7]) / 8192.0
    pressure = pressure + ((v1 + v2 + digP[6]) / 16.0) 
    return pressure;

def compensate_T(adc_T):
  global t_fine
  v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
  v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
  t_fine = v1 + v2
  temperature = t_fine / 5120.0
  return temperature 

def compensate_H(adc_H):
  global t_fine
  var_h = t_fine - 76800.0
  if var_h != 0:
    var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))
  else:
    return 0
  var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)
  if var_h > 100.0:
    var_h = 100.0
  elif var_h < 0.0:
    var_h = 0.0
  return var_h


def setup():
  osrs_t = 1      #Temperature oversampling x 1
  osrs_p = 1      #Pressure oversampling x 1
  osrs_h = 1      #Humidity oversampling x 1
  mode   = 3      #Normal mode
  t_sb   = 5      #Tstandby 1000ms
  filter = 0      #Filter off
  spi3w_en = 0      #3-wire SPI Disable

  ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
  config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
  ctrl_hum_reg  = osrs_h

  writeReg(0xF2,ctrl_hum_reg)
  writeReg(0xF4,ctrl_meas_reg)
  writeReg(0xF5,config_reg)
now.py
# coding: utf_8

import bme280 as bme

bme.setup()
bme.get_calib_param()
data = bme.readData()

print str(data[0]) + "," + str(data[1]) + "," + str(data[2] / 100)

 now.py の出力部分については、各数値をコンマ区切り(気温,湿度,気圧)で出力しています。
 また、気圧はPaで出力されるので100で割ってhPaにしています。

 sudo の壁

 このPythonプログラム、実行しようとするとsudo権限が必要になります。よって
 sudo python now.py と実行するわけですが、PHPのexec()からsudo使えません。
 なのでsudoers変えちゃいましょう。(セキュリティ?知らない子ですねぇ。)
 以下の行を追記します。

/etc/sudoers
www-data ALL=(root) NOPASSWD: ALL

 PHP 側

 あとはPython呼び出すだけです。
 適当にデザインしました。

index.php
<?php $data = explode(",", exec("sudo python now.py")); ?>
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Temp Monitor</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="css/font-awesome.min.css">
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-md-4" align="center" style="padding: 20px 10px">
          <h2><i class="fa fa-thermometer-three-quarters"></i></h2>
          <span class="num-large"><?= substr($data[0], 0, 2) ?></span>
          <span class="num-small"><?= substr($data[0], 2, 3) ?> ℃</span>
        </div>
        <div class="col-md-4" align="center" style="padding: 20px 10px">
          <h2><i class="fa fa-tint"></i></h2>
          <span class="num-large"><?= substr($data[1], 0, 2) ?></span>
          <span class="num-small"><?= substr($data[1], 2, 3) ?> %</span>
        </div>
        <div class="col-md-4" align="center" style="padding: 20px 10px">
          <h2><i class="fa fa-tachometer"></i></h2>
          <span class="num-large"><?= substr($data[2], 0, 4) ?></span>
          <span class="num-small"><?= substr($data[2], 4, 3) ?> hPa</span>
        </div>
      </div>
      <br>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  </body>
</html>
css/style.css
body {
  background-color: #272727;
  color: #fff;
  font-family: "Segoe UI Light", sans-serif;
}

.num-large {
  font-size: 5em;
}

.num-small {
  font-size: 3em;
}

 おわりに

 基本的にガバガバです。気にしないでください。
 もっと良い書き方はいくらでもあります。

 リンク

 ・ラズベリーパイで温度・湿度・気圧をまとめて取得!AE-BME280でIC2通信 | Device Plus - デバプラ
  http://deviceplus.jp/hobby/raspberrypi_entry_039/

 ・Font Awesome, the iconic font and CSS toolkit
  http://fontawesome.io/

 ・Bootstrap · The world's most popular mobile-first and responsive front-end framework.
  http://getbootstrap.com/

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4