コンテンツにスキップ
【vol.2】はじめての電子工作⊹₊⋆ Arduino Uno R4 WiFiで傘忘れないよセンサーを作る

【vol.2】はじめての電子工作⊹₊⋆ Arduino Uno R4 WiFiで傘忘れないよセンサーを作る

こんにちは!アルバイトの中川です

前回の記事では、無事LEDマトリックスを光らせることに成功しました!
この連載では、電子工作未経験の私が成長していく姿をお届けできればと思っています!

暑い日が続いていますが皆さんどうお過ごしですか?

私は、天気予報をあまり見ないので、突然のゲリラ豪雨に出先で絶望することが多いです……今回は、天気のAPIを取得して「傘忘れないよセンサー」を作ります!

今回もArduino Uno R4 wifi を使って作っていこうと思います✴︎
みなさんも一緒に作っていきましょう!

目標は

  • 天気APIを取得してその日の天気、降水確率がわかるようにする
  • 降水確率によって色を変えて、LEDを光らせる
  • ドアを開けた時に光らせるようにする

✴︎使用機器

   A-Type Cタイプ
           Type C-Cタイプ


初めての方に!こちらもオススメです!

Arduino Uno R4 WiFiをはじめようキット


✴︎作業環境

  • PC(MacBook Air)
    CPU:Apple M5
    RAM:32 GB
    OS:macOS 26.4.1

それでは、さっそく作っていきます!
Arduino Uno R4 wifiの動かし方は前回の記事を参考にしてください☆


ArduinoをWi-Fiに接続する

まずはArduinoをインターネットに接続します。

Arduino UNO R4 WiFiにはWi-Fi機能が搭載されているため、追加のモジュールは必要ありません。

コードをコピーして、Wi-Fi名とパスワードを置き換えてください!

#include <WiFiS3.h> // Wi-Fi通信に必要なライブラリを読み込みます。

// 使いたいWi-Fi名とパスワードに置き換えてください
char ssid[] = "Wi-Fi名";
char pass[] = "パスワード";

void setup() {
  Serial.begin(115200); // シリアルモニターの値と合わせてください
  delay(3000);

  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println();
  Serial.println("接続成功!");
}

void loop() {
}

書き込み後にシリアルモニターを開きます。

接続成功!

と表示されれば接続成功です!


天気データを取得する

Wi-Fi接続ができたら、次は天気データを取得します。

そこで今回は無料で利用できるAPIである、Open-Meteoを使用します。 

まずはArduinoに書き込む前に、ブラウザでAPIのURLを開いてみます。

今回使うURLはこちらです。

https://api.open-meteo.com/v1/forecast?latitude=35.6812&longitude=139.7671&current=temperature_2m&daily=precipitation_probability_max&timezone=Asia%2FTokyo&forecast_days=1

このURLでは、東京駅付近の天気データを取得しています。

ブラウザで開くと、文字がたくさん並んだデータが表示されます。
これがJSONです。

今回取り出したいのは、次の2つです。

  • current.temperature_2m:現在の気温
  • daily.precipitation_probability_max[0]:今日の最大降水確率

ArduinoでJSONを読み取る

取得したJSONデータから、気温と降水確率を取り出すために、今回はArduinoJsonライブラリを使用します。

Arduino IDEのライブラリマネージャを開いて、ArduinoJsonを検索してインストールします。


ArduinoJsonを使うと、APIから返ってきたJSONデータの中から、必要な値だけを取り出すことができます。

たとえば、

float temperature;
int rainProbability;

のように、気温と降水確率を変数に保存して扱えるようになります。 

さらに、ArduinoからWeb APIへアクセスするために、ArduinoHttpClientもインストールします。

インストールできたら、先ほどのWi-Fi接続のコードに、天気データを取得する処理を追加していきます。

#include <WiFiS3.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>

// 自分のWi-Fi名とパスワードに置き換えてください
char ssid[] = "Wi-Fi名";
char pass[] = "パスワード";

char server[] = "api.open-meteo.com";

WiFiSSLClient wifi;
HttpClient client = HttpClient(wifi, server, 443);

void setup() {
  Serial.begin(115200);
  delay(3000);

  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println();
  Serial.println("接続成功!");

  getWeather();
}

void loop() {
}

void getWeather() {
  String path = "/v1/forecast?latitude=35.6812&longitude=139.7671&current=temperature_2m&daily=precipitation_probability_max&timezone=Asia%2FTokyo&forecast_days=1";

  Serial.println("天気データを取得中...");

  client.get(path);

  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  if (statusCode != 200) {
    Serial.println("天気データの取得に失敗しました");
    return;
  }

  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, response);

  if (error) {
    Serial.println("JSONの読み取りに失敗しました");
    return;
  }

  float temperature = doc["current"]["temperature_2m"];
  int rainProbability =
      doc["daily"]["precipitation_probability_max"][0];

  Serial.print("現在の気温: ");
  Serial.print(temperature);
  Serial.println(" ℃");

  Serial.print("今日の降水確率: ");
  Serial.print(rainProbability);
  Serial.println(" %");
}

書き込みが終わったら、シリアルモニターを開きます。

うまく取得できると、

のように表示されます。

Arduinoでインターネットから天気情報を取得できました!

次は、この降水確率を使って、傘を持っていくべきかどうかを判定してみます。


気温をLEDマトリックスに表示する

前回は、LEDマトリックスにドット絵を表示しました。

こんな感じ

今回は取得した気温をLEDマトリックスに表示してみます。

Arduino UNO R4 WiFiには、12×8のLEDマトリックスが搭載されています。
このLEDを使えば、数字や簡単なマークを表示できます。

今回は取得した気温を整数にして、LEDマトリックスに表示します。
たとえば気温が25.3℃だった場合は、四捨五入して「25」と表示します。

前回はお絵描きをすることでそのドットの情報をゲットしましたが、今回は気温を表示させたいので1-40くらいの数字を全部書いて保存するのは大変です……

そこで、数字とドットの位置を対応させます。

byte numbers[10][5][3] = {
  {{1,1,1}, {1,0,1}, {1,0,1}, {1,0,1}, {1,1,1}}, // 0
  {{0,1,0}, {1,1,0}, {0,1,0}, {0,1,0}, {1,1,1}}, // 1
  {{1,1,1}, {0,0,1}, {1,1,1}, {1,0,0}, {1,1,1}}, // 2
  {{1,1,1}, {0,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}, // 3
  {{1,0,1}, {1,0,1}, {1,1,1}, {0,0,1}, {0,0,1}}, // 4
  {{1,1,1}, {1,0,0}, {1,1,1}, {0,0,1}, {1,1,1}}, // 5
  {{1,1,1}, {1,0,0}, {1,1,1}, {1,0,1}, {1,1,1}}, // 6
  {{1,1,1}, {0,0,1}, {0,1,0}, {0,1,0}, {0,1,0}}, // 7
  {{1,1,1}, {1,0,1}, {1,1,1}, {1,0,1}, {1,1,1}}, // 8
  {{1,1,1}, {1,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}  // 9
};

これで、数字を表示できるようにします。

LEDマトリックスを使うために、Arduino_LED_Matrixライブラリを読み込みます!
コードはこんな感じです。

#include <WiFiS3.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include <Arduino_LED_Matrix.h>

// 自分のWi-Fi名とパスワードに置き換えてください
char ssid[] = "Wi-Fi名";
char pass[] = "パスワード";

char server[] = "api.open-meteo.com";

WiFiSSLClient wifi;
HttpClient client = HttpClient(wifi, server, 443);
ArduinoLEDMatrix matrix;

byte frame[8][12];

// 各数字でどのLEDを点灯させるか設定
byte numbers[10][5][3] = {
  {{1,1,1}, {1,0,1}, {1,0,1}, {1,0,1}, {1,1,1}}, // 0
  {{0,1,0}, {1,1,0}, {0,1,0}, {0,1,0}, {1,1,1}}, // 1
  {{1,1,1}, {0,0,1}, {1,1,1}, {1,0,0}, {1,1,1}}, // 2
  {{1,1,1}, {0,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}, // 3
  {{1,0,1}, {1,0,1}, {1,1,1}, {0,0,1}, {0,0,1}}, // 4
  {{1,1,1}, {1,0,0}, {1,1,1}, {0,0,1}, {1,1,1}}, // 5
  {{1,1,1}, {1,0,0}, {1,1,1}, {1,0,1}, {1,1,1}}, // 6
  {{1,1,1}, {0,0,1}, {0,1,0}, {0,1,0}, {0,1,0}}, // 7
  {{1,1,1}, {1,0,1}, {1,1,1}, {1,0,1}, {1,1,1}}, // 8
  {{1,1,1}, {1,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}  // 9
};

void setup() {
  Serial.begin(115200);
  delay(3000);

  matrix.begin();

  Serial.print("Wi-Fiに接続中");

  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println();
  Serial.println("接続成功!");

  getWeather();
}

void loop() {
}

void getWeather() {
  String path = "/v1/forecast?latitude=35.6812&longitude=139.7671&current=temperature_2m&daily=precipitation_probability_max&timezone=Asia%2FTokyo&forecast_days=1";

  Serial.println("天気データを取得中...");

  client.get(path);

  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  if (statusCode != 200) {
    Serial.println("天気データの取得に失敗しました");
    return;
  }

  JsonDocument doc;
  DeserializationError error = deserializeJson(doc, response);

  if (error) {
    Serial.println("JSONの読み取りに失敗しました");
    return;
  }

  float temperature = doc["current"]["temperature_2m"];
  int rainProbability =
      doc["daily"]["precipitation_probability_max"][0];

  Serial.print("現在の気温: ");
  Serial.print(temperature);
  Serial.println(" ℃");

  Serial.print("今日の降水確率: ");
  Serial.print(rainProbability);
  Serial.println(" %");

  int temperatureInt = round(temperature);

  Serial.print("LEDマトリックスに表示する気温: ");
  Serial.println(temperatureInt);

  showNumber(temperatureInt);
}

void clearFrame() {
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 12; x++) {
      frame[y][x] = 0;
    }
  }
}

void drawDigit(int digit, int startX) {
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 3; x++) {
      frame[y + 1][x + startX] = numbers[digit][y][x];
    }
  }
}

void showNumber(int number) {
  clearFrame();

  if (number < 0) {
    number = 0;
  }

  if (number > 99) {
    number = 99;
  }

  int tens = number / 10;
  int ones = number % 10;

  drawDigit(tens, 2);
  drawDigit(ones, 7);

  matrix.renderBitmap(frame, 8, 12);
}

実行できると、こんな感じになります!


降水確率によってLEDの色を変える

次に、取得した降水確率を使って、LEDの色を変えてみます。

今回は、降水確率によってこのように判定します!

降水確率 029%→

降水確率 3059%→

降水確率 60%以上

RGB LEDは、赤・緑・青の3色のLEDが1つになった部品です。
赤と緑を同時に光らせると黄色っぽく見えるので、今回はそれを利用します。


回路を組む

RGB LEDのそれぞれの足を、Arduinoのピンに接続します。

今回は次のように接続しました。

D9  抵抗 → RGB LEDの赤端子

D10 → 抵抗 → RGB LEDの緑端子

D11 → 抵抗 → RGB LEDの青端子

RGB LEDの共通端子 → GND

それぞれのピンとLEDの間には、電流を制限するために2.2kΩの抵抗を入れます。

powerのGNDをブレッドボードの-に繋ぐのを忘れずに!(これをやってなくて全然光りませんでした)

配線図はこんな感じです!
※配線図の中ではArduino Uno R3ですが、実際にはArduino Uno R4 WiFiを使用しています!

LEDの色を制御するコード

まずは、RGB LEDを制御するためのピンを追加します。

const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;

setup()の中で、これらのピンを出力に設定します。

pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);

そして、LEDの色を変える関数を作ります。

void setColor(int red, int green, int blue) {
  analogWrite(RED_PIN, red);
  analogWrite(GREEN_PIN, green);
  analogWrite(BLUE_PIN, blue);
}

最後に、降水確率によって色を変える関数を作ります。

void showRainColor(int rainProbability) {
  if (rainProbability < 30) {
    setColor(0, 0, 60);
  } else if (rainProbability < 60) {
    setColor(60, 60, 0);
  } else {
    setColor(60, 0, 0);
  }
}

この関数を、天気データを取得したあとに呼び出します。

showRainColor(rainProbability);

これで、降水確率に応じてLEDの色が変わるようになります。


ドアを開いたかを判定する

最後に、玄関のドアを開けたタイミングだけ通知するようにしてみます。

今回は磁気リードスイッチを使用しました。

リードスイッチは、磁石が近づくとスイッチがONになり、離れるとOFFになるセンサです。ドアとドア枠にそれぞれ取り付けることで、ドアの開閉を検知できます。

今回は以下のように接続しました。

リードスイッチ 片方 → D2

片方 → GND

配線図はこんな感じです!
※配線図の中ではArduino Uno R3ですが、実際にはArduino Uno R4 WiFiを使用しています!


Arduinoでは、INPUT_PULLUPを使用し、次のように設定します。

pinMode(REED_PIN, INPUT_PULLUP);

そして、ドアが開いているかどうかを次のように判定します。

bool doorOpen = digitalRead(REED_PIN) == HIGH;
if (doorOpen) {
  showRainColor(rainProbability);
} else {
  setColor(0, 0, 0);
}

これで、ドアが閉じている間はRGB LEDを消灯し、ドアを開けたときだけ降水確率に応じた色で通知できるようになりました。

完成コード

ここまでの処理をまとめると、コードはこのようになります˖ . ݁𝜗𝜚. ݁₊

#include <WiFiS3.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include "Arduino_LED_Matrix.h"

char ssid[] = "Wi-Fi名";
char pass[] = "パスワード";

char server[] = "api.open-meteo.com";

WiFiSSLClient wifi;
HttpClient client = HttpClient(wifi, server, 443);
ArduinoLEDMatrix matrix;

const int RED_PIN = 9;
const int GREEN_PIN = 10;
const int BLUE_PIN = 11;
const int REED_PIN = 2;

const unsigned long WEATHER_INTERVAL_MS =
    10UL * 60UL * 1000UL;

unsigned long lastWeatherMs = 0;
int rainProbability = 0;

byte frame[8][12];

byte numbers[10][5][3] = {
  {{1,1,1}, {1,0,1}, {1,0,1}, {1,0,1}, {1,1,1}}, // 0
  {{0,1,0}, {1,1,0}, {0,1,0}, {0,1,0}, {1,1,1}}, // 1
  {{1,1,1}, {0,0,1}, {1,1,1}, {1,0,0}, {1,1,1}}, // 2
  {{1,1,1}, {0,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}, // 3
  {{1,0,1}, {1,0,1}, {1,1,1}, {0,0,1}, {0,0,1}}, // 4
  {{1,1,1}, {1,0,0}, {1,1,1}, {0,0,1}, {1,1,1}}, // 5
  {{1,1,1}, {1,0,0}, {1,1,1}, {1,0,1}, {1,1,1}}, // 6
  {{1,1,1}, {0,0,1}, {0,1,0}, {0,1,0}, {0,1,0}}, // 7
  {{1,1,1}, {1,0,1}, {1,1,1}, {1,0,1}, {1,1,1}}, // 8
  {{1,1,1}, {1,0,1}, {1,1,1}, {0,0,1}, {1,1,1}}  // 9
};

void setup() {
  Serial.begin(115200);
  delay(3000);

  matrix.begin();

  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
  pinMode(REED_PIN, INPUT_PULLUP);

  Serial.print("Wi-Fiに接続中");

  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println();
  Serial.println("接続成功!");

  getWeather();
  lastWeatherMs = millis();
}

void loop() {
  if (millis() - lastWeatherMs >= WEATHER_INTERVAL_MS) {
    lastWeatherMs = millis();
    getWeather();
  }

  bool doorOpen = digitalRead(REED_PIN) == HIGH;

  if (doorOpen) {
    showRainColor(rainProbability);
  } else {
    setColor(0, 0, 0);
  }

  static unsigned long lastDebugMs = 0;

  if (millis() - lastDebugMs >= 1000 || lastDebugMs == 0) {
    lastDebugMs = millis();

    Serial.print("rainProbability=");
    Serial.print(rainProbability);
    Serial.print(" door=");
    Serial.print(doorOpen ? "OPEN" : "CLOSED");
    Serial.print(" LED=");
    Serial.println(doorOpen ? "COLOR" : "OFF");
  }
}

void getWeather() {
  String path = "/v1/forecast?latitude=35.6812&longitude=139.7671&current=temperature_2m&daily=precipitation_probability_max&timezone=Asia%2FTokyo&forecast_days=1";

  Serial.println("天気データを取得中...");

  client.get(path);

  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  if (statusCode != 200) {
    Serial.println("天気データの取得に失敗しました");
    return;
  }

  JsonDocument doc;
  DeserializationError error =
      deserializeJson(doc, response);

  if (error) {
    Serial.println("JSONの読み取りに失敗しました");
    return;
  }

  float temperature =
      doc["current"]["temperature_2m"];

  rainProbability =
      doc["daily"]["precipitation_probability_max"][0];

  Serial.print("現在の気温: ");
  Serial.print(temperature);
  Serial.println(" ℃");

  Serial.print("今日の降水確率: ");
  Serial.print(rainProbability);
  Serial.println(" %");

  int temperatureInt = round(temperature);
  showNumber(temperatureInt);

  setColor(0, 0, 0);
}

void showRainColor(int rainProbability) {
  if (rainProbability < 30) {
    setColor(0, 0, 60);
    Serial.println("雨の心配は少なめです");
  } else if (rainProbability < 60) {
    setColor(60, 60, 0);
    Serial.println("少し雨に注意です");
  } else {
    setColor(60, 0, 0);
    Serial.println("傘を持っていきましょう!");
  }
}

void setColor(int red, int green, int blue) {
  analogWrite(RED_PIN, red);
  analogWrite(GREEN_PIN, green);
  analogWrite(BLUE_PIN, blue);
}

void clearFrame() {
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 12; x++) {
      frame[y][x] = 0;
    }
  }
}

void drawDigit(int digit, int startX) {
  for (int y = 0; y < 5; y++) {
    for (int x = 0; x < 3; x++) {
      frame[y + 1][x + startX] =
          numbers[digit][y][x];
    }
  }
}

void showNumber(int number) {
  clearFrame();

  if (number < 0) {
    number = 0;
  }

  if (number > 99) {
    number = 99;
  }

  int tens = number / 10;
  int ones = number % 10;

  drawDigit(tens, 2);
  drawDigit(ones, 7);

  matrix.renderBitmap(frame, 8, 12);
}

動かしてみる


実際にドアに貼り付けて動かしてみましょう!
今まではパソコンに接続したまま実行していたと思うのですが、今回はパソコンから外さないとドアに貼り付けられないので、ArduinoにさしているUSB-Cをモバイルバッテリーに付け替えます。10-20秒くらい待ったらパソコンに繋いでいる時と同じ挙動をするはずです!

ドアに貼り付けるのが難しくてマスキングテープぐるぐる巻きにしてしまったので見た目だいぶ不恰好です(  ; ᴗ ;  )

実際に動かしてみるとこんな感じになります!

開いた時だけLEDが光る!

これで、天気APIから取得した降水確率を使って、傘を持っていくべきかどうかを光で知らせることができました!

完成!!

今回は、Arduino UNO R4 WiFiを使って、天気APIから気温と降水確率を取得し、LEDマトリックスに気温を表示しつつ、降水確率に応じてRGB LEDの色を変える、傘忘れないよセンサーを作りました。

インターネット上のデータをArduinoで取得できるようになると、天気だけでなく、気温や湿度、電車の運行情報など他にも応用がききそうです!

それでは、また次回の記事でお会いしましょう!

次の記事 8月7日締め切り、アイデアをシェアして深圳に行こう! #M5Stack 2026年グローバルイノベーションコンテスト #M5StackInnovationContest