Raspberry pi Zero で オフィス環境の可視化 その1
Raspberry Pi Zero にセンサーを付けて、各種データを集める。
登場するセンサー
- 温湿度センサー AM2302 > AM2320 に変更
- 気圧センサー SCP1000-D01
- CO2センサー K30
Raspberry pi Zero セットアップ
Micor SDカードを SDformatter でフォーマット
公式サイトからダウンロードしてきた 2016-11-25-raspbian-jessie-lite を Win32DiskImager で焼く
挿してBoot
OS 設定
- 色々入れる
rpi-update, vim, build-essential, python-dev
alias vi='vim'
- international
locale, timezone, keybord [Generic 105-Key(Intel) PC] [japanese]
- 日本語フォントとターミナル
apt-get install -y fonts-takao ibus-mozc jfbterm
- SSH ON
systemctl enable ssh
- 新規ユーザーの作成とグループへの追加
piからsudo剥奪 sudo gpasswd -d pi sudo
# usermod -G pi,adm,dialout,cdrom,sudo,audio,video,plugdev,games,users,input,netdev,spi,i2c,gpio _USERNAME_ # visudo
- IP固定
/etc/dhcpcd.conf
interface eth0 static ip_address=192.168.100.88/24 static routers=192.168.100.1 static domain_name_servers=192.168.100.1
GPIOピン付
はんだ付けする。
40PIN メスを付けました。
AM2302
Special instructions of the single-bus communication:
1.Typical application circuit recommended in the short cable length of 30 meters on the 5.1K pull-up resistor pullup resistor according to the actual situation of lower than 30 m.
2.With 3.3V supply voltage, cable length shall not be greater than 100cm. Otherwise, the line voltage drop will lead to the sensor power supply, resulting in measurement error.
3.Read the sensor minimum time interval for the 2S; read interval is less than 2S, may cause the temperature and humidity are not allowed or communication is unsuccessful, etc..
4.Temperature and humidity values are each read out the results of the last measurement For real-time data that need continuous read twice, we recommend repeatedly to read sensors, and each read sensor interval is greater than 2 seconds to obtain accuratethe data.
5.1kΩ のプルアップ抵抗が必要ですが、手元にないので、4.7kΩ を入れました。
動作テスト
adafruit さんのスクリプトをありがたく使わせて頂く。
$ git clone https://github.com/adafruit/Adafruit_Python_DHT.git $ git clone https://github.com/adafruit/Adafruit_Python_DHT.git $ cd Adafruit_Python_DHT $ sudo python setup.py install $ $ cd examples/ $ sudo python ./AdafruitDHT.py 2302 4 Temp=24.9* Humidity=46.0%
動いた。
コーディング
#!/usr/bin/python import sys import time import Adafruit_DHT sensor = Adafruit_DHT.AM2302 pin = 4 if __name__ == '__main__': try: while 1: # Try to grab a sensor reading. Use the read_retry method which will retry up # to 15 times to get a sensor reading (waiting 2 seconds between each retry). humidity, temperature = Adafruit_DHT.read_retry(sensor, pin) # Un-comment the line below to convert the temperature to Fahrenheit. # temperature = temperature * 9/5.0 + 32 # Note that sometimes you won't get a reading and # the results will be null (because Linux can't # guarantee the timing of calls to read the sensor). # If this happens try again! if humidity is not None and temperature is not None: print( 'Temp={0:0.1f}dc'.format(temperature) ) print( 'Humidity={0:0.1f}%'.format(humidity) ) # print('Temp={0:0.1f}D Humidity={1:0.1f}%'.format(temperature, humidity)) else: print('Failed to get reading. Try again!') time.sleep(3) except KeyboardInterrupt: sys.exit(0)
動かしてみて(追記)
数日運用して気がついたのですが、2つ問題が発生。
1. 結構簡単に止まる
2. 変に低い値が出る
電圧低下が原因とも思えないし、、、調査中です。
3.3v でも動作するので、
Vcc を GPIO にして、定期的に 通電/遮断 を繰り返せば、何とかごまかせますが、おかしいと思う。
AM2320
上記問題点をクリアできなかったので、AM2320 に乗り換えてみます。
配線
AM2302 とは異なり、I2C でつなぎます。
動作チェック
$ lsmod | grep i2c i2c_bcm2708 5740 0 i2c_dev 6578 2 $ ls /dev/i2c-* /dev/i2c-1 $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- $ sudo i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- 5c -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
コーディング
こちらを基に、コーディング。
温湿度センサAM2320をRaspberry Pi 3で使用する|wizqro.net
データシートにもには、まだ目を通して居ませんが、
i2cdetect -y 1 を繰り返すたびに、出てきたり出てこなかったりを繰り返していのは、先にreadする必要があるのかな?
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import time import smbus i2c = smbus.SMBus(1) address = 0x5c if __name__ == '__main__': try: while 1: # センサsleep解除 try: i2c.write_i2c_block_data(address,0x00,[]) except: pass # 読み取り命令 time.sleep(0.003) i2c.write_i2c_block_data(address,0x03,[0x00,0x04]) # データ受取 time.sleep(0.015) block = i2c.read_i2c_block_data(address,0,6) humidity = float(block[2] << 8 | block[3])/10 temperature = float(block[4] << 8 | block[5])/10 print('Temp={0:0.1f}D Humidity={1:0.1f}%'.format(temperature, humidity)) time.sleep(10) # SQL にデータを投げます # ... except KeyboardInterrupt: sys.exit(0)
実際には、SQLにデータを投げる処理も行っています。
注意点 Repeated Start Condition
Raspberry Pi で I2C の Repeated Start Condition を有効化 - Rabbit Note
/etc/modprobe.d/i2c.conf
options i2c_bcm2708 combined=1
データシートにも Repeated Start condition setup time 4.7
と表記がある。
SCP1000-D01
SPI通信なので、まず有効にします。
raspi-config > advanced > spi
Wiringpi をインストール
$ git clone git://git.drogon.net/wiringPi $ cd wiringPi/ $ ./build
以下のサイトを参考にさせていただいております。
ArduinoにSPI通信を行う機器を接続する(6) - フィジカル・コンピューティング
特に、コードは「意伝子発信器」さんのコードを改変して作りました。
レジスタ
サンプルを見ると、
レジスタ + 1/0 + 0
がひと固まりだとわかる。
B1 は常に 0
B2 は Read=0,Write=1
だ。
Address を、bite にする計算。
例) 0x06 RSTR "ASIC software reset" W Direct 8bits
の場合、
16進数 0x06
2進数 b110
Writeと 0 をお尻に足す b11010
16進数 0x1A
リセット命令 0x06,W,0 b11010, 0x1A
ステータス取得 0x07,R,0, b11100, 0x1C
オペレーションモード設定 0x03,R,0 0x0E
コーディング
とりあえず動くコード
#include<wiringPiSPI.h> #include<wiringPi.h> #include<stdio.h> #include<stdlib.h> #define SPI_CHANNEL 0 #define SPI_CLK 500000 int main(void){ double temp, pressure = 0; unsigned char buf[3]; int i,flag1=0, flag2=0; //wiringPiライブラリの初期化 if (wiringPiSetup () == -1){ return (1) ; } //SPIデバイスの初期化 if((wiringPiSPISetup(SPI_CHANNEL, SPI_CLK))<0){ printf("error SPI\n"); } //ソフトリセットコード buf[0] = 0x1a; buf[1] = 0x01; wiringPiSPIDataRW(SPI_CHANNEL, buf, 2); printf("delay...\n"); delay(60); //STATUS確認 buf[0] = 0x1c; buf[1] = 0xff; wiringPiSPIDataRW(SPI_CHANNEL, buf, 2); printf("STATUS:%02x\n", buf[1]); i= buf[1]&0x01; if(i == 0){ flag1 = 1; printf("STATUS OK!\n"); } //DATARD8確認 buf[0] = 0x7c; buf[1] = 0xff; wiringPiSPIDataRW(SPI_CHANNEL, buf, 2); printf("DATARD8:%02x\n", buf[1]); i= buf[1]&0x01; if(i == 1){ flag2 = 1; printf("DATARD8 OK!\n"); } if(flag1!=1 || flag2!=1){ printf("Error...\n"); exit(1); } //オペレーションレジスタに高精度測定モードを設定 buf[0] = 0x0e; buf[1] = 0x0a; wiringPiSPIDataRW(SPI_CHANNEL, buf, 2); //メインループ while(1){ //温度の測定 buf[0] = 0x84; buf[1] = 0x00; buf[2] = 0x00; wiringPiSPIDataRW(SPI_CHANNEL, buf, 3); temp = (double)((buf[1] << (8+2)) + (buf[2] << 2)) / 20 / 4; //気圧の測定 buf[0] = 0x7c; buf[1] = 0x00; wiringPiSPIDataRW(SPI_CHANNEL, buf, 2); pressure = buf[1] << 16; buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x01; wiringPiSPIDataRW(SPI_CHANNEL, buf, 3); pressure += (buf[1] << 8) + buf[2]; pressure = pressure / 4 / 100; printf("temp %2.2f\n", temp); printf("press %4.4f\n", pressure); delay(1000); } }