IOT体重計の製作(仕上げ編~blynk対応~)

M5STACK

はじめに

前回までで体重計測値のデータベース化も出来るようになり基本的なシステムは完成していますが今回はもう少し実用的で日常的に使い易くなる改良を施してみました。

表示系

前回予告していた通りに画面の表示を少し格好良くするために体重の表示に7セグフォントを使用しました。

また前回のサンプルプログラムの微修正だけでは画面の文字が小さくて数値が読み辛かったため文字サイズを大きくし、起立した状態での視認性を改善しました。

操作系

M5stickのAボタンクリック操作によるクラウドへのデータ送信では、実際の体重測定時は基本的には直立しているので、Aボタンをクリックする事が出来ないため改善を検討しました。

もちろん物理的に長いGrove互換ケーブルを使用すればその心配はありませんが、ここでは長いケーブルは使用せずにソフトウェア的に解決してみました。

M5stickのAボタン押す操作の代替え機能としてBlynk IoTというスマホアプリを採用します。
Blynkは制限はありますが基本無料で使用できるアプリです。

スマホ画面にボタンを配置してIoT端末を操作したり、画面に表示器を配置して端末からのデータを表示することができます。

使い方の一例を説明します。

Webでの作業①

○上記のBlynk IoTのウェブサイトから新規ユーザー登録後ログインします。


○下記の手順でテンプレートを作成します。

・左側アイコンtemplatesクリック.
・右上の+New Deviceをクリック.template が1つも無い場合は画面の真ん中に+New Deviceがあります。

・HARDWARE >ESP32を選択.
・CONNECTION TYPE>WiFiを選択.
・NAME>任意のテンプレート名を入力.
・最後にDoneをクリック.

○続いてBlynkからの出力設定をします。

・Datastreamsタブを選択 .
・画面右上のEditをクリック.

・+New Datastream をクリックすると表示される選択肢からVirtual Pinをクリック.

・次のVirtual Pin Datastream設定画面で、PINはV0、DATA TYPEはInteger、MINは“0” 、MAXは”1“を選択.
・ウィンドウ右下のCreateをクリック.
・画面右上のsaveクリック.

スマホアプリでの作業

○google play やApple  app store からBlynk IoTアプリを入手します。

○IOTスマホアプリのBlynkでダッシュボードを作成します。
・デベロッパーモードを開きます。すると先ほどのWeb画面で作成したテンプレートが追加されていますので選択します。

・「+」をクリックし「Button」を選択します。

・「Button」が」配置されますので、クリックして設定を進めます。

・DATASTREAMでButtonを押したときに起動するピンを設定します。WEB側で作製したV0ピンを選択します。

・最後に左上の「×」を押します。

以上でテンプレートの作成は完了です。

Webでの作業②

○デバイスを作成します。
・右側の虫眼鏡をクリックし画面右上の+New Deviceをクリック.

・次の画面の3つの選択肢からFrom templateを選択.

・TEMPLATE欄のchose templateをクリックすると作成したテンプレートが表示されるのでWebでの作業①で作成したTemplateを選択する.

・Device nameは任意のものを入力後createをクリック.
・Device info タブのFIRMEWARE CONFIGURATIONに記載されているAuth Token の3行をコピーしておく.Auth TokenはM5stickのプログラミングの方に貼り付ける必要がある.

なお、Auth TokenはDevice Info タブから見ることもできます。

以上でスマホアプリに設定したボタンを押すごとにV0端子が押されたことになり、M5stick側のプログラムでV0を押されたときにspread  sheetにデータが送信するようなプログラムを記述しておけばOKです。

Arduinoスケッチ

○冗長なところは多々ありますが、スケッチは次の通りになります。

#include <M5GFX.h>
#include <M5StickC.h>
#include "HX711.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h> //version 6.19.4
#define BLYNK_PRINT Serial
#define BLYNK_TEMPLATE_ID "*******"//blynkのTemplate ID
#define BLYNK_DEVICE_NAME "******"//blynkのDevice name
char auth[] = "****************************";//blynkのAuth Taken
#include <BlynkSimpleEsp32.h>
char *ssid = "********";// Wi-FiのSSID
char *password = "********";// Wi-Fiのパスワード
const char* published_url = "https://script.google.com/macros/s/**********/exec";// GoogleスプレッドシートのデプロイされたURLを設定
M5GFX display;
M5Canvas canvas(&display);
// HX711 接続先PIN.
#define LOADCELL_DOUT_PIN 33
#define LOADCELL_SCK_PIN  32
HX711 scale;
void setup_wifi(){
  Serial.println("Connecting to ");
  Serial.print(ssid);
  WiFi.disconnect();
  delay(500);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
  }
  Serial.println("\nWiFi Connected.");
  canvas.setTextSize(2);
  canvas.setFont(&fonts::Font0); 
  canvas.setCursor(5, 56); 
  canvas.println("WiFi Connected.");
  canvas.println("IP address: ");  
  canvas.println(WiFi.localIP());
  canvas.pushSprite(0, 0);
  delay(2000);
}
void setup() {
    M5.begin();
    display.begin();
    display.setRotation(3);
    canvas.setColorDepth(1);
    canvas.createSprite(display.width(), display.height());
    canvas.setTextDatum(MC_DATUM);
    canvas.setPaletteColor(1, GREEN);
    canvas.setTextSize(2);
    canvas.setFont(&fonts::Font0); 
    canvas.setCursor(5, 40); 
    canvas.print("Calibration sensor.");
    canvas.pushSprite(0, 0);
    scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
    scale.set_scale(27.61f);  // set scale
    scale.tare();             // auto set offset
    setup_wifi();
    canvas.setTextSize(2);
    canvas.println("Blynk connecting..");
    canvas.pushSprite(0, 0);
    delay(1000);
    Blynk.begin(auth, ssid, password);
    canvas.println("Blynk connected.");
    canvas.pushSprite(0, 0);
    delay(2000);
}
BLYNK_WRITE(V0)// Blynk のDATASTREAMで設定した端子名
{
  float weight = scale.get_units(10) / 1000.0;
  int value = param.asInt();
  if (value == 1 ){
    Serial.printf("blunk-read = %d", value);
    canvas.fillSprite(BLACK);
    canvas.setTextSize(2);
    canvas.setFont(&fonts::Font0); 
    canvas.setCursor(10, 20); 
    canvas.print("Sending...");
    canvas.pushSprite(0, 0);
    delay(1000);      
    StaticJsonDocument<500> doc;
    char pubMessage[256];   
      // JSONメッセージの作成
      JsonArray idValues = doc.createNestedArray("ID");
      idValues.add("12345"); //名前など
      JsonArray dataValues = doc.createNestedArray("weight");
      dataValues.add(weight);
      serializeJson(doc, pubMessage);
      // HTTP通信開始
      HTTPClient http;
      Serial.print(" HTTP通信開始 \n");
      http.begin(published_url);
      Serial.print(" HTTP通信POST \n");
      int httpCode = http.POST(pubMessage);
      if(httpCode > 0){
        canvas.setTextSize(2);
        canvas.setFont(&fonts::Font0); 
        canvas.setCursor(13, 95); 
        canvas.print("HTTP Response: "+String(httpCode)); 
        if(httpCode == HTTP_CODE_OK){
          canvas.setTextSize(2);
          canvas.setFont(&fonts::Font0); 
          canvas.setCursor(13, 115); 
          canvas.print("HTTP Success!!");
          String payload = http.getString();
          Serial.println(payload);
        }
      }else{
        canvas.setTextSize(2);
        canvas.setFont(&fonts::Font0); 
        canvas.setCursor(13, 115); 
        canvas.print("FAILED!!");       
        Serial.printf(" HTTP failed,error: %s\n", http.errorToString(httpCode).c_str());
      }
    http.end();
    Blynk.virtualWrite(V1, LOW); 
  }
}
char info[100];
int x;
void loop() {
    Blynk.run();
    canvas.fillSprite(BLACK);
    canvas.setTextSize(2);
    canvas.setFont(&fonts::Font0); 
    canvas.setCursor(13, 20); 
    canvas.print("<-Upload");
    canvas.setCursor(90, 115); 
    canvas.print("Tare");
    float weight = scale.get_units(10) / 1000.0;
    canvas.setTextSize(1);
    canvas.setFont(&fonts::Font7);  //7セグフォント選択
    if (weight >= 0) {
        Serial.printf("%.1f", weight);
        sprintf(info, "%.1f", weight);
        int len = String(info).length();
        Serial.print(" len");
        Serial.println(len);
        if (len == 3){
            x = 75;
          }
          else if (len == 4){
            x = 43;
          }
          else if (len == 5){
            x = 11;
          }
        canvas.setCursor(x, 65);
        canvas.print(String(info));
        canvas.setTextSize(4);
        canvas.setFont(&fonts::Font0);
        canvas.setCursor(170, 75);
        canvas.print("kg");
    } else {
        canvas.setCursor(75, 65);
        canvas.print("0.0");
        canvas.setFont(&fonts::Font0); 
        canvas.setTextSize(4);
        canvas.setCursor(170, 75);
        canvas.print("kg");
    }
    M5.update();
    if (M5.BtnB.wasPressed()) {
      canvas.setFont(&fonts::Font0); 
      canvas.setCursor(50, 115); 
      canvas.setTextSize(2);
      canvas.print("Zero Cal");
      canvas.pushSprite(0, 0);
      scale.tare();
      canvas.setTextSize(2);
      canvas.setCursor(50+108, 115); 
      canvas.print("done");
      delay(1000);
    }
    StaticJsonDocument<500> doc;
    char pubMessage[256];
    if (M5.BtnA.wasPressed()) {
      canvas.fillSprite(BLACK);
      canvas.setTextSize(2);
      canvas.setFont(&fonts::Font0); 
      canvas.setCursor(10, 20); 
      canvas.print("Sending...");
      canvas.pushSprite(0, 0);
      delay(1000);      
      // JSONメッセージの作成
      JsonArray idValues = doc.createNestedArray("ID");
      idValues.add("12345"); //名前など
      JsonArray dataValues = doc.createNestedArray("weight");
      dataValues.add(weight);
      serializeJson(doc, pubMessage);
      // HTTP通信開始
      HTTPClient http;
      Serial.print(" HTTP通信開始 \n");
      http.begin(published_url);
      Serial.print(" HTTP通信POST \n");
      int httpCode = http.POST(pubMessage);
      if(httpCode > 0){
        canvas.setTextSize(2);
        canvas.setFont(&fonts::Font0); 
        canvas.setCursor(13, 95); 
        canvas.print("HTTP Response: "+String(httpCode));
        if(httpCode == HTTP_CODE_OK){
          canvas.setTextSize(2);
          canvas.setFont(&fonts::Font0); 
          canvas.setCursor(13, 115); 
          canvas.print("HTTP Success!!");
          String payload = http.getString();
          Serial.println(payload);
        }
      }else{
        canvas.setTextSize(2);
        canvas.setFont(&fonts::Font0); 
        canvas.setCursor(13, 115); 
        canvas.print("FAILED!!");       
        Serial.printf(" HTTP failed,error: %s\n", http.errorToString(httpCode).c_str());
      }
    http.end();
    }
    canvas.pushSprite(0, 0);
    delay(1000);  
}

おわりに

動画も作成しましたので見ていただければと思います。

Arduinoスケッチはgithubにも投稿していますので参照して下さい。より便利にバージョンアップしてもらえると幸いです。
ただ、体重計が必要なだけであれば、市販のスマホ対応の体重計を購入した方がお安くて楽ですね…。

コメント

タイトルとURLをコピーしました