1
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?

Tapo Matter 消費電力定期取得(準備編)

Last updated at Posted at 2026-01-08

📝 はじめに

この記事では、Tapo Matterデバイス(特にP110Mスマートプラグ)の初期設定からPythonでの電力データ取得までを解説します。
Switchbot と並んで手に入りやすい、TapoMatterデバイスについて、
SwitchBotプラグミニ 消費電力定期取得 (準備編) #Python - Qiita
と同等にまとめてみました。

この記事の対象読者

  • Matter対応デバイスの活用に興味がある方
  • スマートホームシステムを構築したい方
  • 電力監視・省エネシステムを導入したい方
  • PythonでのIoT連携を学びたい方

前提条件

  • Tapo P110Mスマートプラグを所有していること
  • 基本的なプログラミング知識(Python)

🎯 背景・動機

なぜTapo Matterなのか?

  1. 業界標準プロトコル: MatterはAmazon、Apple、Google、Samsungなどが共同開発
  2. 相互運用性: 異なるメーカーのデバイスが連携可能
  3. ローカル制御: クラウドに依存しない高速応答
  4. セキュリティ: 最新の暗号化技術を採用

Tapo P110Mの特徴

  • 電力監視機能: リアルタイムで消費電力を測定
  • Matter対応: 業界標準プロトコルで動作
  • 音声制御: Alexa、Google Home、Siriに対応
  • 予算管理: 月間の電気代を自動計算

TP-Link Tapo P110M 製品ページ

🔧 技術的基礎知識

Matterプロトコルの仕組み

Matterは、OSI参照モデルの上位3層(アプリケーション層、セッション層、ネットワーク層)を統一したプロトコルです:

Matterの主要コンポーネント

コンポーネント 役割 説明
コントローラー 制御元 Home Assistant、Apple Home、Google Home等
エンドデバイス 制御対象 スマートプラグ、照明、センサー等
クラスター 機能単位 On/Off、電力測定、温度等の機能グループ
エンドポイント アクセスポイント デバイス内の論理的な接続点

通信方式の比較

プロトコル リアルタイム性 相互運用性 セキュリティ 設定難易度
Matter ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐
Wi-Fi ⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐⭐⭐
Zigbee ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
Bluetooth ⭐⭐ ⭐⭐⭐ ⭐⭐⭐ ⭐⭐

電力データの構造

Tapo P110Mから取得できる電力データ:

{
    "power": 45.2,
    "voltage": 119.8,
    "current": 377,
    "energy_consumption": 0.324,
    "timestamp": "2025-01-07T12:30:00Z"
}

電力測定クラスター(0x0B04)の属性

属性ID 属性名 単位 説明
0x050B ActivePower デシワット 有効電力(÷10でW)
0x0505 RMSVoltage デシボルト 実効電圧(÷10でV)
0x0508 RMSCurrent ミリアンペア 実効電流(÷1000でA)
0x0500 CurrentSummationDelivered ワット時 累積消費電力量

🛠️ 実装手順

Step 1: Tapo P110Mの初期設定

1. ハードウェア接続

# デバイスの準備手順
1. Tapo P110Mを電源コンセントに接続
2. 制御したい家電をP110Mに接続
3. LEDインジケータがオレンジ点滅することを確認

2. Tapoアプリでの設定

# セットアップ手順
1. Tapoアプリをダウンロード・インストール
   - iOS: App Store
   - Android: Google Play Store

2. アカウントを作成・ログイン
   - TP-Link IDを作成(メールアドレス必要)
   - 既存アカウントがあればログイン

3. [+追加] → [スマートプラグ]を選択
   - デバイスカテゴリから「スマートプラグ」を選択
   - P110Mを選択

4. P110MのQRコードをスキャン
   - デバイス本体のQRコードをカメラでスキャン
   - または手動でシリアル番号を入力

5. Wi-Fi(2.4GHz)ネットワークを選択
   - 注意: 5GHz帯は非対応
   - パスワードを入力して接続

6. デバイス名を設定(例:Living Room Plug)
   - わかりやすい名前を付ける
   - 部屋名+用途がおすすめ

3. Matter対応の有効化

# Matterセットアップ
1. Tapoアプリでデバイスを選択
2. 右上の歯車アイコン → 「Matterセットアップ」を選択
3. Matterペアリングコード(11桁の数字)をメモ
4. オプション:ホーム画面に追加コードを保存

セットアップ時の注意点

項目 推奨設定 注意事項
Wi-Fi帯域 2.4GHz 5GHzは非対応
ルーター設定 IPv6有効 Matterに必要
ファイアウォール ポート5540開放 Matter通信用
mDNS 有効 デバイス発見に必要

Step 2: Home Assistantでの統合

前提条件の確認

# Home Assistantの要件
- Home Assistant 2023.1以降
- Matter Server アドオン
- Python Matter Server対応

# 確認コマンド
ha --version

Home Assistant Matter統合の設定

# configuration.yaml
matter:
  # Matterサーバーアドオンが自動的に有効化されます

# デバイス追加後の自動検出
sensor:
  - platform: matter
    name: "Living Room Power"
    device_id: "your_device_id"
    entity_id: "sensor.living_room_power"

手動でのデバイス追加手順

  1. Home Assistant Companionアプリを開く
  2. [設定] > [デバイスとサービス] に移動
  3. [デバイスを追加][Matterデバイスを追加] を選択
  4. 「いいえ、新しいデバイスです」を選択
  5. QRコードをスキャンまたはセットアップコードを手動入力
  6. [Home Assistantに追加] を選択

追加後の確認

# デバイスが正常に追加されると以下のエンティティが作成される
- switch.tapo_p110m_power          # ON/OFF制御
- sensor.tapo_p110m_power          # 消費電力(W)
- sensor.tapo_p110m_voltage        # 電圧(V)
- sensor.tapo_p110m_current        # 電流(A)
- sensor.tapo_p110m_energy_today   # 本日の消費電力量(kWh)

Home Assistant Matter統合公式ドキュメント

Step 3: Pythonでの電力データ取得

Matterコントローラーライブラリのインストール

# 必要なライブラリをインストール
pip install matter-server-client
pip install python-matter-server

# オプション:非同期処理用
pip install asyncio

# 開発時の追加ライブラリ
pip install python-dateutil  # 日時処理
pip install typing-extensions  # 型ヒント拡張

環境構成

プロジェクト構成/
├── tapo_monitor/
│   ├── __init__.py
│   ├── monitor.py       # メイン監視クラス
│   ├── config.py        # 設定管理
│   └── utils.py         # ユーティリティ
├── requirements.txt
└── main.py

Python実装例

import asyncio
from datetime import datetime
from typing import Dict, List, Optional
from matter_server.client import MatterClient
from matter_server.client.model.node_device import MatterNodeDevice


class TapoMatterMonitor:
    """
    Tapo MatterデバイスからPythonで電力データを取得するクラス

    Attributes:
        client: Matterサーバークライアント
        devices: 発見されたデバイスの辞書
    """

    def __init__(self, server_url: str = "ws://localhost:5580/ws"):
        """
        初期化

        Args:
            server_url: Matterサーバーのwebsocket URL
        """
        self.server_url = server_url
        self.client = MatterClient(server_url)
        self.devices: Dict[int, MatterNodeDevice] = {}

    async def connect(self) -> bool:
        """
        Matterサーバーに接続

        Returns:
            接続成功時True、失敗時False
        """
        try:
            await self.client.connect()
            print(f"✅ Matterサーバーに接続しました: {self.server_url}")
            return True
        except Exception as e:
            print(f"❌ 接続エラー: {e}")
            return False

    async def discover_devices(self) -> int:
        """
        デバイスを発見

        Returns:
            発見されたプラグデバイスの数
        """
        try:
            devices = await self.client.get_nodes()

            for device in devices:
                if device.is_online and self._is_plug_device(device):
                    self.devices[device.node_id] = device
                    print(f"🔌 デバイス発見: {device.name} (ID: {device.node_id})")

            return len(self.devices)

        except Exception as e:
            print(f"❌ デバイス発見エラー: {e}")
            return 0

    def _is_plug_device(self, device: MatterNodeDevice) -> bool:
        """
        プラグデバイスかどうか判定

        Args:
            device: Matterデバイス

        Returns:
            プラグデバイスの場合True
        """
        # デバイスタイプIDで判定
        # 0x010A: On/Off Plug-in Unit
        # 0x010B: Dimmable Plug-in Unit
        plug_device_types = [0x010A, 0x010B]
        return device.device_type in plug_device_types

    async def get_power_data(self, device_id: int) -> Optional[Dict]:
        """
        電力データ取得

        Args:
            device_id: デバイスのノードID

        Returns:
            電力データの辞書、取得失敗時None
        """
        if device_id not in self.devices:
            print(f"⚠️ デバイスID {device_id} が見つかりません")
            return None

        device = self.devices[device_id]

        try:
            # 電力データエンドポイントを取得 (一般的にエンドポイント1)
            power_endpoint = device.get_endpoint(1)

            # 電力測定クラスター (0x0B04)
            power_cluster = power_endpoint.get_cluster(0x0B04)

            # 電力データ読み取り
            power = await power_cluster.get_attribute_value(0x050B)      # ActivePower
            voltage = await power_cluster.get_attribute_value(0x0505)    # RMSVoltage
            current = await power_cluster.get_attribute_value(0x0508)    # RMSCurrent
            energy = await power_cluster.get_attribute_value(0x0500)     # CurrentSummationDelivered

            return {
                "power": power / 10.0 if power else 0,           # デシワット→ワット
                "voltage": voltage / 10.0 if voltage else 0,     # デシボルト→ボルト
                "current": current / 1000.0 if current else 0,   # ミリアンペア→アンペア
                "energy": energy / 1000.0 if energy else 0,      # ワット時→キロワット時
                "timestamp": datetime.now().isoformat(),
                "device_id": device_id,
                "device_name": device.name
            }

        except Exception as e:
            print(f"❌ 電力データ取得エラー: {e}")
            return None

    async def get_all_power_data(self) -> List[Dict]:
        """
        全デバイスの電力データ取得

        Returns:
            全デバイスの電力データリスト
        """
        results = []

        for device_id in self.devices:
            data = await self.get_power_data(device_id)
            if data:
                results.append(data)

        return results

    def get_device_list(self) -> List[Dict]:
        """
        登録済みデバイス一覧を取得

        Returns:
            デバイス情報のリスト
        """
        return [
            {
                "device_id": device_id,
                "name": device.name,
                "is_online": device.is_online,
                "device_type": hex(device.device_type)
            }
            for device_id, device in self.devices.items()
        ]

    async def close(self) -> None:
        """接続終了"""
        if self.client:
            await self.client.disconnect()
            print("🔌 接続を終了しました")


# 使用例
async def main():
    """メイン関数"""
    # 監視インスタンス作成
    monitor = TapoMatterMonitor()

    # Matterサーバーに接続
    if not await monitor.connect():
        return

    # デバイス発見
    device_count = await monitor.discover_devices()
    print(f"📊 {device_count}台のデバイスを発見しました")

    if device_count == 0:
        print("デバイスが見つかりませんでした")
        await monitor.close()
        return

    # デバイス一覧表示
    print("\n--- 登録デバイス一覧 ---")
    for device in monitor.get_device_list():
        print(f"  - {device['name']} (ID: {device['device_id']}, Type: {device['device_type']})")

    # 全デバイスの電力データ取得
    print("\n--- 電力データ ---")
    power_data = await monitor.get_all_power_data()

    for data in power_data:
        print(f"📍 {data['device_name']}")
        print(f"   電力: {data['power']:.1f} W")
        print(f"   電圧: {data['voltage']:.1f} V")
        print(f"   電流: {data['current']:.3f} A")
        print(f"   累積: {data['energy']:.3f} kWh")
        print(f"   時刻: {data['timestamp']}")
        print()

    # 接続終了
    await monitor.close()


if __name__ == "__main__":
    asyncio.run(main())

実行結果例

✅ Matterサーバーに接続しました: ws://localhost:5580/ws
🔌 デバイス発見: リビングルーム (ID: 12345)
🔌 デバイス発見: 書斎デスク (ID: 12346)
📊 2台のデバイスを発見しました

--- 登録デバイス一覧 ---
  - リビングルーム (ID: 12345, Type: 0x10a)
  - 書斎デスク (ID: 12346, Type: 0x10a)

--- 電力データ ---
📍 リビングルーム
   電力: 45.2 W
   電圧: 119.8 V
   電流: 0.377 A
   累積: 12.345 kWh
   時刻: 2025-01-08T10:30:00.123456

📍 書斎デスク
   電力: 85.0 W
   電圧: 120.1 V
   電流: 0.708 A
   累積: 8.765 kWh
   時刻: 2025-01-08T10:30:00.234567

🔌 接続を終了しました

🚨 トラブルシューティング

よくある問題と解決策

問題 原因 解決方法
Matterデバイスが見つからない ネットワーク接続不備 Wi-Fi 2.4GHz帯域を確認
ペアリングに失敗する コントローラーの互換性 Home Assistantを最新版に更新
電力データが取得できない エンドポイント指定ミス エンドポイント1を確認
通信が不安定 Threadネットワーク問題 Threadボーダールーターを追加
認証エラー 署名生成ミス タイムスタンプとnonceを確認
接続タイムアウト サーバー未起動 Matterサーバーの状態を確認

デバッグ用コマンド

# Matterサーバーの状態確認
curl -X GET http://localhost:5580/api/nodes

# 特定デバイスの詳細情報取得
curl -X GET http://localhost:5580/api/nodes/12345

# ログの確認
docker logs matter-server

# Home Assistantログ
tail -f /config/home-assistant.log | grep -i matter

# ネットワーク確認
ping <デバイスIP>
nmap -sn 192.168.1.0/24  # ネットワークスキャン

Pythonデバッグ用コード

import asyncio
import logging

# デバッグログ有効化
logging.basicConfig(level=logging.DEBUG)

async def debug_connection():
    """接続デバッグ"""
    monitor = TapoMatterMonitor()

    print("=== 接続テスト ===")
    result = await monitor.connect()
    print(f"接続結果: {result}")

    if result:
        print("\n=== デバイス発見テスト ===")
        count = await monitor.discover_devices()
        print(f"発見数: {count}")

        print("\n=== デバイス詳細 ===")
        for device in monitor.get_device_list():
            print(f"  {device}")

        await monitor.close()

asyncio.run(debug_connection())

📝 まとめ

この記事では、Tapo P110Mの初期設定からPythonでの電力データ取得までを解説しました。

実装した内容

  • ✅ Tapo P110Mの初期設定(Tapoアプリ)
  • ✅ Matter対応の有効化
  • ✅ Home Assistantでの統合
  • ✅ Pythonでの電力データ取得クラス

以上です。

1
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
1
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?