はじめに:Raspberry Pi(ラズパイ)とは?
Raspberry Pi(ラズベリーパイ)とは、内蔵ハードディスクなどを搭載しない代わりに、電源やSDカードストレージを装着することによって使用できる、シングルボードコンピュータと呼ばれるハードウェアです。2012年に教育用として英国のラズベリーパイ財団によって開発されました。
通称「ラズパイ」と呼ばれるこの小さなボードには、たくさんの可能性が詰まっています。主な特徴は以下の通りです。
- Linuxを動かすことのできる超小型PCです。
- OSはmicroSDカードにインストールして使用します。
- 小型・安価ながらグラフィック機能(GPU)も内蔵され、LANポート、HDMI、USBポートなど、接続できるデバイスは一般的なPCと変わりません。(今回使用するRaspberry Pi 3 Model BはWi-Fi接続、Bluetoothにも対応しています)
- GPIO(General Purpose Input/Output: 汎用入出力)ピンが搭載されており、センサーや回路を接続して電子工作が可能です。
- Linuxで動作するため、ApacheやPHPなどをインストールして、電力消費の少ない常時起動のホームサーバーとして利用できます。
- GPIOを活用し、ホームキットなどのIoT(モノのインターネット)分野で広く活用されています。
(参考記事: ラズベリーパイで何ができる?初心者にやさしい活用法12選 | Workship MAGAZINE)
この記事の目的:オフィスのトイレ空き状況をSlackで確認したい
さて、今回このラズパイを使って解決したい問題は、オフィスの「トイレ空き状況」問題です。
私たちのオフィスにはトイレが1つしかなく、各社員は利用のたびにトイレまで出向き、空き状況を調べています。しかし、行ってみたら空いていなかった、ということが頻繁に発生していました。
この「無駄足」をなくすため、自席のPCからトイレの空き状況を確認できる仕組みを開発します。
具体的なアプローチは以下の通りです。
- 洗面所にRaspberry Pi(ラズパイ)を設置します。
- 光センサーを接続し、トイレの「使用・未使用」を判定します。
- 電気がついている → 使用中
- 電気がついていない → 未使用
- Raspberry Pi 3は標準でWi-Fiが使用可能なため、社内ネットワークに無線で接続します。
- 取得した情報をSlackに通知し、PC上からステータスとして確認できるようにします。
準備するもの(ハードウェアと費用)
今回の開発で必要になった機材は以下の通りです。
- PC(セットアップ用)
- Raspberry Pi 3 Model B+
- microSDカード (8GB以上推奨)
- micro USBケーブル
- USB ACアダプタ (2.4A推奨。ラズパイ専用品が安心です)
- 光センサー (BH1750)
- ジャンピングワイヤー / ブレッドボード

今回は、これらを準備しました。
最低限必要なもの(本体セット + SD16GB + ACアダプタ)で約10,000円、光センサーやワイヤー類で約2,000円、合計12,000円ほどでした。センサー類を含めると、思ったより費用がかかる印象かもしれません。
ステップ1:ラズパイのOSをセットアップ
まずはラズパイを起動させるため、OSをインストールします。
(今回の最終目的とは少し離れますが、学習も兼ねて一度GUIで起動してみます)
PCでRaspbian(現在はRaspberry Pi OS)というLinuxベースの専用OSをダウンロードします。

SDカードをフォーマットし、このOSイメージを書き込みます。
(参考記事: Raspberry Pi 3 Model B+ に Raspbian Stretch Lite をクリーンインストールする手順 – Qiita)
microSDカードをラズパイに挿入し、HDMIケーブルと電源を繋ぐと、あっという間に起動できます。

今回は色々入っているイメージをインストールしたため、初めからマインクラフトやOffice代替ソフトなどが入っていました。OSがSDカード駆動でも、意外とサクサク動くことに驚きます。
これで動作確認は完了です。
ステップ2:MacからSSHでラズパイにリモート接続
今回はGUI(デスクトップ画面)で操作することはしません。最終的にラズパイは電源だけを接続した「ヘッドレス」状態で運用するため、MacのターミナルからSSH接続で設定を進めます。普段の仮想サーバー(Vagrantなど)や社内サーバーの設定と特に変わりありません。
(参考記事: MacからRaspberry Pi 3にSSH接続(Wi-Fi) – Qiita)

手順の概要は以下の通りです。
ラズパイ側の設定
- SSH接続を許可します。
- 無線LAN(Wi-Fi)を接続してIPアドレスを確認します。
- IPアドレスが変更されないよう、固定化します(設定ファイルを編集)。
Mac側の設定
- ラズパイのIPアドレスへ、社内LAN経由でSSH接続します。
- 接続を簡単にするため、公開鍵認証を設定します。

無線LAN経由でSSH接続が完了しました。
(今回は使用しませんが、VNC(リモートデスクトップ)も設定しておくと、いざという時にGUI操作ができて便利です)
これで、ラズパイに接続していたモニターやキーボードをすべて外しても問題ありません。ここからはリモート操作で進めていきます。
ステップ3:光センサー(BH1750)を接続しI2Cで制御
Raspberry Pi にあるGPIO(汎用入出力ピン)にジャンピングワイヤーを繋ぎ、ブレッドボード経由で光センサーBH1750を接続します。
(参考記事: Raspberry Pi + BH1750 (I2C接続の照度センサ) – Qiita)
ラズパイ側でI2Cモジュールが使用できるよう設定を行います。
接続後、I2Cデバイスのアドレスを確認します。
$ sudo i2cdetect -y 1

アドレス(この場合は 23)が確認できました。
一旦、動作確認のためにシェルスクリプトを作成して実行してみます。
bh1750_sample.sh

![]()
無事に照度の値を取得できました。
ステップ4:PythonでSlackに通知する仕組みを構築
Pythonを使う理由
Raspberry Piでの開発はPythonで行う人が多いようです。必須ではありませんが、センサー用のモジュールがPythonで提供されていることが多いため、今回は勉強も兼ねてPythonで書いていきます。
まず、I2Cをツールで使えるようにします。
$ apt-get install i2c-tools
※I2C通信とは
I2C(Inter-Integrated Circuit)は、シリアル通信の方式の一つです。
(要約)
・電源・グランドを除き、わずか2線のみで利用可能
・シリアル通信
・通信内容にアドレス情報、確認信号を持つ
・マスタ(今回はRaspberry Pi)、スレーブ(今回は光センサー)の関係で動作する
(参考記事: I2C通信について – Qiita)
PythonでI2Cバスをコントロールするためのライブラリ「Python-smbus」をインストールします。
smbusモジュールの設定
$ sudo apt-get install python3-smbus
$ pip3 install smbus
サンプルコードでテスト
Pythonで照度を取得する簡単なコードを書いてみます。
import smbus
def get_lux():
bus = smbus.SMBus(1)
addr = 0x23
lux = bus.read_i2c_block_data(addr, 0x10)
return (lux[0]*256+lux[1])/1.2
if __name__ == '__main__':
print(get_lux())
→このテストで、暗いときは100未満、蛍光灯レベルでは200以上の値が出ることがわかりました。しきい値は「100」に設定するのが良さそうです。
Slackへの通知
Slackで使用できる公式API “Bots” をPythonから簡単に使うためのモジュールslackbotをインストールします。
$ pip3 install slackbot
ファイル構成は以下のようにします。
.
├── run.py # 実際に実行するスクリプト (後で作成)
├── plugins # 話しかけられた際の応答処理を格納するディレクトリ
│ ├── __init__.py
│ └── toilet.py # 会話の応答処理を定義するスクリプト
└── slackbot_settings.py # Botの設定ファイル
Slack Tokenの取得
Botを作成するため、対象のワークスペースにログインし、Slack側でBotを登録してトークン(xoxb-から始まる文字列)を取得します。

取得したトークンを slackbot_settings.py に設定します。
# botアカウントのトークンを指定
API_TOKEN = '取得したトークンをここに記述'
Botによる会話
slackbotライブラリは、話しかけられた際の応答を plugins 配下のスクリプトで定義します。
以下を plugins/toilet.py として配置します。
# coding: utf-8
import smbus
from slackbot.bot import respond_to # @botname: で反応するデコーダ
from slackbot.bot import default_reply # 該当する応答がない場合に反応するデコーダ
def get_lux():
bus = smbus.SMBus(1)
addr = 0x23
lux = bus.read_i2c_block_data(addr,0x10)
return (lux[0]*256+lux[1])/1.2
# 「といれ」と話しかけられたときの応答
@respond_to('といれ|toilet|トイレ')
def check_toilet(message):
lux = get_lux()
message.reply('現在の明るさ: {}'.format(round(lux)))
if lux > 100:
message.reply('使用中だよ')
else:
message.reply('空いてるよ')
# いずれのルールにも該当しない場合の応答
@default_reply
def default_func(message):
message.reply('「といれ」「トイレ」「toilet」のどれかで話しかけてね')
この時点でBotを起動し、Slackから「トイレ」とメンションを送ると、照度と空き状況を返してくれます。

Botの在籍状況(ステータス)の設定
このままでも動作しますが、毎回「トイレ」と入力するのは面倒です。そこで、Botのステータスアイコンで空き状況を判別できるように改良します。
- トイレ使用中 → トイレbot ログイン中(緑丸)
- トイレ未使用 → トイレbot 離席中(グレー丸)
今回利用している slackbot ライブラリには、Botアカウントの在籍・離席といったステータスを設定する機能がありません。そのため、SlackのWEB APIである users.setPresence を直接利用します。
また、定期実行の機能もないため、スレッド(threading)を使って照度を定期的にチェックするロジックも追加します。
run.py (これがメインの実行ファイルです)
#!/usr/bin/env python3
# coding: utf-8
import time
import datetime
import threading
import requests
from slackbot.bot import Bot
# slackbot_settings.py からトークンを読み込む
from slackbot_settings import API_TOKEN
# plugins/toilet.py から照度取得関数を読み込んでおく
from plugins.toilet import get_lux
API_URL = 'https://slack.com/api/users.setPresence?token={token}&presence={status}'
LIGHT_THRESHOLD = 100 # 照度のしきい値
def set_away():
""" Botのステータスを離席にする """
res = requests.get(API_URL.format(token=API_TOKEN, status='away'))
print(res.content)
def set_active():
""" Botのステータスを在籍にする """
res = requests.get(API_URL.format(token=API_TOKEN, status='auto'))
print(res.content)
def check_lux():
"""
Threadで定期的に明るさをチェックして
しきい値を基にステータスを変更する
"""
is_using = False # 現在の使用状況
# 初期化(起動時は「離席」にする)
set_away()
while True:
lux = get_lux()
print(datetime.datetime.now(), lux)
# ステータスが変化したら通知する
# (未使用) で (明るくなった) -> 利用開始
if lux > LIGHT_THRESHOLD and not is_using:
is_using = True
print('ON: トイレ使用開始')
set_active()
# (使用中) で (暗くなった) -> 利用終了
elif lux <= LIGHT_THRESHOLD and is_using:
is_using = False
print('OFF: トイレ利用終了')
set_away()
# 3秒ごとにチェック
time.sleep(3)
def main():
bot = Bot()
# 照度監視用のスレッドを起動する
th_me = threading.Thread(target=check_lux, name="th_check_lux")
th_me.setDaemon(True)
th_me.start()
try:
# bot(メンション応答機能)を起動する
bot.run()
except Exception as e:
print(e)
if __name__ == "__main__":
print('start slackbot')
main()
これで、以下のコマンドでBotを起動すれば、照度の監視が開始されます。
pi@raspberrypi:~/work/script/iot_toilet $ python3 run.py
start slackbot
b'{"ok":true}'
2019-01-21 14:35:29.918734 0.0
2019-01-21 14:35:32.927363 0.0
2019-01-21 14:35:35.936223 0.0
...
完成:Slack Botの動作確認
これで、一通りの設定が完了しました。
Slackのユーザー一覧を見ると、トイレ(電気)が消えている時はBotが「離席中」になっています。

トイレの電気がつくと(使用中になると)、Botが「在籍中」に変わります。

これで、自席からトイレの空き状況が一目でわかるようになりました。
(今回の主な参考サイト: Raspberry Pi + Python + Slack Bot でトイレの空き状況を可視化する – Denzow System)
まとめと今後の展望
今回はRaspberry Piと光センサー、Pythonを使って、オフィスのトイレ空き状況をSlackで可視化する仕組みを構築しました。電子工作とWeb APIの連携は相性が良く、意外と簡単に実装できました。
今後の展望としては、Slack Botを使う代わりに、Raspberry Pi自体を「POSTリクエストを投げるとJSON(空き状況)を返却してくれる簡易サーバー」にして、Chromeの拡張機能ボタンでステータスを確認できると、より多くの人が手軽に使えるようになって便利だと考えています。
最後までお読みいただき、ありがとうございました。
よくある質問(FAQ)
- Q1. 光センサーを使っていますが、誰かが電気を消し忘れたらどうなりますか?
- A1. ご指摘の通り、この仕組みでは「電気がついている=使用中」と判定するため、消し忘れには対応できません。あくまで簡易的な実験(PoC)として安価な光センサーを採用しました。より正確性を高めるなら、人の動きを検知する「人感センサー(PIR)」や、対象物までの距離を測る「超音波センサー」などを組み合わせるのが良いでしょう。(※ドアの開閉センサーだけでは、無人の「閉め切り」を区別できないため注意が必要です)
- Q2. Raspberry Piを持っていないのですが、もっと簡単な方法はありますか?
- A2. 「自作」にこだわらなければ、市販のIoT製品が最も簡単です。例えば「SwitchBot」の人感センサーなどを使い、IFTTTなどの連携サービスを経由してスマホやSlackに通知を送ることで、ハードウェアの知識がなくても同様の仕組みを実現できます。
- Q3. この仕組みを自宅のトイレで使えますか?
- A3. はい、ご自宅でも応用可能です。今回のスクリプトをそのまま動かし、ご自身のプライベートなSlackワークスペースに通知する設定にすれば使えます。また、、工夫次第でスマートスピーカー(Google Home/Alexa)に喋らせたりすることも可能です。