簡易IoT(稼働監視、遠隔操作)テストプログラム(ATOM LITE使用)の紹介

スマホとATOM LITEでIoTの紹介ATOM LITE
スポンサーリンク

「Lチカ」プログラムを終えたばかりの方にはいきなりですが「IoT」やりましょう♪
とはいっても「IoTってなに?」の方もいると思いますので簡単に説明を

IoTとは
Internet  of Things」の略で、直訳して「モノのインターネット」と呼ばれているものです。
今まで単独で存在していた「モノ」が「インターネット」上に接続され、その状態を確認できたり遠隔で操作したり、互いに情報交換や共有して連動させることもできる技術です。

例えば、電動で動く車のおもちゃの場合、スイッチを入れて床に置くと壁にぶつかるまで走り続けます。
これに「IoT」の技術を組み込むと、スマホで動作/停止を制御できたり、壁にぶつかりそうになったらスマホへ通知して停止したり回避したりすることもできます。
前進だけじゃなく、前後左右に動くものなら、スマホで操作するラジコンにもなりますし、カメラを取り付ければスマホ画面を見ながら床下探検なんてこともできますね。

家の中だと、照明や家電のON/OFFをスマホから一括操作できたり、電力メータを付ければ電力の使用状況を管理して節電に役立てられたりします。

産業用途なら複数の製造ライン上の生産数を一括管理したり、装置の稼働状況を監視して、製造工程の無駄を見つけて作業改善にも役立てられます。
機械の故障や異常(温度、過電流等)が発生した場合は機械を停止させ、その時の状態を担当者へ通知することで、ライン停止を最小限にし再稼働させることができます。


本格的にやるとなるとプログラムもそれなりに複雑で、実際はデータを収集する周辺機器が必要になったりするので、テストプログラムとしてまずはあれですね。

やっぱりやります「スマホでLチカ!」

「IoT」でもやっぱり基本は「Lチカ」ですね。本体のON/OFFボタンでLEDが点灯/消灯しますが、同じようにスマホのON/OFFボタンでも操作できるようにしたものです。LEDの状態はスマホ上で確認可能です。

今回は紹介なので、他にも本体に接続したボリューム(電圧可変)の値を表示したり、本体ボタンを押した回数を表示できるようにしています。
さらに、本体側にも液晶表示器を接続して、スマホの情報と同じかどうかを確認できるようにしました。個別の使い方についてはそれぞれ別記事で紹介しますので、今回は「こんな感じか~」ぐらいで確認してみてください。

ローカル接続でJavaScript「fetch」を使用した実用版WiFi遠隔操作の方法は以下リンクで紹介してます。

WiFi遠隔操作Arduinoコマンドでブラウザベースのスマホ、PCリモートコントローラの紹介
ブラウザベースで遠隔操作、リアルタイムデータ通信を行う方法をコピペ用サンプルプログラムを使って紹介します。 サーバー機能を利用して「JavaScript」の「fetch」を使うことでデータの送受信を行います。

1.「ATOM LITE」で簡易IoT

「ATOM LITE」 にいろいろ接続してスマホから操作する簡易「IoT」です。
いろいろ接続した写真がこちら(スマホは使い道を模索していたiphon4s)

スマホとATOM LITEでIoTの紹介

液晶表示器

電源を入れると「ATOM LITE」がアクセスポイントモードで起動します。液晶画面に「SSID」と「PASSWORD」「IPアドレス」が表示されるので、スマホのWiFi接続先選択から「SSID」の「logikara」を選択し「PASSWORD」の「atomlite」を入力すると「ATOM LITE 」と接続されます。
次にブラウザを立ち上げて、アドレスバーに「IPアドレス」の「192.168.4.1」を入力するとスマホに操作画面が表示されます。

・基本動作
スマホ側の「ONボタン」と本体側の「青ボタン」は連動していて、押すと「青色LED」が点灯
スマホ側の「OFFボタン」と本体側の「赤ボタン」は連動していて、押すと「青色LED」が消灯
スマホ画面の「LED」「電圧」「カウント数」は本体の「ATOM LITE 」側の情報を1秒ごとに更新して表示します。

2.各部の動作詳細

ATOM LITEでIoTの紹介ボタンON

青ボタンを押すと青色LEDが点灯し液晶表示の「LED」が「ON」になります。
青ボタンを押している間は液晶表示の「SW0」が「ON」になりボタンを離すと「OFF」になります。

ATOM LITEでIoTの紹介ボタンON

赤ボタンを押すと青色LEDが消灯し液晶表示の「LED」が「OFF」になります。
赤ボタンを押している間は液晶表示の「SW1」が「ON」になりボタンを離すと「OFF」になります。

ATOM LITEでIoTの紹介LED点灯

「ATOM LITE 」の本体ボタンを押すと赤色LEDが点灯し、押した回数がカウントされます。
押すごとに液晶表示の「CNT」の数字が増えて、スマホ画面の「カウント数も」同じ値を表示します。

ATOM LITEでIoTの紹介LED点灯

ボリュームを回すと本体へのアナログ入力電圧が変化します。
液晶画面の「AN0」の左側はアナログ入力値で右側は電圧(V)に換算した値です。

3.使用したもの(部品リスト)

使用した部品リストは以下になります。

ジャンパーワイヤーやピンヘッダ、抵抗内蔵LED等は「秋月電子通商」さんの方が必要な数量、色だけ購入できて送料(600円)を考えても別で購入するのがお得だと思います。
詳細は下の部品表を参照してください。(価格は変更されている可能性があります。)

品名型式等購入先価格
ピンヘッダ1×40(40P)
[ C-00167 ]
秋月電子通商35円
ジャンパーワイヤーブレッドボード・ジャンパーワイヤ 14種類×10本
[ P-00288 ]
秋月電子通商400円
抵抗内蔵LED抵抗内蔵5mmLED 5V
赤:[ I-06245 ]
青:[ I-06247 ]
秋月電子通商※色により異なる
1パック(10個)120円~200円
1個15円~25円

「M5シリーズ」のユニットを固定するのにはレゴ(テクニック)が「便利です。
各ユニットには2か所の穴が開いているものがほとんどで、この穴にレゴ(テクニック)の「コネクターペグ」等が差し込めます。「リフトアーム」や「プレート」を組み合わせることでいろんな形をつくれます。

ここまでの構成になると「ATOM LITE」より液晶付の「M5Stick-C」の方が価格的には安くできます。
「M5Stick-C」には本体にボタンが2個あるので「ボリュームユニット」を追加するだけで同じ構成ができるのですが、外付け部品を使うことで他にも応用できるようにもなるので今回はこの構成にしてみました。「M5Stick-C」版も今後紹介できればと思ってます。

4.本体と各ユニットの配線

各ユニットとの配線はブレッドボードを使用します。(雑で申し訳ないですが紹介します。)
「ATOM LITE」を外した状態が下の写真です。「ATOM LITE」裏の端子に合わせてピンヘッダをブレッドボードに差し込んでジャンパー線を写真のように配線して、GROVE付き配線を使用して各ユニットと接続します。

ATOM LITEでIoTの紹介

5.プログラム

プログラムも貼っておきますが無駄に長いです。1/3ぐらいは液晶表示のプログラムです。
このプログラムは以下の記事で紹介しているものを組み合わせて作られています。
各プログラムの理解のために確認してみましょう。

WiFi(アクセスポイント、サーバー)で近距離遠隔操作する方法(Arduinoプログラミング)
「ATOM LITE」を例にWiFiアクセスポイントに設定して、スマホ等から近距離遠隔操作を行う方法を紹介します。サーバーのリクエスト(要求)に対してレスポンス(応答)を返すという動作を利用して、簡単なプログラムで遠隔操作が実現できます。
アナログ入力(A/D変換)の使い方(Arduinoプログラミング)
Arduinoコマンドを使用した「アナログ入力」の使い方について紹介します。A/D変換とも呼ばれ「A/D」とは「Analog」と「Digital」の頭文字をとったもので、アナログデータをデジタルデータに変換する処理のことを言います。
液晶表示器OLED(SH1107)の使い方。M5GFXライブラリ使用。
液晶表示器の使い方について紹介します。今回使う液晶は「M5Stack用1.3インチ 128 x 64 OLEDディスプレイユニット SH1107」でI2C通信に対応しており、M5GFX等のライブラリを使うことで簡単に表示ができます。
今回は「簡易IoT」としています。
本体に埋め込んだブラウザページは1秒ごとに再読み込みして画面を更新する簡易なものです。
実際は画面の要素を取得して必要な部分を更新します。これにはプログラム言語「javascript」を使用しますが、プログラムがさらに長くなるので今回は簡単なページとして「簡易IoT」としました。
Webページのような凝ったものも埋め込めますが、この場合はSDカードを搭載した「M5Stack GRAY」等でSDカードからデータを読み込んで表示させた方が楽なので、また詳しく紹介したいと思います。
#include <M5Atom.h>
#include <M5UnitOLED.h> //M5GFXライブラリ使用
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>

// サーバー設定ポート80で接続
WebServer server(80);
// アクセスポイント設定
const char ssid_AP[] = "logikara";    //SSID
const char pass_AP[] = "atomlite";    //パスワード(8文字以上)
// OLED設定(M5GFX)
M5UnitOLED display(26, 32, 400000); // 任意の端子でI2Cを使用する場合(SDA, SCL, FREQ)
M5Canvas canvas(&display);
// FastLED(CRGB構造体)設定
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
  return (CRGB)((r << 16) | (g << 8) | b);
}
// 入出力ピン番号設定
#define INPUT_PIN0 25   //入力ピン(外部ボタン)
#define INPUT_PIN1 21
#define OUTPUT_PIN0 22  //出力ピン(LED)
#define OUTPUT_PIN1 19
#define AN_PIN0 33      //アナログ入力ピン
// グローバル変数設定
float an_val0;  //アナログ入力値格納用
float anv0;     //アナログ入力電圧換算
bool sw_sig0;   //外部青ボタン信号
bool sw_sig1;   //外部赤ボタン信号
bool btn_sig0;  //ブラウザONボタン信号
bool btn_sig1;  //ブラウザOFFボタン信号
char led[] = "OFF"; //LED状態(ON/OFF)格納用配列
int count = 0;  //カウント数格納用
// htmlメイン画面データ
String html = "";
void htmlData() {
  html = "\
  <!DOCTYPE html><html lang=\"jp\"><head>\n\
  <meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\
  <meta http-equiv=\"refresh\" content=\"1; URL=/\">\n\
  <title>REMOTE-CONTROLLER</title>\n\
  <style>\n\
    body{font-family: sans-serif; background-color: #22578b; max-width: 480px; margin: 0 auto; align-items: center;}\n\
    h1 {color:#ffffff; text-align: center; font-size: 28px; margin: 10px auto;}\n\
    div {display: flex; flex-direction: row; justify-content: center;}\n\
    .btn {height: 70px; width: 100px; color: rgb(44, 43, 43); background-color: #dddde9; font-size: 18px; font-weight: bold; border-radius: 7%; margin: 0 10px; -webkit-appearance: none;}\n\
    td {width: 110px; color:#ffffff; text-align: center; font-size: 18px;}\n\
  </style></head><body>\n\
    <h1>REMOTE-CONTROLLER</h1>\n\
    <div>\n\
      <button class=\"btn\" onclick=\"location.href='/get/btn_on'\">ON</button>\n\
      <button class=\"btn\" onclick=\"location.href='/get/btn_off'\">OFF</button>\n\
    </div>\n\
    <div style = \"margin-top: 20px;\">\n\
      <table border = \"1\">\n\
        <tr><td>LED</td><td>" + (String)led + "</td></tr>\n\
        <tr><td>電圧</td><td>" + (String)anv0 + "</td></tr>\n\
        <tr><td>カウント数</td><td>" + (String)count + "</td></tr>\n\
      </table>\n\
    </div>\n\
  </body></html>\n";
}
//-------------------------------------------------
// 関数
//-------------------------------------------------
/********* クライアントにWebページ(HTML)を返す *********/
void handleRoot() {
  htmlData(); //htmlデータ更新
  // レスポンス200を返し、htmlデータ送信
  server.send(200, "text/html", html);
}
/********** クライアントにエラーメッセージを返す **********/
void handleNotFound() { //ファイルが見つかりません
  server.send(404, "text/plain", "File not found!");
}
/************** ブラウザボタンON受信 **************/
// ブラウザONボタン処理
void btnOn() {
  btn_sig0 = 1; //ブラウザONボタン信号を1
  htmlData();   //htmlデータ更新
  // レスポンス200を返し、htmlデータ送信
  server.send(200, "text/html", html);
  Serial.println("BTN_ON!");
}
// ブラウザOFFボタン処理
void btnOff() {
  btn_sig1 = 1; //ブラウザOFFボタン信号を1
  htmlData();   //htmlデータ更新
  // レスポンス200を返し、htmlデータ送信
  server.send(200, "text/html", html);
  Serial.println("BTN_OFF!");
}
/******************* OLED表示 *******************/
// ページ0:タイトル表示
void oledPage0() {
  canvas.clearDisplay();                //表示クリア
  canvas.setFont(&fonts::Font4);        //フォント
  canvas.setCursor(0, 0);               //座標を指定
  canvas.printf("Starting\nAP Mode!!"); //メッセージ
  canvas.pushSprite(5, 5);              //描画
}
// ページ1:SSID、パスワード、IPアドレス表示
void oledPage1() {
  canvas.clearDisplay();                //表示クリア
  canvas.setFont(&fonts::Font2);        //フォント
  canvas.setCursor(0, 0);               //座標を指定
  canvas.print("SSID: ");
  canvas.println(ssid_AP);
  canvas.print("PASS: ");
  canvas.println(pass_AP);
  canvas.print("IP = ");
  canvas.println(WiFi.softAPIP());
  canvas.pushSprite(5, 5);              //描画
}
/******************* wifi接続 *******************/
//アクセスポイント設定
void softAPWifiConnect() {
  WiFi.softAP(ssid_AP, pass_AP);  //ソフトAP設定
  // WiFi.softAPConfig(ip, ip, subnet);    //IPアドレス指定
  oledPage0();  //タイトル表示
  delay(2000);  //タイトル表示時間
  oledPage1();  //SSID、パスワード、IPアドレス表示
  // シリアル出力
  Serial.println("Starting Access Point!!");
  Serial.printf("SSID:%s\n", ssid_AP);
  Serial.printf("PASS:%s\n", pass_AP);
  Serial.print("IP address: ");
  Serial.println(WiFi.softAPIP());
  Serial.println("WiFi connected!!");
  delay(4000);  //SSID、パスワード、IPアドレス表示時間
}
/********************* Webサーバー設定 ********************/
void serverSet() {
  server.on("/", handleRoot);         //ルートアクセス時の応答関数を設定
  server.onNotFound(handleNotFound);  //不正アクセス時の応答関数を設定
  server.on("/get/btn_on", btnOn);    //ボタンオン受信処理
  server.on("/get/btn_off", btnOff);  //ボタンオフ受信処理
  server.begin();                     //Webサーバー開始
}
//-------------------------------------------------
// 初期設定
//-------------------------------------------------
void setup() {
  M5.begin(true, false, true);  //Serial,POWER,LED
  Serial.begin(9600);           //標準のシリアル通信設定
  while (!Serial) {};           //シリアル接続待ち
  Serial.println("\nM5Atom Lite setup");
  // 本体LED設定
  M5.dis.drawpix(0, dispColor(20, 20, 20)); //LED点灯(白)
  // OLED(M5GFX)設定
  display.init();
  display.setRotation(1);       //表示方向(コネクタ位置):0下、1右、2上、3左
  canvas.setColorDepth(1);      //モノクロ
  canvas.setTextWrap(false);    //自動改行をしない
  canvas.setFont(&fonts::Font2);//フォント(Font0,2,4/ 6,7,8(数字のみ))
  canvas.setTextSize(1);        //文字サイズ
  canvas.createSprite(display.width(), display.height());
  // 通信設定
  softAPWifiConnect();          //アクセスポイント
  serverSet();                  //サーバー
  // 入出力端子設定
  pinMode(INPUT_PIN0, INPUT_PULLUP);  //入力端子
  pinMode(INPUT_PIN1, INPUT_PULLUP);
  pinMode(OUTPUT_PIN0, OUTPUT);       //出力端子
  pinMode(OUTPUT_PIN1, OUTPUT);
  digitalWrite(OUTPUT_PIN0, LOW);     //出力初期化(OFF)
  digitalWrite(OUTPUT_PIN1, LOW);
  pinMode(AN_PIN0, ANALOG);           //アナログ入力端子
}
//-------------------------------------------------
// メイン
//-------------------------------------------------
void loop() {
  server.handleClient();              //クライアントからのアクセス処理
  M5.update();                        //ボタン状態更新
  // アナログ入力処理
  an_val0 = analogRead(AN_PIN0);      //アナログ入力取得
  anv0 = (3.3 / 4096) * an_val0;      //電圧換算
  // ボタン状態格納
  sw_sig0 = digitalRead(INPUT_PIN0);  //青(ON)ボタン状態格納
  sw_sig1 = digitalRead(INPUT_PIN1);  //赤(OFF)ボタン状態格納
  //青ボタンまたはブラウザONボタンが押されたら
  if ((sw_sig0 == 0) || (btn_sig0 == 1)) {
    digitalWrite(OUTPUT_PIN0, HIGH);  //出力0 ON(青色LED)
    M5.dis.drawpix(0, dispColor(0, 0, 200)); //本体LED(青)
    strcpy(led, "ON");                //出力0(青色LED)状態ブラウザ表示
    btn_sig0 = 0;                     //ブラウザボタン信号初期化
  }
  //赤ボタンまたはブラウザOFFボタンが押されたら
  if ((sw_sig1 == 0) || (btn_sig1 == 1)) {
    digitalWrite(OUTPUT_PIN0, LOW);   //出力0 OFF(青色LED)
    M5.dis.drawpix(0, dispColor(20, 20, 20)); //本体LED(白)
    strcpy(led, "OFF");               //出力0(青色LED)状態ブラウザ表示
    btn_sig1 = 0;                     //ブラウザボタン信号初期化
  }
  // 本体スイッチ処理
  if (M5.Btn.wasPressed()) {          //本体ボタンが押されていれば
    count++;                          //カウント+1
    digitalWrite(OUTPUT_PIN1, HIGH);  //出力1 ON(赤色LED)
    M5.dis.drawpix(0, dispColor(200, 0, 0)); //本体LED(赤)
  }
  if (M5.Btn.wasReleased()) {         //本体ボタンが離されていれば
    digitalWrite(OUTPUT_PIN1, LOW);   //出力1 OFF(赤色LED)
    if ((String)led == "ON") {        //本体LEDの状態で分岐
      M5.dis.drawpix(0, dispColor(0, 0, 200)); //本体LED(青)
    } else {
      M5.dis.drawpix(0, dispColor(20, 20, 20)); //本体LED(白)
    }
  }
  // OLED表示
  canvas.clearDisplay();          //表示クリア
  canvas.setFont(&fonts::Font2);  //フォント
  canvas.setCursor(0, 5);         //座標を指定(1行目)
  canvas.print("SW0: ");          //SW0(青)状態表示
  if (sw_sig0 == 0) {
    canvas.print("ON  ");
  } else {
    canvas.print("OFF");
  }
  canvas.setCursor(70, 5);        //座標を指定(1行目)
  canvas.print("SW1: ");          //SW1(赤)状態
  if (sw_sig1 == 0) {
    canvas.print("ON  ");
  } else {
    canvas.print("OFF");
  }
  canvas.setCursor(0, 24);        //座標を指定(2行目)
  canvas.printf("LED: %s", led);  //LED状態
  canvas.setCursor(70, 24);       //座標を指定(2行目)
  canvas.printf("CNT: %d", count);//カウント数
  canvas.setCursor(0, 43);        //座標を指定(3行目)
  canvas.print("AN0: ");          //アナログ値
  canvas.printf("%.0f", an_val0);
  canvas.setCursor(90, 43);       //座標を指定(3行目)
  canvas.printf("%.2fV", anv0);   //アナログ値電圧換算
  canvas.pushSprite(0, 0);        //描画したcanvasを座標を指定して表示
  delay(100);
}

長い~「コピペ」の限界を感じる・・・


他にも以下のリンクでいろいろなマイコンボードを使用したプログラムを開発環境の準備と合わせて紹介してますので確認してみましょう。

プログラミングの記事一覧ページは → こちら

コメント

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