前回摂取カロリー記録のための3ボタンUIを作ったので、今回はここに通信の仕組みを乗せていく。
thom.hateblo.jp
M5 Stackのコード
※ssidとパスワードは他人に見せられないので英字をすべてx、数字をすべて9に置き換えている。
#include <M5Stack.h> #include <WiFi.h> int p; int digit[4]; const char* ssid = "xx999x-999x99-9"; const char* password = "99x999xx9999x"; const int port = 49152; const IPAddress server_ip(192, 168, 1, 101); WiFiClient client; void setup() { // init lcd, serial, but don't init sd card M5.begin(true, false, true); /* Power chip connected to gpio21, gpio22, I2C device Set battery charging voltage and current If used battery, please call this function in your project */ M5.Power.begin(); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } resetNumber(); } // Add the main program code into the continuous loop() function void loop() { // update button state M5.update(); // if you want to use Releasefor("was released for"), use .wasReleasefor(int time) below if (M5.BtnA.wasReleased() || M5.BtnA.pressedFor(1000, 200)) { if(digit[p]++ >= 9){digit[p]=0;} displayNumber(); } else if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000, 200)) { if(++p >= 4){p=0;} displayNumber(); } else if (M5.BtnC.wasReleased() || M5.BtnC.pressedFor(1000, 200)) { /*M5.Lcd.setTextSize(2); M5.Lcd.println("Connecting..."); delay(1000);*/ int x = 0; x = digit[0]*1000 + digit[1]*100 + digit[2]*10 + digit[3]; //M5.Lcd.println("Sending " + String(x) + " kcal."); //delay(1000); if (sendData(x)){ M5.Lcd.println("Done!"); M5.Speaker.tone(659, 200); delay(200); } else { M5.Lcd.println("Failed!"); M5.Speaker.tone(440, 100); delay(100); M5.Speaker.mute(); delay(100); M5.Speaker.tone(440, 100); delay(100); M5.Speaker.mute(); delay(100); M5.Speaker.tone(440, 100); delay(100); } M5.Speaker.mute(); delay(1000); resetNumber(); } else if (M5.BtnB.wasReleasefor(700)) { resetNumber(); } } bool sendData(int n) { M5.Lcd.setTextSize(2); M5.Lcd.println("Connecting..."); M5.Lcd.println("Sending " + String(n) + " kcal."); if (!client.connect(server_ip, port)) { return false; } client.print(n); //client.stop(); //WiFi.disconnect(); return true; } void resetNumber() { p = 1; for (int i=0; i<4; i++){ digit[i] = {0}; } displayNumber(); } void displayNumber() { M5.Lcd.clear(BLACK); M5.Lcd.setCursor(0, 0); M5.Lcd.setTextSize(10); for(int i=0; i<4; i++) { if(i==p){M5.Lcd.setTextColor(YELLOW);} else {M5.Lcd.setTextColor(WHITE);} M5.Lcd.print(digit[i]); } M5.Lcd.setTextColor(WHITE); M5.Lcd.setTextSize(5); M5.Lcd.setCursor(180, 18); M5.Lcd.println("kcal"); }
M5 Stack側コードの説明
UIの挙動については前回の記事を参照して欲しい。
前回からの更新は、起動時にWifiに接続されることと、右ボタンでサーバーに接続してデータを送っている点である。
データ送信の度にサーバーに繋ぎに行くくせに切断するコードが無いことを不思議に思う方もいるかもしれない。
これはクライアント側から通信を切断すると上手く行かなかった為、試行錯誤した結果データを受信する度にサーバー側でコネクションをクローズさせるようにした為。
ネットワークの作法に疎いのでこれで良いのかあんまり分かってないんだけど、個人利用のプログラムだから安定稼働すればとりあえず良しとする。
あと送信失敗したときの音は以下のサイトのコードをそのままいただいた。
msr-r.net
ラズパイ側のコード
import socket import time with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(("", 49152)) while True: s.listen(1) conn, addr = s.accept() try: data = conn.recv(16) print(data) time.sleep(1) except socket.error: pass except KeyboardInterrupt: conn.close() s.close() conn.close()
ラズパイ側のコード解説
こちらは単純に受信データをPrintするだけのコード。
conn.recv(16)でデータを待ちつつデータが来たらプリントし、コネクションを切断するという流れ。
KeyboardInterruptを拾う位置がおかしい気がするので、いつかもう少し知識が付いたら書き直したい。
動作イメージはこんなかんじ。
見てもつまらないとは思うけど、ここまでが一番の難所だった。
あとはファイルに記録してGUIで表示させれば、摂取カロリー記録システムの完成である。
ファイル記録は経験あるので問題ないけど、GUIは少々苦労しそうな気がする。
以上。