今回は、M5Stack と Node-RED を使って、ローカルネットワーク内で完結する「お題に対してA/Bで即時投票できるシステム」を構築してみました。
システム概要
- 投票端末:M5Stack Core
- 集計・表示:Node-RED(HTTP通信)
- 通信方式:M5Stack → Node-REDへHTTP POST(MQTT不要)
- 投票方式:A/Bボタンで即時投票、Cボタンで次のテーマへ変更
- 投票結果:Node-REDダッシュボード上にリアルタイム表示
構成イメージ
[M5Stack端末]
↓ (HTTP POST)
[Node-RED(PC)]
→ ダッシュボードで集計・表示
M5Stack 側の実装
M5Stackでは、複数のテーマと選択肢を配列で定義し、電源投入時にランダムで1つ表示。
AまたはBボタンで即投票、Cボタンで次のテーマへ更新・送信します。
<code>#include <M5Stack.h>
#include <WiFi.h>
#include <HTTPClient.h>
// Wi-Fi設定
const char* ssid = "smartlight-net";
const char* password = "42397311";
// Node-RED HTTPエンドポイント
const char* serverName = "http://192.168.1.46:1880/vote";
// テーマ一覧
const char* themes[][3] = {
{"ランチはどっち?", "ラーメン", "カレー"},
{"好きな季節は?", "春", "秋"},
{"旅行するなら?", "海", "山"},
{"ペット飼うなら?", "犬", "猫"},
{"観戦するなら?", "サッカー", "野球"}
};
const int themeCount = sizeof(themes) / sizeof(themes[0]);
int currentThemeIndex = 0;
void connectWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void sendToServer(String vote, String theme = "") {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverName);
http.addHeader("Content-Type", "application/json");
String json = "{";
if (vote != "") json += "\"vote\":\"" + vote + "\"";
if (theme != "") {
if (vote != "") json += ",";
json += "\"theme\":\"" + theme + "\"";
}
json += "}";
http.POST(json);
http.end();
}
}
void displayTheme() {
M5.Lcd.clear();
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextSize(2);
M5.Lcd.println("テーマ:");
M5.Lcd.println(themes[currentThemeIndex][0]);
M5.Lcd.println("A:" + String(themes[currentThemeIndex][1]));
M5.Lcd.println("B:" + String(themes[currentThemeIndex][2]));
M5.Lcd.println("C:次のテーマ");
}
void setup() {
M5.begin();
connectWiFi();
randomSeed(analogRead(36));
currentThemeIndex = random(themeCount);
displayTheme();
sendToServer("", themes[currentThemeIndex][0]); // 初回テーマ送信
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
sendToServer("A");
M5.Lcd.setCursor(0, 180);
M5.Lcd.println("Aに投票しました");
}
if (M5.BtnB.wasPressed()) {
sendToServer("B");
M5.Lcd.setCursor(0, 200);
M5.Lcd.println("Bに投票しました");
}
if (M5.BtnC.wasPressed()) {
currentThemeIndex = random(themeCount);
displayTheme();
sendToServer("", themes[currentThemeIndex][0]); // 新テーマ送信
}
}
</code>
Code language: PHP (php)
Node-RED 側の構成
HTTP受信フロー

functionノードのコード
<code>let voteData = flow.get('voteData') || {
theme: '',
A: 0,
B: 0
};
// テーマ変更時にリセット
if (msg.payload.theme && msg.payload.theme !== voteData.theme) {
voteData = {
theme: msg.payload.theme,
A: 0,
B: 0
};
}
// 投票処理
if (msg.payload.vote === 'A') voteData.A++;
if (msg.payload.vote === 'B') voteData.B++;
flow.set('voteData', voteData);
msg.payload = voteData;
return msg;
</code>
Code language: JavaScript (javascript)
M5Stuckcoreでの表示

左ボタン:A 真ん中ボタン:B 右ボタン:C
ダッシュボードでの表示
Node-REDのDashboardで以下を表示しています:

Cボタンでテーマが変わると自動でリセットされ、常に新しい投票を受け付ける設計です。
まとめ
A/Bボタンによる即時投票、Cボタンによるテーマ変更もスムーズに動作し、結果はダッシュボード上にリアルタイムで反映されます。ただしM5Stuckcoreが日本語で表示できないため英語でしか表示できません。