t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

ラズパイ本番機でカロリー記録&運動時間記録システムの運用開始

しばらくRaspberry Piの開発機側で運用していたカロリー記録システムと合わせて、最近完成した運動時間記録システムをラズパイの本番機にデプロイした。

動作イメージ

以下の5つのプログラムが動作中。
f:id:t-hom:20210228130148p:plain

体重記録だけはデーモン化してあるので表には出てない。

グラフ3種は外部から通信が入った時にそれらに応じて自動で切り替わるようになっていて、体重計に乗ると体重グラフが、M5 Stackで運動量を記録すると運動量グラフが、M5 Stackでカロリー摂取量0キロカロリーを送付するとカロリーグラフが最前面に表示される。

グラフ切替の仕組み

それぞれのグラフに対する入力があった際に単にプロセスをKillして再度起動させているために最前面に上がってくるだけ。
リアルタイムに更新させたかったけど今のところそんなスキルはない。

カロリーだけ0キロを送らなければいけない仕様にしたのもその関係で、摂取カロリーは連続で入力するのでそのたびグラフの再起動は避けたいからだ。

グラフはtkinterに埋め込んでいて、pythonプログラムのプロセス名を変更するライブラリを使用しているので他のプログラムから用意にプロセスを特定してKillできる。
プロセス間通信とかでKillしなくても更新できる方法を模索したこともあったけど一旦挫折した。

グラフをtkinterに埋め込む部分のコード

変更点に関係するところだけ掲載。
※変更前コードはブログ紹介用にコメントで残したが実際は綺麗に消えてる。

import setproctitle as sp
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime, date, timedelta

#tkinterとFigureCanvasTkAggをインポート
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


#データ加工関係は省略。以前の記事をご参照ください。

#前回はfigやaxを作らずに直接pltにbarを出力していた。
fig, ax = plt.subplots()
 
#plt.title("Calorie Record", fontsize = 22)

#plt.xlabel("Date", fontsize = 22)
ax.set_xlabel('Date')

#plt.ylabel("Calorie", fontsize = 22)
ax.set_ylabel('Calorie')

#plt.grid(True)\
ax.grid(True)
 

#plt.bar(record_date, maximum-minimum, width=0.25, bottom = minimum, tick_label = record_date, align="center", label="Guideline", color = "#98fb98", edgecolor="#008000", lw=0, hatch="/////")
ax.bar(record_date, maximum-minimum, width=0.25, bottom = minimum, tick_label = record_date, align="center", label="Guideline", color = "#98fb98", edgecolor="#008000", lw=0, hatch="/////")

#plt.bar(record_date, breakfast, width=0.2, tick_label = record_date, align="center", label="Breakfast", color = "#f3d394")
ax.bar(record_date, breakfast, width=0.2, tick_label = record_date, align="center", label="Breakfast", color = "#f3d394")

#plt.bar(record_date, lunch, width=0.2, bottom = breakfast, tick_label = record_date, align="center", label="Lunch", color = "#45938b")
ax.bar(record_date, lunch, width=0.2, bottom = breakfast, tick_label = record_date, align="center", label="Lunch", color = "#45938b")

#plt.bar(record_date, dinner, width=0.2, bottom = breakfast+lunch, tick_label = record_date, align="center", label="Dinner", color = "#003a34")
ax.bar(record_date, dinner, width=0.2, bottom = breakfast+lunch, tick_label = record_date, align="center", label="Dinner", color = "#003a34")

#plt.show()

def _destroyWindow():
    root.quit()
    root.destroy()

root = tk.Tk()
root.title(u"Calorie Intake Graph")
root.configure(bg='black')
root.withdraw()
root.protocol('WM_DELETE_WINDOW', _destroyWindow)

#ここでfigをcanvasに入れてルートウインドウの配下にする。
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(fill=tk.BOTH,expand=1)

root.update()
root.attributes("-zoomed", "1")
root.deiconify()
root.mainloop()

matplotlibってサイトによって書き方がまちまちでうまく行く方法を探すのに苦労した。
棒グラフをpltじゃなくてfigを作ってaxにプロットするサンプルを探し回ってなかなか思うようなコードが見つからずに苦労したんだけど結局たどり着いたのは本家matplotlibのサイト。

ここにそのままやりたいことが載ってた。やっぱ一時情報を当たるべきだな。。英語だけど下手な日本語解説より分かりやすかったりする。
matplotlib.org

figに入ってしまえばあとはtkに乗せるだけ。これは体重グラフで実績があるので楽勝だった。

開発からデプロイまでのフロー

以前はすべてのファイルをWinSCPで本番機に連携していたけど、管理にGitHubを使い始めたので少しマシになった。
f:id:t-hom:20210228135500p:plain

本当はClientで開発してDevにPushした後にDevでPullしてテストって方向で考えてたんだけど、実機でしかうまく動かない部分も出てくるし折角Vim使えるのにわざわざローカルで開発するのも面倒くさくて、結局開発は従来通り実機でやってしまった。そういう意味でラズパイ開発機は、いわゆるTest環境じゃなくて本当の意味でDev環境として使っている。

本番機の変更管理

デプロイの際の本番変更もしっかり管理。
f:id:t-hom:20210228125744p:plain

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。