Arduino Uno R4 WiFiとOLEDで「いま話しかけていい?」を見える化するデスクステータス表示器を作ってみた

はじめに

オフィスや在宅作業で、地味だけど意外と困るのが「いま話しかけてよいか分からない」問題です。

・すぐ相談したいけれど、相手が集中作業中かもしれない
・会議中なのか離席中なのか、見ただけでは分からない
・毎回「今大丈夫ですか?」と確認するのも少し手間

そこで今回も、「エレクトロニクスを簡単に」をテーマとしてボタンを押すだけで現在の状態を切り替え、日本語でOLEDに表示するデスクステータス表示器を作ってみます。

表示する状態は、次の5つです。

・対応可能
・軽い相談OK
・作業中(集中)
・会議中
・離席中

ベースに使うArduino Uno R4 WiFiは、Renesas RA4M1(48 MHz、32 kB SRAM、256 kB Flash) を搭載し、さらに ESP32-S3 による Wi‑Fi / Bluetooth も利用できます。まずはローカル表示だけで完結させつつ、あとからWeb表示や通知に拡張しやすい構成です。

ローカル表示の基本構成

今回の構成はとてもシンプルです。 
OLED表示器 + ボタン1個 + Arduino Uno R4 WiFi だけで動きます。

使用部品

Arduino Uno R4 WiFi
・I2C接続 OLEDディスプレイ(SSD1306系 128×64 を想定)
・タクトスイッチ 1個
・ブレッドボード
・ジャンパーワイヤ

この工作で解決したい困りごと

・話しかけてよいタイミングが分からない
・集中中や会議中に割り込みが入る
・離席中かどうかを見える化したい
・デスクに小さくて分かりやすい状態表示が欲しい

画面仕様と操作ルール

今回は、ボタンの短押しで状態を順番に切り替える方式にします。 
さらに、長押しで「対応可能」に戻すようにすると運用しやすくなります。

表示する状態一覧

状態

OLED表示

意味

対応可能

対応可能

いつでも声かけOK

軽い相談OK

軽い相談OK

短い相談ならOK

作業中(集中)

集中中

できれば後で対応したい

会議中

会議中

すぐの対応は難しい

離席中

り席中

席を外している

※「り席中」の表記について:離席中の「離」など、一部の漢字がフォント側で表示されないため、ひらがな表示しています。

ボタン操作

短押し: 次の状態へ切り替え
長押し(約1.5秒): 対応可能 に戻す

OLEDに日本語を表示したいので、今回はU8g2ライブラリを使います。 
U8g2 はモノクロOLED向けの定番ライブラリで、日本語フォントや日本語表示サンプルも公開されています。

開発環境と実装のポイント

開発は PlatformIO を使います。 
Arduino Uno R4 WiFiの PlatformIO でのボードIDは uno_r4_wifiです。 
最小構成の platformio.ini ではplatform = renesas-raboard = uno_r4_wififramework = arduino を設定すればOKです。

実装上のポイント

・ボタンは INPUT_PULLUPを使い、外部プルアップ抵抗なしで構成
・物理ボタンの誤反応を減らすため、デバウンス処理を実装
・OLED は SSD1306 128×64 / I2C接続 を想定
・日本語表示のため、U8g2 の日本語フォントを利用

配線情報

今回は ボタン1個構成 です。 
ボタンは内部プルアップを使うため、片側を D2、もう片側を GNDに接続するだけで動きます。

モジュール

信号

接続先

補足

OLED

VCC

5V

3.3V専用モジュールなら3.3Vを使用

OLED

GND

GND

共通GND

OLED

SDA

SDA

I2C接続

OLED

SCL

SCL

I2C接続

タクトスイッチ

片側

D2

INPUT_PULLUP使用

タクトスイッチ

反対側

GND

押すとLOWになる

実際のプログラム

ボタンを押すたびに、OLEDディスプレイへ表示する内容を書き換えます。
※本プログラムは、生成AIを用いて作成しております。

`main.cpp
#include <Arduino.h>
#include <Wire.h>
#include <U8g2lib.h>

// SSD1306 128x64 I2C OLED
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

const int buttonPin = 2;

enum DeskState {
  AVAILABLE = 0,
  LIGHT_OK,
  FOCUS,
  MEETING,
  AWAY,
  STATE_COUNT
};

DeskState currentState = AVAILABLE;

const char* stateTitle[STATE_COUNT] = {
  "対応可能",
  "軽い相談OK",
  "集中中",
  "会議中",
  "り席中"
};

const char* stateSub[STATE_COUNT] = {
  "いつでもどうぞ",
  "短い相談なら可",
  "あとでどうぞ",
  "会議終わってから",
  "すぐもどります"
};

bool lastReading = HIGH;
bool stableButtonState = HIGH;

unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 40;

unsigned long pressStartTime = 0;
bool longPressTriggered = false;
const unsigned long longPressDuration = 1500;

void drawCenteredUTF8(int y, const char* text) {
  int width = u8g2.getUTF8Width(text);
  int x = (128 - width) / 2;
  if (x < 0) x = 0;
  u8g2.drawUTF8(x, y, text);
}

void drawState(DeskState state) {
  u8g2.clearBuffer();

  // 日本語フォント
  u8g2.setFont(u8g2_font_unifont_t_japanese1);

  // タイトル
  drawCenteredUTF8(14, "デスク状態");
  u8g2.drawHLine(0, 18, 128);

  // 現在状態
  u8g2.drawRFrame(4, 24, 120, 18, 3);
  drawCenteredUTF8(38, stateTitle[state]);

  // 補足
  drawCenteredUTF8(58, stateSub[state]);

  u8g2.sendBuffer();
}

void nextState() {
  currentState = static_cast<DeskState>((currentState + 1) % STATE_COUNT);
  drawState(currentState);

  Serial.print("State changed: ");
  Serial.println(stateTitle[currentState]);
}

void resetState() {
  currentState = AVAILABLE;
  drawState(currentState);

  Serial.println("State reset: 対応可能");
}

void setup() {
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);

  Wire.begin();
  u8g2.begin();

  drawState(currentState);
  Serial.println("Desk status display started");
}

void loop() {
  unsigned long now = millis();
  bool reading = digitalRead(buttonPin);

  if (reading != lastReading) {
    lastDebounceTime = now;
  }

  if ((now - lastDebounceTime) > debounceDelay) {
    if (reading != stableButtonState) {
      stableButtonState = reading;

      if (stableButtonState == LOW) {
        pressStartTime = now;
        longPressTriggered = false;
      } else {
        if (!longPressTriggered) {
          nextState();
        }
      }
    }
  }

  if (stableButtonState == LOW && !longPressTriggered) {
    if (now - pressStartTime >= longPressDuration) {
      resetState();
      longPressTriggered = true;
    }
  }

  lastReading = reading;
}
```
```platformio.ini
[env:uno_r4_wifi]
platform = renesas-ra
board = uno_r4_wifi
framework = arduino
monitor_speed = 115200
lib_deps =
    olikraus/U8g2

プログラムのポイント

1. ボタン1個で5状態を順送り

短押しごとに、以下の順で状態が切り替わります。

text

対応可能
-> 軽い相談OK
-> 集中中
-> 会議中
-> り席中
-> 対応可能

机の上でワンアクションで切り替えられるので、操作が簡単です。

2. 長押しで即座に「対応可能」へ戻せる

会議や集中作業が終わったあと、 
長押し1回で 対応可能 に戻せるようにしてあります。

3. チャタリング対策を入れている

物理ボタンは押した瞬間に信号が細かく揺れることがあります。 
この誤反応を防ぐために、debounceDelay を使ってデバウンス処理を入れています。

4. OLED表示は日本語

今回は OLEDを日本語表示にすることがポイントなので、U8g2 の日本語フォント u8g2_font_unifont_t_japanese1 を使っています。 
このため、画面上に 対応可能会議中 をそのまま表示できます。

OLEDディスプレイ前のボタンを押すたびに画面表示が切り替わります。

発展編:MQTTとWebダッシュボードによるリモート確認

Arduino Uno R4 WiFiには ESP32-S3 による Wi‑Fi / Bluetooth があるため、ローカル表示だけでなく、現在の状態をネットワーク越しに共有することもできます。 [Source]

たとえば、ボタンで状態を変えたときに MQTT へ次のような情報を送信すれば、離れた席や別室からでも確認できます。

json
{
  "desk": "A-12",
  "status": "集中中",
  "updated_at": "2026-06-09T09:30:00+09:00"
}

こうすると何がうれしいか

・チームメンバーが離れた席からでも状態を確認できる
・会議中や離席中をWeb上でも共有できる
・履歴を残して、状態変化の傾向を見える化できる
・在宅 / 出社が混在する環境でも使いやすい

具体的な発展先

・Node-RED で簡易ダッシュボード化
・社内ステータスページに表示
・Slack / Teams 通知と連携
・複数人分を一覧表示

今後の展望(改善案)

1. ボタンを2個にして操作性を上げる: 
 ・ 次へ
 ・ 確定
の2ボタン構成にすると、状態選択がより分かりやすくなります。

2. 状態ごとに自動復帰を入れる
たとえば、
会議中 は 60 分経過で確認表示
離席中 は 15 分後に点滅
集中中 は 90 分後に休憩リマインド
のような運用ができます。

3. LEDと組み合わせる
OLEDだけでも十分ですが、状態に応じて
・ 緑:対応可能
・ 黄:軽い相談OK
・ 赤:集中中 / 会議中
のようにすると、遠目でも分かりやすくなります。

4. 状態を不揮発保存する
電源を入れ直しても前回の状態を復元できるようにすると、実用品としてさらに使いやすくなります。

5. スケジュール連携や自動切り替え
会議予定や作業時間に応じて自動で状態を変える仕組みを入れると、より業務改善ツールらしくなります。

関連技術・参考トピック

Arduino Uno R4 WiFi

・Renesas RA4M1(48 MHz)
・32 kB SRAM
・256 kB Flash
・Wi‑Fi / Bluetooth 用 ESP32-S3 搭載
・5V系で扱いやすいUNOフォームファクタ 

PlatformIO

・ボードIDは uno_r4_wifi
・platform = renesas-ra
Arduino framework を利用可能

U8g2

・モノクロOLED / LCD向けの定番ライブラリ
・SSD1306 に対応
・多くのフォントを含み、日本語サンプルもある 

Wi-Fi 6 / Bluetooth LE

また、無線という観点では、Renesasは近年 Wi-Fi 6 / Bluetooth LE 対応のRA6シリーズも展開しています。今回の作例でそこまで踏み込んでいるわけではありませんが、IoT機器が「つながること」を前提に設計される流れの中で、より低消費電⼒‧⾼機能な常時接続デバイスへ広げていく⽅向性を考えるうえで参考になります。植物の⾒守りも、1鉢のローカル表⽰から、複数拠点‧複数デバイスの運⽤へと発展していく余地があると感じました。

Wi-Fi 6 / Bluetooth LE対応RA6シリーズ発売 ニュースリリース | Renesas

まとめ

今回は、「いま話しかけていい?」を日本語で見える化する OLED デスクステータス表示器を作ってみました。

ポイントは次の3つです。

ボタン1個で状態を手軽に切り替えられる
OLEDに日本語表示できるので直感的に分かりやすい
・将来的に Wi‑Fi / MQTT / Web ダッシュボードへ拡張しやすい

シンプルな工作ですが、実際の作業環境に置くとかなり便利です。 
「いま声をかけてよいか」をひと目で伝えられるだけで、割り込みストレスを減らしやすくなります。

参考リンク

Arduino Uno R4 WiFi 公式ドキュメント
PlatformIO: Arduino Uno R4 WiFi ボード情報
U8g2 GitHub
U8g2 日本語表示サンプル
Wi-Fi 6 / Bluetooth LE対応RA6シリーズ発売 ニュースリリース | Renes