かなり前にも書きましたが、I2C接続の2行表示のディスプレイに、手持ちのセンサーなどから取得した情報を表示してみます
表示する情報は以下の内容
- 現在の日付、時間
- CPU使用率と温度、メモリの使用量と全量
- ホスト名
- IPアドレスと、それを保持するインターフェース名
- 温度と大気圧
- 温度と湿度
使用した機器です(本体、Raspberry Pi は除く)
いろいろと似たようなものがありますが、手持ちのものと同じものです
温度・湿度センサー
手持ちのものと同じものが見つかりませんでしたが、I2C接続できる「SHT3X」という型番で探しました。たぶん、大丈夫
温度・大気圧センサー
上の温度センサーの値と、この温度センサーの値が、ちょっと異なるんですよね。1℃くらい。
ソースコード
情報を1秒ごとに表示します
以前の内容から、少し変えています
from time import sleep
import smbus
class i2c:
''' i2cクラス '''
# i2c オブジェクト
i2c = None
# i2c アドレス
ADR = None
def __init__(self, adr, bus = 1) -> None:
''' コンストラクタ '''
self.ADR = adr
self.i2c = smbus.SMBus(bus)
def readS8(self, register):
''' 符号あり8ビット読込 '''
result = self.i2c.read_byte_data(self.ADR, register)
if result > 127:
# 符号算出
result -= 256
return result
def readS16(self, register):
''' 符号あり16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) '''
hi = self.readS8(register)
lo = self.readU8(register+1)
return (hi << 8) + lo
def readU8(self, register):
''' 符号なし8ビット読込 '''
result = self.i2c.read_byte_data(self.ADR, register)
return result
def readU16(self, register):
''' 符号なし16ビット読込(アドレス値は指定8ビット と 指定8ビット + 1) '''
hi = self.readU8(register)
lo = self.readU8(register+1)
return (hi << 8) + lo
def readBlockData(self, register, blocks):
''' 指定ブロック読込 '''
block = self.i2c.read_i2c_block_data(self.ADR, register, blocks)
return block
def write8(self, register, value):
''' 8ビット書込 '''
self.i2c.write_byte_data(self.ADR, register, value)
def writeByte(self, value):
''' 8ビット書込 '''
self.i2c.write_byte(self.ADR, value)
class SHT3X:
''' 温度・湿度センサー '''
SHT3X_FREQ_MSB = 0x23
SHT3X_FREQ_LSB = 0x34
SHT3X_READ_MSB = 0xe0
SHT3X_READ_LSB = 0x00
SHT3X_READ_ADR = 0x00
I2C_ADR = 0x44
i2c = None
def __init__(self) -> None:
''' コンストラクタ '''
# i2cオブジェクト
self.i2c = i2c(self.I2C_ADR)
def calcTemperatureHumidity(self):
''' 温度と湿度を算出 '''
# 測定頻度の設定
self.i2c.write8(self.SHT3X_FREQ_MSB, self.SHT3X_FREQ_LSB)
sleep(0.5)
# 測定値の読出し
self.i2c.write8(self.SHT3X_READ_MSB, self.SHT3X_READ_LSB)
sleep(0.5)
# 6バイト取得
d = self.i2c.readBlockData(self.SHT3X_READ_ADR, 6)
# 0~1バイトが温度
# 測定データ(生データ)を取得
t = ((d[0]) << 8) | (d[1])
# 換算する
t = -45 + (175 * t / 65535)
# 3~4バイトが湿度
# 測定データ(生データ)を取得
h = ((d[3]) << 8) | (d[4])
# 換算する
h = 100 * h / 65535
# 結果を返却
return t, h
class BMP085:
''' 温度・大気圧センサー '''
BMP085_CAL_AC1 = 0xAA
BMP085_CAL_AC2 = 0xAC
BMP085_CAL_AC3 = 0xAE
BMP085_CAL_AC4 = 0xB0
BMP085_CAL_AC5 = 0xB2
BMP085_CAL_AC6 = 0xB4
BMP085_CAL_B1 = 0xB6
BMP085_CAL_B2 = 0xB8
BMP085_CAL_MB = 0xBA
BMP085_CAL_MC = 0xBC
BMP085_CAL_MD = 0xBE
BMP085_CONTROL = 0xF4
BMP085_TEMPDATA = 0xF6
BMP085_PRESSUREDATA = 0xF6
BMP085_READTEMPCMD = 0x2E
BMP085_READPRESSURECMD = 0x34
MODE = 3
WAIT_TIME = [0.005, 0.014, 0.008, 0.026]
I2C_ADR = 0x77
i2c = None
def __init__(self) -> None:
''' コンストラクタ '''
# i2cオブジェクト
self.i2c = i2c(self.I2C_ADR)
def calibration(self):
''' キャリブレーション '''
# キャリブレーションデータ読込
self.cal_AC1 = self.i2c.readS16(self.BMP085_CAL_AC1)
self.cal_AC2 = self.i2c.readS16(self.BMP085_CAL_AC2)
self.cal_AC3 = self.i2c.readS16(self.BMP085_CAL_AC3)
self.cal_AC4 = self.i2c.readU16(self.BMP085_CAL_AC4)
self.cal_AC5 = self.i2c.readU16(self.BMP085_CAL_AC5)
self.cal_AC6 = self.i2c.readU16(self.BMP085_CAL_AC6)
self.cal_B1 = self.i2c.readS16(self.BMP085_CAL_B1)
self.cal_B2 = self.i2c.readS16(self.BMP085_CAL_B2)
self.cal_MB = self.i2c.readS16(self.BMP085_CAL_MB)
self.cal_MC = self.i2c.readS16(self.BMP085_CAL_MC)
self.cal_MD = self.i2c.readS16(self.BMP085_CAL_MD)
def readUncpmpensatedTemp(self):
''' センサーから温度を取得 '''
self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READTEMPCMD)
sleep(0.026)
raw = self.i2c.readU16(self.BMP085_TEMPDATA)
return raw
def readUncpmpensatedPressure(self):
''' センサーから気圧を取得 '''
self.i2c.write8(self.BMP085_CONTROL, self.BMP085_READPRESSURECMD + (self.MODE << 6))
sleep(self.WAIT_TIME[self.MODE])
msb = self.i2c.readU8(self.BMP085_PRESSUREDATA)
lsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+1)
xlsb = self.i2c.readU8(self.BMP085_PRESSUREDATA+2)
raw = ((msb << 16) + (lsb << 8) + xlsb) >> (8 - self.MODE)
return raw
def calcTemperaturePressure(self):
''' 温度と気圧を算出 '''
UT = self.readUncpmpensatedTemp()
UP = self.readUncpmpensatedPressure()
X1 = ((UT - self.cal_AC6) * self.cal_AC5) / 32768
X2 = (self.cal_MC * 2048) / (X1 + self.cal_MD)
B5 = X1 + X2
B6 = B5 - 4000
X1 = (self.cal_B2 * (B6 * B6) / 4096) / 2048
X2 = (self.cal_AC2 * B6) / 2048
X3 = X1 + X2
# 温度を算出しておく
temp = (B5 + 8) / 16 / 10
B3 = (((self.cal_AC1 * 4 + X3) * ( 2 ** self.MODE)) + 2) / 4
X1 = (self.cal_AC3 * B6) / 8192
X2 = (self.cal_B1 * ((B6 * B6) / 4096)) / 65536
X3 = ((X1 + X2) + 2) / 4
B4 = (self.cal_AC4 * (X3 + 32768)) / 32768
B7 = (UP - B3) * (50000 >> self.MODE)
if (B7 < 0x80000000):
press = int((B7 * 2) / B4)
else:
press = int((B7 / B4) * 2)
X1 = (press / 256 ) * (press / 256)
X1 = (X1 * 3038) / 65536
X2 = (-7357 * press) / 65536
press = press + ((X1 + X2 + 3791) / 16)
return temp, press
class LCD1602:
''' LCD '''
LCD_LINES = [0x80, 0xC0]
# LCDの1行目のアドレス
LCD_LINE_1 = 0x80
# LCDの2行目のアドレス
LCD_LINE_2 = 0xC0
# 1行あたりの文字数
LCD_WIDTH = 16
# バックライトのON/OFF(ON:0X08, OFF:0X00を指定)
LCD_BACKLIGHT = 0X08
LCD_CHR = 1
LCD_CMD = 0
ENABLE = 0b00000100
E_PULSE = 0.0005
E_DELAY = 0.0005
I2C_ADR = 0x27
i2c = None
def __init__(self) -> None:
''' コンストラクタ '''
# i2cオブジェクト
self.i2c = i2c(self.I2C_ADR)
def calibration(self):
''' キャリブレーション '''
self.writeByte(0x33, self.LCD_CMD)
self.writeByte(0x32, self.LCD_CMD)
self.writeByte(0x06, self.LCD_CMD)
self.writeByte(0x0C, self.LCD_CMD)
self.writeByte(0x28, self.LCD_CMD)
self.writeByte(0x01, self.LCD_CMD)
sleep(self.E_DELAY)
def writeByte(self, bits, mode):
''' LCDへの書き込み '''
bits_high = mode | (bits & 0xF0) | self.LCD_BACKLIGHT
bits_low = mode | ((bits << 4) & 0xF0) | self.LCD_BACKLIGHT
self.i2c.writeByte(bits_high)
self.writeByteSub(bits_high)
self.i2c.writeByte(bits_low)
self.writeByteSub(bits_low)
def writeByteSub(self, bits):
''' LCDへの書き込み(サブ) '''
sleep(self.E_DELAY)
self.i2c.writeByte(bits | self.ENABLE)
sleep(self.E_DELAY)
self.i2c.writeByte(bits & ~self.ENABLE)
sleep(self.E_DELAY)
def dispString(self, message: str, dispLine):
''' LCDへの文字の表示(半角文字列のみ) '''
# 表示対象行の初期化
self.writeByte(self.LCD_LINES[dispLine], self.LCD_CMD)
# 文字列を1行あたりの文字数に調整
message = message.ljust(self.LCD_WIDTH)
# 表示処理
for dispIndex in range(self.LCD_WIDTH):
self.writeByte(ord(message[dispIndex]), self.LCD_CHR)
import socket
import psutil
import datetime
class RaspiInfo:
''' RaspberryPi情報 '''
@staticmethod
def getMemoryInfo():
''' メモリ情報(使用量[MB]、総量[MB])の取得 '''
mem = psutil.virtual_memory()
mem_used = round(mem.used / 1024 / 1024)
mem_total = round(mem.total / 1024 / 1024)
return mem_used, mem_total
@staticmethod
def getCpuTemp():
''' CPU温度の取得 '''
f = open("/sys/class/thermal/thermal_zone0/temp","r")
cpu_temp = 0
for t in f:
cpu_temp = t[:2]
# 小数点以下2桁まで表示する場合
# cpu_temp = t[:2]+"."+t[2:3]
f.close()
return cpu_temp
@staticmethod
def getCpupercent():
''' CPU使用率の取得 '''
cpu_percent = psutil.cpu_percent(interval=0)
return round(cpu_percent)
@staticmethod
def getHostName():
''' ホスト名の取得 '''
host_name = socket.gethostname()
return host_name
@staticmethod
def getIP():
''' IPアドレスとインターフェース名を取得 '''
for interface, snics in psutil.net_if_addrs().items():
for snic in snics:
if snic.address != '127.0.0.1' and snic.family == socket.AF_INET:
return snic.address, interface
return "none", "none"
# メイン処理
# LCDの初期化
lcd = LCD1602()
lcd.calibration()
# インスタンス生成
bmp = BMP085()
sht3x = SHT3X()
# 初期化
bmp.calibration()
while True:
# 現在日時
now = datetime.datetime.now()
lcd.dispString(f'date: {now.strftime("%Y/%m/%d")}', 0)
lcd.dispString(f'time: {now.strftime("%H:%M:%S")}', 1)
sleep(1)
# 「CPU温度」「CPU使用率」と「メモリ情報」
mem_info = RaspiInfo.getMemoryInfo()
lcd.dispString(f'cpu : {RaspiInfo.getCpuTemp()}\337C {RaspiInfo.getCpupercent()}%', 0)
lcd.dispString(f'mem : {mem_info[0]}/{mem_info[1]}MB', 1)
sleep(1)
# ホスト名
hostName = RaspiInfo.getHostName()
lcd.dispString(f'host:', 0)
lcd.dispString(f' {hostName}', 1)
sleep(1)
# IPアドレス
ip = RaspiInfo.getIP()
lcd.dispString(f'ip :', 0)
lcd.dispString(f'{str(ip[1])}:', 0)
lcd.dispString(f' {ip[0]}', 1)
sleep(1)
# 温度と大気圧(次の取得処理中でスリープしているので、ここでの表示後のスリープはしない)
tempPress = bmp.calcTemperaturePressure()
lcd.dispString(f'temp: {str(tempPress[0])[:5]}\337C', 0)
lcd.dispString(f'prss: {str(tempPress[1] / 100.0 )[:6]} hPa', 1)
# 温度と湿度
ht = sht3x.calcTemperatureHumidity()
lcd.dispString(f'temp: {str(ht[0])[:5]}\337C', 0)
lcd.dispString(f'humi: {str(ht[1])[:5]}%', 1)
sleep(1)