しばらくRaspberry Piの開発機側で運用していたカロリー記録システムと合わせて、最近完成した運動時間記録システムをラズパイの本番機にデプロイした。
動作イメージ
以下の5つのプログラムが動作中。
体重記録だけはデーモン化してあるので表には出てない。
グラフ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を使い始めたので少しマシになった。
本当はClientで開発してDevにPushした後にDevでPullしてテストって方向で考えてたんだけど、実機でしかうまく動かない部分も出てくるし折角Vim使えるのにわざわざローカルで開発するのも面倒くさくて、結局開発は従来通り実機でやってしまった。そういう意味でラズパイ開発機は、いわゆるTest環境じゃなくて本当の意味でDev環境として使っている。
本番機の変更管理
デプロイの際の本番変更もしっかり管理。
以上