人工無能ハウスキーパー的なものを作る(LINE Notify)

こんにちは。
今回は、LINE Notifyを使って家の状況を報告してくれるようなものを作ってみました。

目的

やりたいこと

RaspberryPiで集計している家の状況(温度・湿度・消費電力)のデータを、LINE Notifyを介して自分のスマホに送信し、外出中でも自宅の状況を確認できるようにします。
なお、LINE Notifyは相互のメッセージのやりとりはできません。基本的に、送信側からの一方通行のメッセージの送信のみになります。よって、あらかじめ送信タイミングをスケジューリングしておきます。
今回は、7:00, 12:00, 18:00, 21:00に送信させるようにします。

送信するデータは、送信時点の最新のデータと、当日および過去1週間分の取得データをプロットしたグラフを送信させる方針にします。
イメージ・・・というか実際に動かしてみたスクショが以下の画像の通りです。

こんな感じで部屋の状態をレポートしてくれます。

外で家の気温とか見てどうするんだ??という感じですが、外からエアコンの操作とかができるようになれば、家に帰る前に部屋の温度を確認して、エアコンのON/OFFや温度設定をしておく、といったことができます。
まあ、我が家ではできませんが・・・

製作

LINE Notify トークンの取得

以下の記事の手順に従ってLINE Notifyトークンを取得します。

トークン名は「ハウスキーパー家安(いえやす)君」としました。

コードの作成

今回はソフトウェアのみの製作になります。
Pythonを使ってソフトを作っていきます。
全てを載せたいところですが、コードが長くなってしまったのでポイントのみ載せます。

不快指数

温度と湿度から、不快指数というものが計算できます。
これは、夏の蒸し暑さを定量的に表現する指数で、温度と湿度という2次元量から1次元量で表現できるので感覚的にわかりやすくなります。
なお、計算式は次の通りです。

$$
0.81T + 0.01H(0.99T-14.3)+46.3
$$

(T:温度[℃], H:湿度[%])

ちなみに、不快指数と感じ方は以下の通りらしいです(Wikipediaより)。

$$
\begin{array}{c|l}
不快指数 & 体感 \\ \hline
~50 & 寒くてたまらない \\
50~55 & 寒い \\
55~60 & 肌寒い \\
60~65 & 何も感じない \\
65~70 & 快適 \\
70~75 & 不快感を持つ人が出始める \\
75~80 & 半数以上が不快に感じる \\
80~85 & 全員が不快に感じる \\
85~ & 暑くてたまらない \\
\end{array}
$$

私の体感では、74あたりから暑いと感じました。

SQLからのデータの取得

SQLデータベースは次の図のような構造になっています。
なお、データベースの名前は「dht11」です。

SQLデータベースの構造(温湿度)

ここから、今日を基準に何日か前のデータを取得するSQL文は次のようになります。
なお、日数は「daysAgo」という変数で指定しています。

SELECT time, temp, humid
	FROM dht11 
	WHERE
	date = DATE_SUB(CURDATE(), INTERVAL {daysAgo} DAY)

このSQL文を使ってpythonでデータを取得すると、時刻は「timeDelta型」という型になってしまいます。この型は、グラフ化等のデータを加工する上では非常に扱いづらいものです。
そこで、datetimeモジュールのstrptimeメソッドを使うことで、再びdatetime型に変換することができます。
ただし、日付は1900/1/1になってしまいます。日付毎に配列の別の要素として扱うなどの対処が必要になります。

以上を踏まえ、SQLから、今日を基準に数日分のデータを取得する処理を、pythonの関数として以下の通り作成しました。

# 不快指数の計算
def discomfort_index(temp, humid):
    di = 0.81*temp + 0.01*humid * (0.99*temp - 14.3) + 46.3
    return di


# SQLに接続する処理
def sql_connect():
	global cnx, cursor
	cnx = MySQLdb.connect(
		user = SQL_USER,
		password = SQL_PASSWD,
		host = SQL_HOST,
		database = SQL_DATABASE
	)
	cursor = cnx.cursor()


# SQLと接続を解除する処理
def sql_disconnect():
	cnx.close()


# SQLからデータを取得
def sql_getPastDaysData_amb(maxDaysAgo):

	global cnx, cursor
	ret_time = []
	ret_temp = []
	ret_humid = []
	ret_di = []

	sql_connect()
    
	for daysAgo in range(0, maxDaysAgo+1):
		onedayData_time = []
		onedayData_temp = []
		onedayData_humid = []
		onedayData_di = []
		sql = (
			f'''
			SELECT time, temp, humid
		    	FROM dht11 
				WHERE
				date = DATE_SUB(CURDATE(), INTERVAL {daysAgo} DAY)
			'''
		)
		cursor.execute(sql)
		for row in cursor:
			onedayData_time.append(datetime.datetime.strptime(str(row[0]), '%H:%M:%S'))
			onedayData_temp.append(row[1])
			onedayData_humid.append(row[2])
			di = discomfort_index(row[1], row[2])
			onedayData_di.append(di)
            
		ret_time.append(onedayData_time)
		ret_temp.append(onedayData_temp)
		ret_humid.append(onedayData_humid)
		ret_di.append(onedayData_di)
	
	cnx.commit()
	ret = dict(time=ret_time, 
			   temp=ret_temp, 
               humid=ret_humid,
			   di=ret_di
			   )
	sql_disconnect()
	return ret

グラフ作成

上記で得たデータからグラフを作成します。
作成にはpythonでよく使われるmatplotlibを使います。
また、直近数日分のデータを並べて表示することで、「最近と比べて今はどうなのか?」を比較しやすくします。

以上の方針でグラフ作成処理を行う関数を以下のように作成しました。
これは気温のグラフを作成するもので、湿度、不快指数は別の関数になります。
が、ほとんど同じ処理なので、同じ関数にまとめれると思います。

def makeGraph_temp(data, maxDaysAgo):
	fig = plt.figure(figsize=(6, 4))
	ax1 = fig.add_subplot(1, 1, 1)
	for d in range(maxDaysAgo, -1, -1):
		ln1 = ax1.plot(data['time'][d], data['temp'][d], graph_lines(d), lw=1, color=cm.PuRd((8-d)/10.0), label=f"{d}days ago")
	ax1.plot(data['time'][0][-1], data['temp'][0][-1], 'o', color="#880000", label="now")
	plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
	ax1.set_xlabel("TIME")
	ax1.set_ylabel("TEMPERATURE[℃]")
	plt.show()
	plt.savefig("report/graph_tm.png", format="png", dpi=300)
	plt.clf()
	plt.close()

これでグラフを作ると以下のような感じになります。

気温
湿度
不快指数

このグラフを作った日は不快指数が76前後で、かなり不快感がありました。
皆さんはどうお過ごしでしょうか?熱中症には気を付けて下さい。

ということで、普通なら冒頭で書くような文章を今さら書いたところで締めにしたいと思います。

この記事が気に入ったらサポートをしてみませんか?