0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flask-SocketIO で BME280 センサーデータを配信

Last updated at Posted at 2026-01-22

📝 はじめに

Flask + Socket.IO を使って、IoT センサー(BME280)から収集したデータをブラウザにリアルタイム配信する方法を解説します。

対象読者

  • Web 経由で IoT データを可視化したい人
  • REST API のポーリングから WebSocket に移行したい人

前提条件


🎯 背景・動機

IoT センサーデータを Web で表示する場合、REST API を定期的にポーリングする方法が一般的ですが、遅延や無駄な通信が発生します。WebSocket を使うことでサーバーからのプッシュ型配信が可能になり、これらの問題を解決できます。


システム構成

┌─────────────────┐     WebSocket      ┌─────────────────┐
│  SensorClient   │ ────────────────→ │  Flask Server   │
│  (BME280)       │   sense_data       │  (SocketIO)     │
└─────────────────┘                    └────────┬────────┘
                                                │ broadcast
                                                ↓
                                       ┌─────────────────┐
                                       │  Web Browser    │
                                       └─────────────────┘

🛠️ 手順

1. 必要なパッケージ

[tool.poetry.dependencies]
flask = "^3.0.3"
flask-socketio = "^5.3.6"
python-socketio = "^5.11.3"
eventlet = "^0.36.1"

2. Flask-SocketIO サーバーの実装

from flask import Flask, send_from_directory
from flask_socketio import SocketIO, emit
from datetime import datetime

app = Flask(__name__, static_folder="dist", static_url_path="")
socketio = SocketIO(app, async_mode='eventlet')

@app.route('/')
def index():
    return send_from_directory(app.static_folder, "index.html")

@socketio.on('connect')
def ws_connect():
    app.logger.info('クライアントが接続しました')

@socketio.on('sense_data')
def ws_sense_data(sense_data):
    """センサーデータ受信時の処理"""
    sense_data['timestamp'] = str(datetime.now())
    app.logger.debug(f"{sense_data['host']}: {sense_data['temperature']}°C")

socketio.run(app, host="0.0.0.0", port=5010)

eventlet を選んだ理由: 軽量で Flask との相性が良く、monkey patching で既存コード対応が容易。

3. センサークライアントの実装

from socketio import Client
import time
import os

class SensorClient:
    def __init__(self, server_url='http://localhost:5010', interval=10):
        self.server_url = server_url
        self.interval = interval
        self.client = None
        self.hostname = os.getenv('HOSTNAME', 'unknown-host')

    def connect_to_server(self):
        try:
            self.client = Client()
            self.client.connect(self.server_url, retry=True)
            return True
        except Exception as e:
            print(f'接続失敗: {e}')
            return False

    def send_sensor_data(self, data):
        if self.client and self.client.connected:
            data['host'] = self.hostname
            self.client.emit('sense_data', data)
            return True
        return False

    def run(self):
        if not self.connect_to_server():
            return
        try:
            while True:
                data = self.read_sensor_data()
                if data:
                    self.send_sensor_data(data)
                time.sleep(self.interval)
        except KeyboardInterrupt:
            pass
        finally:
            if self.client:
                self.client.disconnect()

🚨 つまずきポイント

接続が切れる問題

長時間接続が維持されない場合は、ping/pong の設定を確認します。

socketio = SocketIO(app, async_mode='eventlet', ping_timeout=60, ping_interval=25)

CORS 設定

開発時にフロントエンドとバックエンドが別ポートで動作する場合:

socketio = SocketIO(app, cors_allowed_origins="*")

📈 まとめ

  • リアルタイム通信で UX が大幅に向上: ポーリング不要で即座にデータ反映
  • Flask-SocketIO の使いやすさ: デコレータベースで直感的に実装可能
  • 双方向通信の可能性: センサー→ブラウザだけでなく、ブラウザ→センサーの制御も可能
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?