odoo_mqtt/iot_bridge/shelly_parser.py
2026-02-10 20:00:27 +01:00

80 lines
2.5 KiB
Python

"""Shelly PM Mini G3 Parser - extracts power data from MQTT messages."""
import json
import logging
from typing import Dict, Optional
from datetime import datetime
logger = logging.getLogger(__name__)
class ShellyParser:
"""Parser for Shelly PM Mini G3 MQTT Messages."""
def parse_message(self, topic: str, payload: dict) -> Optional[Dict]:
"""
Parse Shelly MQTT message.
Args:
topic: MQTT topic
payload: Message payload (already JSON parsed)
Returns:
Dict with parsed data or None
"""
try:
# Only parse status messages
if '/status/pm1:0' in topic:
return self._parse_status_message(topic, payload)
return None
except Exception as e:
logger.debug(f"parse_error topic={topic} error={str(e)}")
return None
def _parse_status_message(self, topic: str, data: dict) -> Optional[Dict]:
"""
Parse Shelly PM status message.
Topic: shaperorigin/status/pm1:0
Payload format:
{
"id": 0,
"voltage": 230.0,
"current": 0.217,
"apower": 50.0,
"freq": 50.0,
"aenergy": {"total": 12345.6},
"temperature": {"tC": 35.2}
}
"""
try:
device_id = self._extract_device_id(topic)
result = {
'message_type': 'status',
'device_id': device_id,
'timestamp': datetime.utcnow().isoformat() + 'Z',
'voltage': data.get('voltage'),
'current': data.get('current'),
'apower': data.get('apower', 0), # Active Power in Watts
'frequency': data.get('freq'),
'total_energy': data.get('aenergy', {}).get('total'),
'temperature': data.get('temperature', {}).get('tC'),
}
logger.debug(f"parsed_status device={device_id} apower={result['apower']}")
return result
except Exception as e:
logger.error(f"status_parse_error error={str(e)}")
return None
def _extract_device_id(self, topic: str) -> str:
"""Extract device ID from topic path."""
# Example: shaperorigin/status/pm1:0 -> shaperorigin
parts = topic.split('/')
if len(parts) > 0:
return parts[0]
return "unknown"