import smbus2
import bme280
import datetime, time
import pygame
from pygame.locals import *
import sys, os
import csv
from enum import Enum
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.font_manager as mfontm
import matplotlib.dates as mdates
import concurrent.futures as cf
class CONST():
BME280_PORT = 1
BME280_ADDRESS = 0x76
PYGAME_SCREEN_SIZE = (480, 320)
LOG_INTERVAL = 5
LOG_DIR = "./BME280log/"
LOG_NAME = " BME280.log"
PIC_DIR = "./BME280log/"
PIC_NAME = " BME280.png"
PIC_SIZE = (4.8, 3.2)
LINE_WIDTH = 2
FONT_FILENAME = "ipag.ttf"
DATE_FONT_SIZE = 35
DATA_FONT_SIZE = 62
DATA_BACKGROUND_COLOR = (0, 0, 0)
DATA_FONT_COLOR = (255, 255, 255)
MESSAGE_FONT_SIZE = 20
MESSAGE_CORNER = 10
MESSAGE_BACKGROUND_COLOR = (255, 250, 240)
MESSAGE_FONT_COLOR = (0, 0, 0)
class MODE(Enum):
REALTIME = 1
WAITING = 2
GRAPH = 3
ERR_LOG_NOT_FOUND = 4
def main():
bus = smbus2.SMBus(CONST.BME280_PORT)
calibration_params = bme280.load_calibration_params(bus, CONST.BME280_ADDRESS)
pygame.init()
screen = pygame.display.set_mode((CONST.PYGAME_SCREEN_SIZE))
pygame.display.set_caption("温度・湿度・気圧計")
executor = cf.ThreadPoolExecutor(max_workers=2)
mode = MODE.REALTIME
old_time = time.perf_counter()
while True:
new_time = time.perf_counter()
if new_time - old_time >= 1:
old_time = new_time
data = bme280.sample(bus, CONST.BME280_ADDRESS, calibration_params)
screen.fill(CONST.DATA_BACKGROUND_COLOR)
if mode != MODE.GRAPH:
show_realtime_data(data, screen)
if mode == MODE.WAITING:
show_message_box("グラフ作成中...", screen)
if future.done():
mode = MODE.GRAPH
elif mode == MODE.GRAPH:
pic_filename = get_pic_filename()
image = pygame.image.load(pic_filename)
screen.blit(image,(0,0))
elif mode == MODE.ERR_LOG_NOT_FOUND:
show_message_box("ログがありません", screen)
pygame.display.update()
if data.timestamp.second == 0 and data.timestamp.minute % CONST.LOG_INTERVAL == 0:
log_filename = get_log_filename()
f = open(log_filename, "a")
writer = csv.writer(f)
csvrow = []
csvrow.append("{0:%Y/%m/%d %H:%M:%S}".format(data.timestamp))
csvrow.append("{0:.1f}".format(data.temperature))
csvrow.append("{0:.1f}".format(data.humidity))
csvrow.append("{0:.1f}".format(data.pressure))
writer.writerow(csvrow)
f.close()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if mode == MODE.REALTIME:
log_filename = get_log_filename()
if os.path.exists(log_filename):
future = executor.submit(create_graph)
mode = MODE.WAITING
else:
mode = MODE.ERR_LOG_NOT_FOUND
elif mode == MODE.GRAPH or mode == MODE.ERR_LOG_NOT_FOUND:
mode = MODE.REALTIME
time.sleep(0.1)
def get_log_filename(days_ago=0):
date = "{0:%Y.%m.%d}".format(datetime.date.today() - datetime.timedelta(days=days_ago))
return CONST.LOG_DIR + date + CONST.LOG_NAME
def get_pic_filename(days_ago=0):
date = "{0:%Y.%m.%d}".format(datetime.date.today() - datetime.timedelta(days=days_ago))
return CONST.PIC_DIR + date + CONST.PIC_NAME
def show_realtime_data(data, screen):
data_str = []
data_str.append("{0:%Y年%m月%d日 %H時%M分%S秒}".format(data.timestamp))
data_str.append("温度:{0:>6.1f} ℃".format(data.temperature))
data_str.append("湿度:{0:>6.1f} %".format(data.humidity))
data_str.append("気圧:{0:>6.1f} hPa".format(data.pressure))
myfont1 = pygame.font.Font(CONST.FONT_FILENAME, CONST.DATE_FONT_SIZE)
myfont2 = pygame.font.Font(CONST.FONT_FILENAME, CONST.DATA_FONT_SIZE)
render_str = []
render_str.append(myfont1.render(data_str[0], True, CONST.DATA_FONT_COLOR))
render_str.append(myfont2.render(data_str[1], True, CONST.DATA_FONT_COLOR))
render_str.append(myfont2.render(data_str[2], True, CONST.DATA_FONT_COLOR))
render_str.append(myfont2.render(data_str[3], True, CONST.DATA_FONT_COLOR))
screen.blit(render_str[0], (0, 10))
screen.blit(render_str[1], (0, 70))
screen.blit(render_str[2], (0, 155))
screen.blit(render_str[3], (0, 240))
def show_message_box(text, screen):
bgc = CONST.MESSAGE_BACKGROUND_COLOR
fc = CONST.MESSAGE_FONT_COLOR
cn = CONST.MESSAGE_CORNER
info = pygame.display.Info()
scr_w, scr_h = info.current_w, info.current_h
myfont = pygame.font.Font(CONST.FONT_FILENAME, 20)
mes = myfont.render(text, True, (0, 0, 0))
mes_w, mes_h = mes.get_size()
mes_l = (scr_w - mes_w) // 2
mes_t = (scr_h - mes_h) // 2
rect_w, rect_h = int(mes_w * 1.5), mes_h * 3
rect_l, rect_t = (scr_w - rect_w) // 2, (scr_h - rect_h) // 2
rect_r, rect_b = rect_l + rect_w, rect_t + rect_h
in_rect_l, in_rect_t, in_rect_r, in_rect_b = rect_l + cn, rect_t + cn, rect_r - cn, rect_b - cn
in_rect_w, in_rect_h = in_rect_r - in_rect_l, in_rect_b - in_rect_t
pygame.draw.circle(screen, bgc, (in_rect_l, in_rect_t), cn)
pygame.draw.circle(screen, bgc, (in_rect_r, in_rect_t), cn)
pygame.draw.circle(screen, bgc, (in_rect_l, in_rect_b), cn)
pygame.draw.circle(screen, bgc, (in_rect_r, in_rect_b), cn)
pygame.draw.rect(screen, bgc, (in_rect_l, rect_t, in_rect_w, rect_h))
pygame.draw.rect(screen, bgc, (rect_l, in_rect_t, rect_w, in_rect_h))
screen.blit(mes, (mes_l, mes_t))
def create_graph():
log_filename = get_log_filename()
pic_filename = get_pic_filename()
data = []
with open(log_filename, "r") as f:
reader = csv.reader(f)
for row in reader:
timestamp = datetime.datetime.strptime(row[0] ,"%Y/%m/%d %H:%M:%S")
data.append([timestamp, float(row[1]), float(row[2]), float(row[3])])
data = [list(x) for x in zip(*data)]
fp = mfontm.FontProperties(fname="./ipag.ttf")
fig = plt.figure(figsize=CONST.PIC_SIZE)
plt.subplots_adjust(left=0.07, bottom=0.15, top=0.9, right=1)
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax3 = ax1.twinx()
ax1.plot(data[0], data[1], color='orange', alpha=1.0, lw=CONST.LINE_WIDTH, antialiased=True)
ax2.plot(data[0], data[2], color='deepskyblue', alpha=0.6, lw=CONST.LINE_WIDTH, antialiased=True)
ax3.plot(data[0], data[3], color='green', alpha=0.8, lw=CONST.LINE_WIDTH, antialiased=True)
ax1.set_ylim(0, 40)
ax2.set_ylim(0, 100)
ax3.set_ylim(960, 1020)
ax1.yaxis.set_major_locator(ticker.MultipleLocator(5))
ax2.yaxis.set_major_locator(ticker.MultipleLocator(10))
ax3.yaxis.set_major_locator(ticker.MultipleLocator(10))
fig.subplots_adjust(right=0.80)
ax3.spines["right"].set_position(("axes", 1.13))
hoursfmt = mdates.DateFormatter("%H:%M")
ax1.xaxis.set_major_formatter(hoursfmt)
xlabels = ax1.get_xticklabels()
plt.setp(xlabels, rotation=45)
ax1.yaxis.set_label_coords(-0.045, 1.03)
ax2.yaxis.set_label_coords(1.07, 1.09)
ax3.yaxis.set_label_coords(1.21, 1.09)
ax1.set_ylabel("(℃)", fontproperties=fp, rotation=0)
ax2.set_ylabel("(%)", fontproperties=fp, rotation=0)
ax3.set_ylabel("(hPa)", fontproperties=fp, rotation=0)
fig.legend(["温度", "湿度", "気圧"], bbox_to_anchor=(0, 0), bbox_transform=ax1.transAxes, loc="lower left", prop=fp)
plt.savefig(pic_filename)
if __name__ == "__main__":
main()