posted by rerofumi
2015/12/19 土曜日 17:11:03
前回 RaspberryPi2 に気圧センサーと気温/湿度センサーを付けて値を読み取れるようにした。
ぱっと見良さそうだったのだけれども、しばらくコレで計測を続けてみるとどうも湿度が正しく変動していない様に見受けられた。
たまたま使った DHT11 の個体不具合っぽい。自分の目的的に湿度はおまけみたいなものだったけれども、計測できないとなるとなんか悔しくなってきたので作り直すことにした。
その際、ワンワイヤーシリアルだった DHT11 の代わりに I2C の AM2310 に変更を行った。これで I2C に統一できる。
気圧センサは手持ち在庫の関係で LPS25H ではなく LPS331AP に、現在は LPS25H の方が在庫品になっているのでそっちで読み替えて貰うとありがたい。
AM2310 のインターフェースは I2C だが、なんとなく扱いはワンワイヤーに近い感じでちょっと変な扱いとなる。具体的にはリクエストコマンドを 3byte 投げた後ストップシーケンスにせずそのままデータを受け取っていく。
この表現が wiringpi のライブラリで上手く呼べなかったので困っていたら、先達が ruby でのコードを公開してくれていた。
「Raspberry PIで温度湿度センサーをRubyで動かす」
ありがたいのでこれをそのまま使わせて頂くことにする。
ruby gem の ‘i2c’ パッケージを使っているので、LPS331AP の読み取りも i2c パッケージを使うことにする。
読み取りコードはこんな感じ。
#!/usr/bin/ruby require 'i2c' require 'net/http' require 'uri' DEVICE = "/dev/i2c-1" HOST = 'http://nanlog.local:8080/' VERB = false # ----------------------------- class Lps331ap def initialize(path, address=0x5d) @device = I2C.create(path) @address = address end def writeCommand(address, data) send = [ address, data ].pack("c*") @device.write(@address, send) end def readCommand(address) # Wake up sensor begin writeCommand(0x20, 0x90) rescue # ignore end begin s = @device.read(@address, 1, address) rescue return nil end return s.bytes[0] end def init live = readCommand(0x0f) if (live != 0xbb) then return false end writeCommand(0x20, 0x90) sleep(1.5) end def pressure a = readCommand(0x2a) b = readCommand(0x29) c = readCommand(0x28) d = (a * 0x10000) + (b* 0x100) + c d = d / 4096.0 return d end def temp a = readCommand(0x2c) b = readCommand(0x2b) c = (a * 0x100) + b if c > 0x7fff then c = c - 65536 end d = 42.5 + (c / 480.0) return d end end # ----------------------------- class AM2321 def initialize(path, address = 0x5c) @device = I2C.create(path) @address = address end def crc16(data) crc = 0xFFFF data.each do |b| crc ^= b; 8.times do if (crc & 0x01) != 0 then crc = crc >> 1 crc ^= 0xA001 else crc = crc >> 1 end end end return crc end def read # Wake up sensor begin @device.write(@address, "") rescue # ignore end # Read sensor values begin s = @device.read(@address, 8, "\x03\x00\x04") rescue return nil end func_code, ret_len, hum_h, hum_l, temp_h, temp_l, crc_l, crc_h = s.bytes.to_a orig_crc = (crc_h << 8) | crc_l hum = (hum_h << 8) | hum_l temp = (temp_h << 8) | temp_l # Calc CRC crc = crc16(s[0,6].bytes) return nil if crc != orig_crc return hum/10.0, temp/10.0 end end # ----------------------------- class IotPost def initialize(host) @server = host end def post(tag, body) uri = URI.parse(@server+tag) http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.request_uri) req.body = body res = http.request(req) printf("http request %d\n", res.code) if VERB end end # ----------------------------- # --- main # ----------------------------- sense = Lps331ap.new(DEVICE) sense.init press = sense.pressure temp = sense.temp printf("%f hPa\n", press) if VERB printf("%f *C\n", temp) if VERB sense2 = AM2321.new(DEVICE).read printf("%f \%\n", sense2[0]) if VERB printf("%f *c\n", sense2[1]) if VERB logger = IotPost.new(HOST) logger.post('100yo_temp', temp.to_s) logger.post('100yo_pressure', press.to_s) logger.post('100yo_temp2', sense2[1].to_s) logger.post('100yo_humidity', sense2[0].to_s)
コードの中に結果をロガーに向けて POST しているところがあるけれども、この辺は次回の説明にて。
Leave a Reply