【新歓ブログリレー】ESP32でボタンが押された回数をサーバーに送信する
ちょっとしたIoT講座
電算(電子計算機研究会)はIoT講座をやっていたのですが、去年はコロナウイルスの影響でIoT講座を開講できていませんでした。
そこで少しでもIoTに触れてもらうため、この記事ではArduino互換のマイコンであるESP32をつかって簡単なシステムを作ってみます。電算のIoT講座ではラズベリーパイを扱っているので、ネタ被りもしないかなという意図もあります。
やることはWiFiを使ったインターネット接続、サーバーとのソケット通信、割込み処理といったことです。ESP32がない人もコードだけ見てこんな感じなんだと思ってもらえれば幸いです。
ESP32とは
ESP32はArduinoの開発環境で開発できるマイコンです。
ESP32はラズベリーパイほどの性能がなく基本的にOS無しで動かします。しかし、Wi-FiやBluetoothが使える上に省電力で安い(1000円~2000円)です。
Arduino IDEのセットアップ
公式サイトのダウンロードページからダウンロードします。インストーラーをダウンロードがおすすめです。windowsユーザーなら『Windows Win 7 and newer』を選択します。
寄付してみないか?と聞かれますが、寄付しないなら『JUST DOWNLOAD』を押してください。
後はインストーラーを起動して指示に従ってください。
インストールしたらESP32のための設定をします。
ファイル>環境設定を開きます。
追加ボードマネージャのURLを https://dl.espressif.com/dl/package_esp32_index.json にします。
ツール>ボード>ボードマネージャを開きます。
ESP32で検索してEspressif Systemsが提供しているものをダウンロードします。
ツール>ボードから『ESP32 Dev Module』を選択。
以下の項目もお手持ちのESP32に合わせて変えましょう。
Flash Mode
Flash Frequency
CPU Frequency
Flash Size
Upload Speed
ボタンを使ってプルアップ回路を作る
記事書く気力が尽きかけてるので丸投げします。下記のページを参考にプルアップ回路を作ってください。図がついていてわかりやすいですね。
ピンの役割はESP32 Pinout Reference: Which GPIO pins should you use?を参照。
Arduinoのコードを書く
目標を確認します。
ESP32のボタンが押された回数をサーバーに送信する
早速コードを書いていきます。言語はC/C++です。
チェックボタンでコンパイル。矢印ボタンでコンパイルとESP32への書き込みが行われます。
#include <WiFi.h>
#include <WiFiClient.h>
#include <SPI.h>
//サーバーに送るデータのサイズ(byte)
#define PACKET_SIZE 2
#define BUTTON_PIN 35/*ここに対応したピンの番号*/
//サーバーにデータを送る間隔
#define INTERVAL 10000
const byte serverIP[] = { 255, 255, 255, 255 };//ここにサーバーのIPを4byteで
const int serverPort = 8888; //ここにサーバーのポート番号
const char ssid[] = "ここにWiFiのSSID";
const char pass[] = "ここにWiFiのパスワード";
//サーバーに送るデータ
byte packet[PACKET_SIZE] = {};
//送信するかの判定に使う
volatile bool sending_flag = false;
//ボタンが押された数
volatile unsigned short int num = 0;
//ボタンが押されたとき呼ばれる割込み処理
void IRAM_ATTR onButton(){
++num;
sending_flag = true;
Serial.print("ボタンが押された:");
Serial.print(num);
Serial.println("回目");
}
WiFiClient client;
//データを送信
void sendData(){
sending_flag = false;
packet[0] = static_cast<byte>(num >> 8);
packet[1] = static_cast<byte>(num % 0x100);
client.write(packet, PACKET_SIZE);
}
void setup() {
Serial.begin(9600);
//WiFiに接続
Serial.print("SSID:");
Serial.println(ssid);
WiFi.begin(ssid, pass);
int TTL = 5;
Serial.print("WiFiに接続中");
delay(5000);
while( WiFi.status() != WL_CONNECTED && --TTL>0) {
WiFi.begin(ssid, pass);
Serial.print(".");
delay(5000);
}
if( WiFi.status() != WL_CONNECTED) {
Serial.println("\nWiFiに接続失敗");
return;
}
Serial.print("\nWiFiに接続しました\nIPアドレス:");
Serial.println(WiFi.localIP());
//サーバーに接続
client.connect(serverIP, serverPort);
TTL = 5;
Serial.print("Connecting to Server");
delay(5000);
while( !client.connected() && --TTL>0) {
client.connect(serverIP, serverPort);
Serial.print(".");
delay(5000);
}
if( !client.connected()) {
Serial.println("\nサーバーに接続失敗");
return;
}
Serial.println("\nサーバーに接続しました");
//ピンの設定
pinMode(BUTTON_PIN, INPUT);
//割込み処理の設定
attachInterrupt(BUTTON_PIN, onButton, FALLING);
}
void loop() {
//10秒間隔で送信
delay(INTERVAL);
//最後に送ったデータから更新されているなら送信
if(sending_flag) sendData();
}
内容に関わらずsetup関数は初めに呼ばれ、loop関数はずっと実行され続けます。
個々のコードの意味はコメント通りですね。
WiFiのSSIDとパスワード、サーバーのIPとポート、PIN番号は自分が使うものに書き換えます。
delay関数について
単位はミリ秒
Serial.print関数について
ツール>シリアルモニタからシリアルモニタを開けます。Serial.printはシリアルモニタにメッセージを出力できます。
接続待ちについて
WiFi.beginとClient.connectは実行してすぐ接続が確立されたか判定するとうまくいかなかったので待ち時間を作りました。接続が確立されていなかったら一定回数再試行します。
割込み処理について
下記のページを見てください。
サーバーに送るデータについて
Client.write関数はbyte型のデータをサーバーに送ります。引数はbyte[]と配列のサイズです。今回は2byteのデータを送ります。
1byteだと255までしかカウントできないので2byteにして65535までカウントできるようにしました。ビックエンディアンです。
サーバーのコードを書く
言語はPythonです。
import socket
class Receiver:
ADDR = "ここにサーバーのIP"
RECEIVE_PORT = 8888 #ここにサーバーのポート番号
def __init__(self):
print("Receiver Init")
def _receiving(self, s_conn):
while True:
data = s_conn.recv(2)
##受け取ったbyte列を整数型に変換
num = int.from_bytes(data[0:2], "big")
print("ボタンが押された回数は", num, "です")
def start(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((Receiver.ADDR, Receiver.RECEIVE_PORT))
s.listen(1)
while True:
conn, addr = s.accept()
try:
print("接続しました:", addr)
self._receiving(conn)
finally:
conn.close()
if __name__ == "__main__":
receiver = Receiver()
receiver.start()
byte型の配列を文字コードとして扱ったり、数値に変換する便利な関数があります。すごい!
実行
実行してみましょう。
1.Arduino IDEからESP32にプログラムのコードを書きこむ
2.自分のパソコンをサーバーとして公開してサーバープログラムを実行
3.Arduino IDEのシリアルモニタを開きESP32のリセットボタンを押してプログラムを実行開始
パソコンからでないとシリアルモニタを見れないのでESP32はパソコンにつなぎます。ESP32は電源に接続したらすぐに書き込まれているプログラムが実行されるので注意。
ESP32のリセットボタンを押すとプログラムが初めから実行され直します。サーバーの準備ができたら、リセットボタンを押して接続開始しましょう。
最後に
お疲れ様でした!
電算ではもっと時間をかけてラズベリーパイでIoT講座をやってました。
カメラで画像認識やってみたり、ICカードリーダーで学生証を読み取ったり、ラジコンつくってみたり好きに出来ます。
今年はIoT講座実施できるといいですね。
参考文献
ESP32 Pinout Reference: Which GPIO pins should you use?
自分が使っているノートパソコンについて
Dell Inspiron 14 5000
購入時期 | 2019年5月 |
CPU | Core i5-8265U |
メモリ | 8GB×1,DDR4,2666MHz |
ストレージ | KBG40ZNS256G NVMe TOSHIBA(SSD 256GB) |
GPU | UHD Graphics 620(CPU内蔵) |
ディスプレイ | 14.0インチFHD(1920×1080)IPS LEDバックライト Narrow Border デイスプレイ |
サイズ | 324mm×231mm |
重さ | 1.5㎏ |
値段 | 62,266円 |
その他 | 光学ドライブなし タッチパネルなし テンキーなし |
情報工1,2年生の間はこれで困ったことはなかったです。ZoomとChromeとVScodeとAcrobat同時に開いても問題ありません。
ただし、大学が出したノートPCの推奨スペックによると、情報工はメモリが16GB必要になるのでこれから困るのかもしれません🥺
Unityとかやると重いので3D系やりたい人はスペック高いとよさげ。Reactのビルドするときもとても時間がかかります。そういうのはデスクトップでやるのが正解かもしれませんが…
ストレージは絶対SSDがいいです。前に使ってたHDD搭載のPCは立ち上げがとても遅く不便でした。SSDの快適さを知ったらHDDには戻れません。
CPUについてですが今はRyzen搭載のノートPCが充実しているのでIntel以外も全然ありだと思います。
Dell製のPCはDELL公式サイトから買うと安くなります。
コメント入力