概要
Arduino Uno R4 WiFiでインターネットから現在時刻を取得して特定の時間にアラームが鳴るシステムをつくる
開発環境
- Window11 Home 24H2(OSビルド 26100.4770)
- エディタ:Arduino IDE 2.3.6
使用した機器
機器名 | 型番 | 個数 |
---|---|---|
Arduino Uno R4 WiFi | AbX00087 | 1 |
ブレッドボード | EIC-102J | 1 |
ブレッドボード用ダイナミックスピーカー | MSI28-12R | 1 |
炭素被膜抵抗(1/2 W 22 Ω) | CFS50J22RB | 1 |
ジャンパーワイヤー(オス-オス) | BBJ-65 | 1 |
使用したライブラリ
- RTC.h
Real Time Clock.時刻の設定や取得,アラームなどの割り込み処理を行う. - NTPClient.h
Network Time Protocol.NTPサーバから現在時刻を取得する. - WiFiC3.h
- WiFiS3.h
- WiFiUdp.h
WiFiC3.h,WiFiS3.h,WiFiUdp.hに関しては公式のドキュメントがなさそうだったが,ネット接続やUDPでの通信に必要なものらしい.
作っていて便利だったショートカット
今まではMacのトラックパッドでそこまで気にならなかったため使ってなかったが,いちいちキーボード→マウスを繰り返すのが面倒だったのでショートカットを使ってみた.わざわざここに書くようなものでもないが一応書いておく.ショートカットは使ったほうがいいなあ.
- Ctrl + U:Arduinoにアップロード
- Ctrl + Shift + M:シリアルモニタの開閉
回路図
スケッチ
基本的にはArduino Uno R4 WiFiのRTCドキュメントにあるものをそのまま利用している.時刻の取得や割込み処理の大体の説明はここを読めばなんとなくわかると思う.またコメントはできる限りサンプルコードのままにしてある.
#include "RTC.h"
#include <NTPClient.h>
#if defined(ARDUINO_PORTENTA_C33)
#include <WiFiC3.h>
#elif defined(ARDUINO_UNOWIFIR4)
#include <WiFiS3.h>
#endif
#include <WiFiUdp.h>
#include "arduino_secrets.h"
///// set parameters for the alarm /////
const int alarmpin = 3;
const int freq = 1800;
const int t = 50;
const int interval = 2000;
bool ledState = false;
bool alarmFrag = false;
///// set alarm time(HH/MM/SS) /////
const int matchhour = 15;
const int matchmin = 17;
const int matchsec = 0;
/////// please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int wifiStatus = WL_IDLE_STATUS;
WiFiUDP Udp;
NTPClient timeClient(Udp);
RTCTime currentTime;
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void connectToWiFi(){
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (wifiStatus != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
wifiStatus = WiFi.begin(ssid, pass);
delay(10000);
}
Serial.println("Connected to WiFi");
printWifiStatus();
}
void setup(){
Serial.begin(9600);
pinMode(alarmpin, OUTPUT);
while (!Serial);
connectToWiFi();
RTC.begin();
Serial.println("\nStarting connection to server...");
timeClient.begin();
timeClient.update();
// Get the current date and time from an NTP server.
// Change the time zone offset to your local one.
auto timeZoneOffsetHours = 9;
auto unixTime = timeClient.getEpochTime() + (timeZoneOffsetHours * 3600);
Serial.print("Unix time = ");
Serial.println(unixTime);
RTCTime timeToSet = RTCTime(unixTime);
RTC.setTime(timeToSet);
RTCTime alarmTime;
alarmTime.setHour(matchhour);
alarmTime.setMinute(matchmin);
alarmTime.setSecond(matchsec);
AlarmMatch matchTime;
matchTime.addMatchHour();
matchTime.addMatchMinute();
matchTime.addMatchSecond();
RTC.setAlarmCallback(alarmCallback, alarmTime, matchTime);
// Retrieve the date and time from the RTC and print them
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("The RTC was just set to: " + String(currentTime));
}
void loop(){
// for debugging
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("current time in Japan: " + String(currentTime));
// if the current time matches the set time, the alarm will sound
if(alarmFrag){
alarmFrag = false;
sound();
}
delay(1000);
}
void alarmCallback(){
if(!ledState){
digitalWrite(LED_BUILTIN, HIGH);
}else{
digitalWrite(LED_BUILTIN, LOW);
}
ledState = !ledState;
alarmFrag = true;
}
void sound(){
for(int i=0; i<10; i++){
for(int j=0; j<10; j++){
tone(alarmpin, freq);
delay(t);
noTone(alarmpin);
delay(t);
}
delay(interval);
}
}
かいつまんで解説
///// set parameters for the alarm /////
const int alarmpin = 3;
const int freq = 1800;
const int t = 50;
const int interval = 2000;
bool ledState = false;
bool alarmFrag = false;
アラームを鳴らすときの各種パラメータを設定する.
- alarmpin:スピーカーを接続するArduinoのPWDピン
- freq:スピーカーから出す音の周波数
- t:音の長さ.ピピピピッのピの部分.
- interval:1アラームの間隔.ピピピピッとピピピピッの間の長さ.
- ledState:設定時刻になったらArduinoのLEDが光るようにしたのでLEDの状態を宣言しておく
- alarmFrag:設定時刻になったときにアラームを鳴らすためのフラグ
///// set alarm time(HH/MM/SS) /////
const int matchhour = 15;
const int matchmin = 17;
const int matchsec = 0;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
RTCTime alarmTime;
alarmTime.setHour(matchhour);
alarmTime.setMinute(matchmin);
alarmTime.setSecond(matchsec);
AlarmMatch matchTime;
matchTime.addMatchHour();
matchTime.addMatchMinute();
matchTime.addMatchSecond();
上部と中部で何時(matchhour)何分(matchmin)何秒(matchsec)にアラームを鳴らすか,下部でどこまで一致させるかを設定する.
この場合だと15時17分00秒に設定している.
void alarmCallback(){
if(!ledState){
digitalWrite(LED_BUILTIN, HIGH);
}else{
digitalWrite(LED_BUILTIN, LOW);
}
ledState = !ledState;
alarmFrag = true;
}
RTC.setAlarmCallback(alarmCallback, alarmTime, matchTime);
でalarmTimeとmatchTimeの条件にしたがってalarmCallback関数を呼び出している.呼び出されたらLEDの状態を切り替え,アラームのフラグをtrueにする(loop関数につながる).
void sound(){
for(int i=0; i<10; i++){
for(int j=0; j<10; j++){
tone(alarmpin, freq);
delay(t);
noTone(alarmpin);
delay(t);
}
delay(interval);
}
}
アラームの音を決める.ピピピピピピピピピピッと鳴るようにしてみた.これはiPhoneの時計アプリで設定できるタイマー終了時の音であるクラシック-ヒルサイドを参考にした.
void loop(){
// for debugging
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.println("current time in Japan: " + String(currentTime));
// if the current time matches the set time, the alarm will sound
if(alarmFrag){
alarmFrag = false;
sound();
}
delay(1000);
}
デバッグ用に現在時刻をシリアル表示している.alarmCallback関数でアラームのフラグが立ったらアラームを鳴らし,フラグを初期化している.
はじめはalarmCallback関数の中でアラームを鳴らすようにしていたが,for文でアラームを回すと音が出なかった(tone関数だけだと音は鳴った).調べてみたら割り込み処理内ではdelay()をすぐに抜けてしまって無効になるらしい.
使い方
- Arduino IDEに上のスケッチntp.inoを書く
- 同じディレクトリにarduino_secrets.hを作り,接続するネットワークのSSIDとパスワードを記述する
-
const int matchhour = 15; const int matchmin = 17; const int matchsec = 0;
を好きな時刻に設定する - Arduinoにアップロード!
#define SECRET_SSID "接続するSSID"
#define SECRET_PASS "そのパスワード"
動作(シリアルモニタと音)
下書きだと接続が拒否されましたと言われプレビューできない
少し汚めのモニターが映るので注意.
感想
もっと簡単なアラーム時刻の設定をできるようにしたり,アラーム音を単音ではなく和音とかきれいな音にできたらもっと楽しそう.今回はIDEでやったけど,CLIでできたらかっこいい.
初めてqiitaの記事書いたので感想や指摘など書いてくれると助かる.