NodeMCUマイコンを用いたIOT基礎実験

(1)NodeMCU とは

 オープンソースのハードウェアです。オープンソースハードウェア ( OSHW ) とは、設計図やファームウェア等のソースコードが公開されており、誰でも自由に改変したり、拡張したりできるハードウェアのことです。NodeMCU は CPUとして ESP32、または ESP8266 を用いたものがあります。
 ESP32 : デュアルコアであり、マルチタスクを行うことができます。Wi-Fi と Bluetooth が搭載されています。

 ESP8266 : シングルチップであり、Wi-Fi のみ搭載しており、Bluetooth はありません。  中国の上海の Espressif Systems により製造されています。

 本実験では、ESP8266 を搭載した OSOYOO 製 NodeMCU を使用します。特徴は PC との通信・プログラム転送用に Type C コネクタが付いていること、日本の技適取得済みであり、価格がamazon で3個で税込み 2,241 円と安いことです。( 技適(ぎてき)とは、技術基準適合証明または技術基準適合認定の略で、通信機器が日本の電波法や電気通信事業法の基準に適合していることを証明する認証です。携帯電話やスマートフォン、Wi-Fi端末、Bluetooth機器などが対象です。)

GPIOピンとして自由に使用できるのは、
D1ピン = GPIO5  /  D2ピン = GPIO4  /  D5ピン = GPIO14
D6ピン = GPIO12  /  D7ピン = GPIO13

(2)NodeMCU 実験用の回路図です

A.  NodeMCU、OLED、スイッチ、可変抵抗の回路図です

B.  NodeMCU、LED2個、温度センサDHT22、超音波センサHC-SR04の回路図です

C.  NodeMCU、スイッチ、LED、可変抵抗、赤外線レシーバの回路図です

D.  NodeMCU、2個のLEDと2個のスイッチの回路図です

E.  NodeMCU、1個のLEDと1CHリレーモジュールと
 1個のスイッチの回路図です
           リレーモジュールは SRD-5VDC-SL-C です

F.  NodeMCU、赤外線LEDと赤外線レシーバの回路図です
 赤外線レシーバは VS1838B です
 赤外線LED は外径5mm(直径5mmですよ)、ピーク波長940nm、
順方向電圧VF 1.25V~1.8V、動作電流 20mA、カラーは透明です
型番は OSI5LA5113A だと思っています( ? )

〇補足説明1 ブレッドボードの使い方

〇補足説明2トランジスタ・LEDの使い方

(3)実験項目(作成するプログラム)について

N1.“ Hello World “ を出力しよう。

N2. LED を点灯しよう(上の回路図 B 参照)。

N3.リレーモジュールを操作しよう(上の回路図 E 参照)。

N4.スイッチの ON と OFF を読み取ろう(上の回路図 C 参照)。

N5.応用問題

① スイッチの ON で LED を点灯し、OFF で消灯する
 (上の回路図 C 参照)。
② スイッチの ON でリレーモジュールを ON にし、スイッチの
  OFF でリレーモジュールを OFF にする(上の回路図 E 参照)。

N6.可変抵抗の電圧を測定をしよう(上の回路図 C 参照)。

N7.OLED モジュールに文字表示しよう(上の回路図 A 参照)。
 ( OLED とは Organic Light Emitting Diode  の略で、発光材料に
有機物質( Organic ) を使った LED(発光ダイオード)のことです )

N8.応用問題  (上の回路図 A 参照)
 ① スイッチの ON と OFF を OLED モジュールに表示する。
 ただし、スイッチは1つ使用し、D5ピン ( GPIO14 ) につなげる
 こと。
 ② 可変抵抗の電圧を OLED モジュールに表示する。

N9.温度センサ DHT22 のデータを NodeMCU で読み込もう。
 DHT22 ( AM2302 ) はデータ交換と制御が1本のデータ線で行うシングルワイヤ通信を採用しています。シングルワイヤ通信は、1-WIre と書きます。そのため、電源VCC、GND、データ線の3本で温度・湿度データを出力できます。(上の回路図 B 参照) 

N10.超音波センサ HC-SR04 の出力を NodeMCU で読み込もう。
   (上の回路図 B 参照)

N11.ダイソーのリモコンライトの赤外線リモコン の出力値を NodeMCU で読み込もう。
 使用するのはダイソーで税込み330円で売っている リモコンライト [イルミネーション] です。同じ価格で似た品物があるので間違えないで下さいね。

 赤外線リモコンとライトのセットです。ライトはリモコンで点灯します。この赤外線リモコンの信号の値を読み取ります。

 リモコンの各スイッチに上図のように番号を付けましたの、このスイッチ番号に対して、信号値を読み取って下さい。
 赤外線レシーバは VS1838B を使用します。
   (上の回路図 C 参照)

N12.上記の N11で読み込んだ出力値を用いて、回路の
 赤外線 LEDから赤外線リモコンのスイッチ番号と同じ信号値を発光し、ランプを点灯させよう。
   (上の回路図 F 参照)

〇 N1 から N12 までのサンプルプログラム

 プログラムの編集、ビルド、ダウンロードはすべて、Arduino IDE 1.8.19 を使用しています。NodeMCU のボードマネージャや必要なライブラリのインストールは必ず行ってください。ボードマネージャーのインストールについては、
https://osoyoo.com/ja/2023/02/23/getting-started-with-nodemcu-using-arduinoide/
 MQTT ブローカーと通信するためのMQTTライブラリ PubSubClient のインストールについては、
https://osoyoo.com/ja/2017/05/10/nodemcu-lesson-6-mqtt-basic-example/
を参考にしてください。

N1_HelloWorld HelloWorld を表示

// N1_HelloWorld.ino

//***************************************//
//*   NodeMCU                          *//
//*   1秒ごとに "hello World" を表示します *//
//***************************************//
void setup() {      // 初期設定を書く関数:1番最初に1回だけ実行されます
  Serial.begin(9600);   // 通信速度設定 9600bps
  while (!Serial) {
   ; //wait for serial port to connect. Needed for native USB port only
  }
}

void loop() { // 繰り返し行う動作を書く: setup() の後に実行されます
  Serial.println("Hello World"); //( )内に送信する文字列
                  // Serial.println は表示後、改行されます
  delay(1000);    // wait時間 0.001秒 = 1ms 単位です
}



// 練習問題1. 自分の氏名をCOMポートに出力し、シリアルモニタに表示しなさい。

// 練習問題2. 練習問題1で表示した自分の名前と一緒に、表示回数も表示しなさい。
//  String( カウント変数 ) を使い、
// Serial.println( “ 自分の名前 “ + String( カウント変数 ) ) で表示できます。

N2_LED LEDの利用

// N2_LED . ino

//***********************************************************//
//*       NodeMCU  : 赤色LEDと青色LEDを点灯する    *//
//*                   1秒毎に点灯、消灯します              *//
//***********************************************************//
int red_led = 4;
int blue_led = 5;

void setup( ) {   // 初期設定を書く関数:1番最初に1回だけ実行されます
  // GPIO4 ( D2pin ), GPIO5 ( D1pin )はトランジスタのベースにつながる
  pinMode( red_led, OUTPUT ); // GPIO4 ( D2pin ) を出力ピンにする設定
  pinMode( blue_led, OUTPUT ); // GPIO5 ( D1pin ) を出力ピンにする設定
}

void loop( ) { // 繰り返し行う動作を書く: setup( ) の後に実行されます
  ///////////////  1秒毎にLEDを点灯、消灯する  ////////////
  /* トランジスタのベースに電流が流れるので
コレクタからエミッタに電流が流れる */
  // LEDが点灯する
  digitalWrite( red_led, HIGH ); // GPIO4 ( D2pin ) にHIGH(3.3V)出力する 
  digitalWrite( blue_led, HIGH ); // GPIO5 ( D1pin ) にHIGH(3.3V)出力する
  delay( 1000 );    // wait時間 0.001秒 = 1ms 単位です
  
  /*  トランジスタのベースに電流が流れないので
コレクタからエミッタに電流が流れない */
  // LEDが消灯する 
  digitalWrite( red_led, LOW ); // GPIO4 ( D2pin ) にLOW(0V)出力する  
  digitalWrite( blue_led, LOW );// GPIO5 ( D1pin ) にLOW(0V)出力する 
  delay(1000);    // wait時間 0.001秒 = 1ms 単位です
}


// 練習問題1.この実験項目は赤色LEDと青色LEDを同時に
// 点灯、消灯しますが、一方が点灯しているときには、片方が消灯
// するように変更しなさい。

N3_Rellay リレーモジュールをON、OFFさせる

// N3_Rellay.ino

//**************************************************//
//*   NodeMCU                                       *//
//* 2CHのリレーモジュールをON、OFFさせます    *//
//*************************************************//
int rellay_1 = 14;
int rellay_2 = 12;

void setup() {      // 初期設定を書く関数:1番最初に1回だけ実行されます
  // GPIO14(D5pin), GPIO12(D6pin)はトランジスタのベースにつながっている
  pinMode(rellay_1, OUTPUT);  // GPIO14 (D5pin) を出力ピンにする設定
  pinMode(rellay_2, OUTPUT); // GPIO12 (D6pin) を出力ピンにする設定
  Serial.begin(9600);   // 通信速度設定 9600bps
  while (!Serial) {
  ;//wait for serial port to connect. Needed for native USB port only
  }
}

void loop() { // 繰り返し行う動作を書く: setup() の後に実行されます
  
  // トランジスタのベースに電流が流れるので
  // コレクタからエミッタに電流が流れる
  // Rellay が ON となる
  Serial.println("Rellay ON");
  digitalWrite(rellay_1, HIGH);// GPIO14 (D5pin) にHIGH(3.3V)出力する 
  digitalWrite(rellay_2, HIGH);// GPIO12 (D6pin) にHIGH(3.3V)出力する
  delay(2000);    // wait時間 0.001秒 = 1ms 単位です
  
  //トランジスタのベースに電流が流れないので
  //コレクタからエミッタに電流が流れない
  // Rellay が OFF となる
  Serial.println("Rellay OFF");
  digitalWrite(rellay_1, LOW); // GPIO14 (D5pin) にLOW(0V)出力する  
  digitalWrite(rellay_2, LOW);// GPIO12 (D6pin) にLOW(0V)出力する 
  delay(2000);    // wait時間 0.001秒 = 1ms 単位です
}



// 練習問題1.リレーがONされた回数を「Rellay_ON」の表示の後に付け加えなさい。
// ヒント: int型変数i 等は、 関数 String( i ) で
// 文字列に変えることができます。

N4_SW スイッチの利用

// N4_SW.ino

//**********************************************//
//*     NodeMCU                                *//
//*  スイッチのONとOFFを読み取ります           *//
//*********************************************//
//ピンの定義
#define SWITCH_PIN 4 //スイッチの電圧を入力するD2 pin - GPIO4

void setup() { // 初期設定を書く関数:1番最初に1回だけ実行されます
  Serial.begin(9600);
  while (!Serial) {
   ;// wait for serial port to connect. 
      // Needed for native USB port only
  } 
  pinMode( SWITCH_PIN, INPUT );//GPIO4(D2pin)を入力ピンにする設定
}

int on_flag=1; /* このフラグは、スイッチONで1,スイッチOFFで0
このフラグは「スイッチ オン」「スイッチ オフ」の表示を何回も
を繰り返えさないためです */

void loop() { // 繰り返し行う動作を書く: setup() の後に実行されます
  if( digitalRead( SWITCH_PIN ) == HIGH ){// スイッチの状態を読む 
   // スイッチが押されていなければ HIGH です。オフです。
    if(on_flag==1){
      on_flag = 0;
      Serial.println( "スイッチ オフ" );//シリアルモニタに表示
    }
  }
  else {    // スイッチが押されれば LOW です。オンです。
    if(on_flag==0){
      on_flag = 1;
      Serial.println( "    スイッチ オン" );//シリアルモニタに表示
    }
  }
  delay(100); // wait時間 0.001秒 = 1ms 単位です
}


// 練習問題1.スイッチが押された回数を「スイッチ オン」の表示の後に
// 付け加えなさい。
// ヒント: int型変数i 等は、 関数 String( i ) で
//          文字列に変えることができます。

N6_VR_AD 可変抵抗の電圧を測定する

// N6_VR_AD.ino

//***********************************************************//
//*     NodeMCU                                     *//
//*  A0ピンに入力された 0-3.3V の電圧をAD変換する  *// 
//*********************************************//
int val; // AD変換後の値を代入するint型変数:0~1023の値
float vol; // AD変換されたint型変数を0-3.3V にする

void setup() { // 初期設定を書く関数:1番最初に1回だけ実行されます
  Serial.begin(9600);
  while (!Serial) {
   ; // wait for serial port to connect. 
      // Needed for native USB port only
  }
  Serial.println();
}

void loop() { // 繰り返し行う動作を書く: setup() の後に実行されます
  val = analogRead(A0); // A0 ピンから可変抵抗の電圧値を読み、
                        // AD 変換結果を val に入力する
  vol = val * 3.3 / 1024;                     
  Serial.println("変換値 " + String(val)
                  + "  :電圧 " + String(vol) + " V"); 
  delay(500);  // wait時間 0.001秒 = 1ms 単位です
}


// 練習問題1.AD変換されたvalの値によりLEDを以下のように動作させなさい。
// ・5未満(約0V)なら両方とも消灯させる。
// ・5以上512未満(1.65V未満)なら、青色LEDを点灯させる。
// ・512以上(1.65V以上)1000未満なら、赤色LEDを点灯させる。
// ・1000以上(約3.3V)で両方とも点灯させる。

N7_OLED OLEDモジュールに文字表示する
(OLEDとはOrganic Light Emitting Diode の略で、発光材料に
有機物質(organic)を使ったLED(発行ダイオード)のことです)

// N7_OLED.ino

//***********************************************************//
//*     NodeMCU                                     *//
//*  OLED モジュール使います。端子の接続は以下です。*// 
//*  OLEDコントローラーは SSD1306 です            *//
//*  I2C でNodeMCUと接続します                   *//
//*     VDD -- 3.3V                                 *//
//*     GND -- GND                                  *//
//*     SCK -- D1                                   *//
//*     SDA -- D2                                   *//
//*  D1,D2 を I2C ピンとして使います              *//
//*******************************************************//
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 //OLED display width, in pixels
#define SCREEN_HEIGHT 64 //OLED display height, in pixels

// Declaration for SSD1306 display connected using I2C
#define OLED_RESET -1 // Reset pin このOLEDは
                    // Resetピンがないので使用しないことを示す
#define SCREEN_ADDRESS 0x3C // OLED の I2Cアドレス
// 次は Adafruit_SSD1306クラスのオブジェクトを作るための
// コンストラクタです
Adafruit_SSD1306 display(SCREEN_WIDTH, 
SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()
{
  Serial.begin(9600);
  // initialize the OLED object : display.begin
  // SSID1306_SWITCHCAPVCC で OLED内部の電圧を上げる
//チャージポンプを ON にする
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Clear the buffer. OLED の画面用メモリクリア
  display.clearDisplay();

  // Display Text "Hello world!"を表示します
  display.setTextSize(1);      //フォントサイズ設定
  display.setTextColor(WHITE); //黒い背景のときWHITE 
//明るい背景のときBLACK と書く
  display.setCursor(0,28); //カーソル位置の設定
// (X,Y) X=horizontal, Y=vertical
                    //(0,0)は左上端です。(63,127)が右下端です。
  display.println("Hello world!"); //画面にメッセージを出力します
      // print(" ")は改行無し、println(" ")は改行します。
  display.display();//メッセージを画面に表示します
  delay(2000);
  display.clearDisplay();  //OLED の画面用メモリクリア

  // Display Inverted Text "Hello world!" の色を反転表示します
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  // BLACK = FontColor文字色, WHITE = BackgroundColor背景色
  display.setCursor(0,28);
  display.println("Hello world!");// Hello world を表示します
  display.display();
  delay(2000);
  display.clearDisplay();

  // Changing Font Size 文字サイズを変えます
  display.setTextColor(WHITE);
  display.setCursor(0,24);
  display.setTextSize(2); //フォントサイズを2にする(大きくなる)
  display.println("Hello!"); // Hello を表示します
  display.display();
  delay(2000);
  display.clearDisplay();

  // Display Numbers 数字を表示します - 整数を表示できます
  display.setTextSize(1);
  display.setCursor(0,28);
  display.println(123456789);// 123456789 を表示します
  display.display();
  delay(2000);
  display.clearDisplay();

  // Display ASCII Characters 絵文字を書くことができます
  display.setCursor(0,24);
  display.setTextSize(2);
  display.write(3); // write(3)と書くとハートマークが描かれます
  display.display();
  delay(2000);
  display.clearDisplay();

  // Scroll full screen 画面をスクロールします
  display.setCursor(0,0); //左上端にカーソルをセット
  display.setTextSize(1);
  display.println("Full");  // 1行目に表示する"Full"
  display.println("screen");// 2行目に表示する"screen"
  display.println("scrolling!");// 3行目に表示する"scrolling!"
  display.display();
  display.startscrollright(0x00, 0x07);//右に水平にスクロールする
  delay(2000);
  display.stopscroll();// スクロール停止
  delay(1000);
  display.startscrollleft(0x00, 0x07);//左に水平にスクロールする
  delay(2000);
  display.stopscroll();
  delay(1000);    
  display.clearDisplay();

  // Scroll part of the screen 特定の行だけスクロール
  display.setCursor(0,0); //左上端にカーソルセット
  display.setTextSize(1);
  display.println("0000");// 1行目文字列 0ページ目
  display.println("1111"); // 2行目文字列 1ページ目
  display.println("2222"); // 3行目文字列 2ページ目
  display.println("3333");// 4行目文字列 3ページ目
  display.println("4444"); // 5行目文字列 4ページ目
  display.println("5555"); // 6行目文字列 5ページ目
  display.println("6666");// 7行目文字列 6ページ目
  display.println("7777"); // 8行目文字列 7ページ目
  display.display();
}

void loop() {
  display.startscrollright(0x00, 0x00);// ページ0だけ右にスクロール
  delay(3000);
  display.startscrollleft(0x01, 0x01);// ページ1だけにス左にスクロール
  delay(3000);  
  display.startscrollright(0x02, 0x02);// ページ2だけ右にスクロール
  delay(3000);
  display.startscrollleft(0x03, 0x03);// ページ3だけ左にスクロール
  delay(3000);
  display.startscrollright(0x04, 0x04);// ページ4だけ右にスクロール
  delay(3000);  
  display.startscrollleft(0x05, 0x05);// ページ5だけ左にスクロール
  delay(3000);
  display.startscrollright(0x06, 0x06);// ページ6だけ右にスクロール
  delay(3000);
  display.startscrollleft(0x07, 0x07);// ページ7だけにス左にスクロール
  delay(3000);  
}

// 練習問題1.自分の名前をローマ字で表示しなさい。

// 練習問題2. 文字 ON と OFF を2秒ごとに、
// ON → OFF → ON → OFFと交互に表示しなさい。

// 練習問題3.整数型のカウント変数 countを用いて、
// count=0 から 1秒ごとに count++ でカウントアップ
// しいていき、このカウント値を表示しなさい。

N9_DHT22 温度センサ DHT22を用い温度と湿度を測定します

// N9_DHT22.ino

//**************************************//
//*     NodeMCU                        *//
//*   温度センサ DHT22 使用プログラム    *//
//*     温度と湿度を表示します           *//
//*   ピンの接続                        *//
//*     VCC = 3.3V                     *//
//*     S   = GPIO13 ( D7pin )         *//
//*     GND = GND                      *//
//**************************************//
#include "DHT.h"
#define DHTPIN 13     // NodeMCU D7pin = GPIO13

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11 
#define DHTTYPE DHT22   // DHT 22  (AM2302)

// Initialize DHT sensor.
// Note that older versions of this library 
// took an optional third parameter to
// tweak the timings for faster processors.  
// This parameter is no longer needed
// as the current DHT reading algorithm 
// adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600); 
  while (!Serial) {
  ; // wait for serial port to connect. 
    // Needed for native USB port only
  }
  Serial.println("DHTxx test!");
  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(2000);
  // Reading temperature or humidity takes
  //  about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // humidity 湿度
  float h = dht.readHumidity();
  // Read temperature as Celsius  セルシウス温度 (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit  華氏温度 (isFahrenheit = true)
  float f = dht.readTemperature(true);
  
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Serial.print("Humidity: "); 
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: "); 
  Serial.print(t);
  Serial.println(" *C ");
}

// 練習問題1. 温度の整数部分をOLED で表示しなさい。
// ただし表示する温度範囲は20度以上40度以下とし、
// 20度未満は LO 、40度を超えたら HI と表示しなさい。

N10_HCSR04 超音波センサ HCSR04 を使います

// N10_HCSR04.ino

//*************************************************//
//*     NodeMCU                            *//
//* 超音波センサ HC-SR04 使用プログラム    *//
//*   ピンの接続                              *//
//*     VCC = VIN 5V                        *//
//*     Trig = GPIO12 ( D6pin )              *//
//*     Echo = GPIO14 ( D5pin )             *//
//*     GND = GND                         *//
//************************************************//
const int trigPin = 12;
const int echoPin = 14;

//define sound velocity in cm/uS
#define SOUND_VELOCITY 0.034

long duration;
float distanceCm;

void setup() {
  Serial.begin(115200); // Starts the serial communication
  while (!Serial) {
  ; // wait for serial port to connect. Needed for native USB port only
  }
    
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
}

void loop() {
  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // Reads the echoPin, returns the sound wave travel time 
// in microseconds
  duration = pulseIn(echoPin, HIGH);
  
  // Calculate the distance
  distanceCm = duration * SOUND_VELOCITY/2;

  // Prints the distance on the Serial Monitor
  Serial.print("Distance (cm): ");
  Serial.println(distanceCm); 
  delay(1000);
}


// 練習問題1. 距離の整数部分をOLED で表示しなさい。

N11_IRremote
赤外線リモコン の出力値を NodeMCU で読み込もう。赤外線レシーバは VS1838B を使用します。  (上の回路図 C 参照)

( IRremoteESP8266 ライブラリはバージョン 2.8.6 です。2025年12月24日にインストールしました )

// N11_IRremote.ino
/* 
 *  赤外線レシーバを NodeMCU に接続し、赤外線リモコンのキーが押されると送出される
 *  赤外線信号を、この赤外線レシーバで受信し、NodeMCU に IRコードを送信します。
 * 
 *  IRremoteESP8266 ライブラリはバージョン 2.8.6 です。2025年12月24日にインストールしました。
 *     2025.12.24
 */
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>

// An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU
// board).
// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts.
// Note: GPIO 14 won't work on the ESP32-C3 as it causes the board to reboot.
#ifdef ARDUINO_ESP32C3_DEV
const uint16_t kRecvPin = 10;  // 14 on a ESP32-C3 causes a boot loop.
#else  // ARDUINO_ESP32C3_DEV
const uint16_t kRecvPin = 14; // D5ピンです
#endif  // ARDUINO_ESP32C3_DEV

IRrecv irrecv(kRecvPin);
decode_results results;

long lastMsg = 0;

void setup() {
  Serial.begin(115200);
  irrecv.enableIRIn(); // Start the receiver
  while (!Serial)  // Wait for the serial connection to be establised.
  delay(50);
  Serial.println();
  Serial.print("IRrecvDemo is now running and waiting for IR message on Pin ");
  Serial.println(kRecvPin);
}

void loop() {
  
  long now = millis();

  if (now - lastMsg > 500) {
     lastMsg = now;
    if (irrecv.decode(&results)) {
      Serial.print(results.value, HEX);Serial.print("  "); Serial.println(results.value);
      irrecv.resume(); // Receive the next value
     }
  }
}

N12_IR_LED
N11_IRremote で読み込んだ信号を用いて、回路の赤外線LEDから赤外線リモコンの各スイッチと同じ信号を発光し、ランプを点灯させます。(上の回路図 F 参照)

// N12_IR_LED.ino
/* 
 *  N11_IRremote で読み込んだ信号を用いて、回路の赤外線LEDから
 *  同じ信号を発光し、ランプを点灯させます
 */
#include <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>

///////////////////////////////////////////////////
//    赤外線LED から送出される信号の 「表」 です     //
//                                              //
//  プログラム N11_IRremote で読み込んだ           //
//  赤外線リモコンのスイッチを押したときに点灯する    //
//  赤外線LED から送出される信号の内容を以下に記入しましょう  //
//   16進数で書いてね: 0x1FE48B7 とか          //
///////////////////////////////////////////////////
// スイッチ番号 / 信号16進数 / スイッチの意味
// 1 /  / ON スイッチ
const uint32_t NO_1 = 0x0  ;
// 2 /  / OFF スイッチ
const uint32_t NO_2 = 0x0  ;
// 3 /  / Mode スイッチ
const uint32_t NO_3 = 0x0  ;
// 4 /  / 4 hour timer
const uint32_t NO_4 = 0x0  ;
// 5 /  / 8 hour timer
const uint32_t NO_5 = 0x0  ;
// 6 /  / Multi 点灯
const uint32_t NO_6 = 0x0  ;
// 7 /  / 色スイッチ
const uint32_t NO_7 = 0x0  ;
// 8 /  / 色スイッチ
const uint32_t NO_8 = 0x0  ;
// 9 /  / 色スイッチ
const uint32_t NO_9 = 0x0  ;
// 10 /  / 色スイッチ
const uint32_t NO_10 = 0x0  ;
// 11 /  / 色スイッチ
const uint32_t NO_11 = 0x0  ;
// 12 /  / 色スイッチ
const uint32_t NO_12 = 0x0  ;
// 13 /  / 色スイッチ
const uint32_t NO_13 = 0x0  ;
// 14 /  / 色スイッチ
const uint32_t NO_14 = 0x0  ;
// 15 /  / 色スイッチ
const uint32_t NO_15 = 0x0  ;
// 16 /  / 色スイッチ
const uint32_t NO_16 = 0x0  ;
// 17 /  / 色スイッチ
const uint32_t NO_17 = 0x0  ;
// 18 /  / 色スイッチ
const uint32_t NO_18 = 0x0  ;

// 赤外線LEDを接続したピン (D2 = GPIO4)
const uint16_t kIrLed = 4;
IRsend irsend(kIrLed);

void setup() {
  Serial.begin(115200);
  irsend.begin();
  Serial.println("IR Sender Ready");
}

void loop() {
  Serial.println("Sending NEC IR signal...");
  
  // NECフォーマットでデータを送信
  // データとビット数はリモコンの解析結果に合わせて変更してください
  // NO_1, NO_2 ....NO_17, NO_18 の値については上記の表をご覧ください
  irsend.sendNEC(NO_2, 32); // OFF スイッチ   
  delay(5000); // 5秒 wait
  irsend.sendNEC(NO_1, 32); // ON スイッチ   
  delay(5000); // 5秒 wait
  irsend.sendNEC(NO_7, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_8, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_9, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_10, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_11, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_12, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_13, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_14, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_15, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_16, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_17, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
  irsend.sendNEC(NO_18, 32); // 色スイッチ   
  delay(5000); // 5秒 wait 
}

(4)IOT 実験項目 1

IOT実験は MQTT を用いて行います。

〇 MQTT  ( Message Queueing Telementry Transport ) とは
 
 MQTT はIBM社とEurotech社のメンバーにより考案されたプロトコルで、コンピュータと通信に関する標準化団体であるOASISにより標準化が進められています。パブリッシュ/サブスクライブ ( Publish / Subscribe ) 型モデルを採用し、メッセージを送信するクライアントをパブリッシャー (Publisher)、メッセージを受信するクライアントをサブスクライバー (Subscriber) とし、MQTTサーバーがメッセージの中継を行います。MQTTサーバーをブローカー (Broker) と呼びます。
 MQTTはメッセージのトピック (Topic) を使って、どのメッセージをどのサブスクライバーに送るかを決定します。送信するパブリッシャーは受信するサブスクライバーを限定せずに情報を発信して、複数のサブスクライバーは、関心のあるメッセージだけをトピックで選択して受信できます。

 分かりやすい、MQTT 説明ページの URL を貼っておきますので、ぜひご覧ください。
https://sakiot.com/what-is-mqtt/

〇 MQTT ブローカーの使いかた

 無料で利用できるMQTT ブローカーを「公開 MQTT ブローカー」と呼びます。ここでは EMQX が提供する公開 MQTT ブローカーを使用します。このブローカーアドレスは  broker.emqx.io です。

chromeブラウザの検索窓に、https://www.emqx.com/en/mqtt/public-mqtt5-broker
と入力して検索すると、EMQX の公開 MQTT ブローカーを利用できるページに移動しますので、以下の通り、設定してください。

〇 IOT 実験項目

MQ1.MQTT を用いて NodeMCU でのカウント値を PC に送り表示しよう。

MQ2.MQTT を用いて PC から NodeMCU に数字1と0を送る。
 数字1で NodeMCU の BUILTIN LEDを点灯し、数字0で消灯しよう。

〇 MQ1 と MQ2のサンプルプログラム

MQ1   MQTT を用いて NodeMCU から PC にカウント値を送ります

// MQ1_MQTT2PC_count . ino

//************************************************/
//*   NodeMCU MQTT client                        */
//*    MQTT を用いて                               */
//*   NodeMCU -> PC : カウント値を表示する           */
//* NodeMCU用のMQTTクライアントライブラリ             */
//* pubsubclientをダウンロードすること Nick O'Leary作 */
//*    2025.5.27                                 */
//***********************************************/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define wifi_ssid "*********" //接続するWiFiのssid
#define wifi_password "*********" //接続するWiFiのパスワード

#define mqtt_server "broker.emqx.io"  // MQTTブローカーアドレス
#define topic "自分で決めたトピックを書いてください" // 設定した Topic

WiFiClient espClient;
PubSubClient client(espClient); //MQTT client生成

void setup() {
    Serial.begin(9600); // WiFiの接続
    while (!Serial) {
      ; // COMポートの接続完了待ち。USBポートの時だけ必要。
    }
    setup_wifi();
    // MQTTブローカーアドレスと
    // portアドレス1883(nodeMCUマイコンのportアドレス1883)
    client.setServer(mqtt_server, 1883);// MQTTブローカーと接続
}

void setup_wifi() {
    delay(10);
    WiFi.begin(wifi_ssid, wifi_password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
}

void reconnect() {
    // 再接続するまでループ
    while (!client.connected()) {
        Serial.print("connecting...");
        if (client.connect("nodeMcu_MQTT")) {
            Serial.println("Success");
        } else {
            Serial.print("Failure, rc=");
            Serial.print(client.state());
            // 3秒後に再接続
            Serial.println("reconnect after 3 seconds");
            delay(3000);
        }
    }
}

long lastMsg = 0;
int count = 0;

void loop() {
    if (!client.connected()) {
        reconnect();
    }
    client.loop();

    long now = millis(); // NodeMCUマイコンの現在時間をミリ秒単位で取得
    if (now - lastMsg > 1000) {
        // 1秒間待機
        lastMsg = now;
        Serial.println(String(count));
        // topicとcount値を MQTTブローカーに送る
        client.publish(topic, String(count).c_str(), true);
        count++;
    }
}


// 練習問題1. NodeMCU に接続されたスイッチの ON と OFF を読み取り、
// それを MQTT で PC に送りなさい。

MQ2   MQTT を用いて PC から文字を NodeMCU に送り、
NodeMCU の BUILTIN_LED を点灯・消灯させる

// MQ2_MQTT2NodeMCU.ino

//************************************************/
//*   NodeMCU MQTT client                        */
//*    MQTT を用いて                               */
//*   PC -> NodeMCU : 数字を送る                 */
//*   数字 1 で NodeMCU の BUILTIN_LED を点灯する  */
//*   数字 0 で消灯です                        */
//* 同時にカウント変数 value の値を NodeMCU から PC に送る */      
//* NodeMCU用のMQTTクライアントライブラリ             */
//* pubsubclientをダウンロードすること Nick O'Leary作 */
//*    2025.5.30                               */
//***********************************************/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define wifi_ssid "************" //接続するWiFiのssid
#define wifi_password "***********" //接続するWiFiのパスワード

#define mqtt_server "broker.emqx.io"  // MQTTブローカーアドレス
#define ttopic "自分で決めたトピックを書いてください" // 設定した Topic

WiFiClient espClient;
PubSubClient client(espClient); //MQTT client生成

unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE	(50)
char msg[MSG_BUFFER_SIZE];
int value = 0;

void setup_wifi() {
  delay(10);
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  //randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  //Serial.println("IP address: ");
  //Serial.println(WiFi.localIP());
}

///////////////////////////////////////////////////////////
// この callback 関数はブローカーから NodeMCU にメッセージが //
// 送られると実行されます                                   //
///////////////////////////////////////////////////////////
void callback(char* topic, byte* payload, unsigned int length) {
  //MQTTの仕様では、ブローカーがクライアントからのメッセージ
  // (このプログラムでは NodeMCU からのメッセージ)をパブリッシュした後に、
  //そのメッセージをブローカー自身が再びクライアント(NodeMCU)に
  //配信(エコー)する設定がデフォルトで有効になっています。
  //これを無効にすることができるそうですが、いまのところ不明
  // そのため、NodeMCU からブローカーにメッセージを送ると、
  //ブローカーからエコーされた同じメッセージを、このcallback 関数が受け取り
  //以下の Serial.print() でシリアルモニタで表示します。 
  Serial.print("[ callback ] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  //**************************************************************//
  //以下は PC から送られる数字によって、NodeMCU に付属するBUILTIN_LED を//
  //  点灯・消灯するサンプルです  -----   1 で点灯、0 で消灯です    //
  // Switch on the LED if an 1 was received as first character    //
  //**************************************************************//
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);
    // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else if((char)payload[0] == '0'){
   // Turn the LED off by making the voltage HIGH
    digitalWrite(BUILTIN_LED, HIGH); 
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("nodeMcu_MQTT")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(ttopic, "~~~~~~~~~~~~~~~ Start ~~~~~~~~~~~~~~~~");
      // ... and resubscribe
      client.subscribe(ttopic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 3 seconds");
      // Wait 3 seconds before retrying
      delay(3000);
    }
  }
}

void setup() {
  // Initialize the BUILTIN_LED pin as an output
  pinMode(BUILTIN_LED, OUTPUT); 
  // Turn the LED off by making the voltage HIGH
  digitalWrite(BUILTIN_LED, HIGH); 
  Serial.begin(9600);
  while (!Serial) {
    ; // COMポートの接続完了待ち。USBポートの時だけ必要。
  }
  setup_wifi();
  // MQTTブローカーアドレスと
  // portアドレス1883(nodeMCUマイコンのportアドレス1883)
  client.setServer(mqtt_server, 1883); // MQTTブローカーと接続
  // callback 関数のセット
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  
  //////////////////////////////////////////////////////////////////
  // 以下で NodeMCU からメッセージ hello world と value のカウント値を //
  // 2秒ごとにブローカーに送ります                                   //
  //////////////////////////////////////////////////////////////////
  unsigned long now = millis(); // NodeMCUマイコンの現在時間を
                                // ミリ秒単位で取得
  if (now - lastMsg > 2000) {
    // 2秒間待機
    lastMsg = now;
    ++value;
    snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value);
    Serial.print("[ Publish message ] ");
    Serial.println(msg);
    client.publish(ttopic, msg);
  }
}


// 練習問題1. NodeMCUのビルドインLEDではなく、実験装置に入っている
// 2つのLEDを MQTT を用いて、PCからNodeMCUに1または0の数字を送り、
// 点灯・消灯させなさい ( 回路図 D 参照 )

(5)IOT 実験項目 2

 公開MQTTブローカーを使う場合、以下の理由でセキュリティ上のリスクを伴います。
〇 認証や暗号化がない場合がある:公開ブローカーは、誰でも簡単に接続できるように、認証(ユーザー名やパスワード)を必要とぜす、暗号化( SSL / TLS )も提供していない場合があります。これにより、通信内容が平文でネットワーク上を流れ、容易に盗聴される可能性があります。
〇 データの公開:送信されたデータが一般に公開されていて、トピックが一致した場合、他のユーザーが購読( subscribe )できてしまいます。個人情報を含むデータをやり取りするのは非常に危険です。

 公開ブローカーは学習やテスト目的には便利ですが、一般の使用には適していません。そこで、セキュリティを確保でき、無料で利用できるMQTTブローカーを探してみました

 以降はこちらをご覧ください。