| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- """Reading a smart plug's power and state, whatever kind of plug it is."""
- from sqlalchemy.ext.asyncio import AsyncSession
- from backend.app.models.smart_plug import SmartPlug
- from backend.app.services.homeassistant import homeassistant_service
- from backend.app.services.mqtt_relay import mqtt_relay
- from backend.app.services.rest_smart_plug import rest_smart_plug_service
- from backend.app.services.tasmota import tasmota_service
- async def _configured_homeassistant(db: AsyncSession):
- from backend.app.api.routes.settings import get_homeassistant_settings
- ha_settings = await get_homeassistant_settings(db)
- homeassistant_service.configure(ha_settings["ha_url"], ha_settings["ha_token"])
- return homeassistant_service
- async def get_plug_energy(plug: SmartPlug, db: AsyncSession) -> dict | None:
- """Get energy from plug regardless of type (Tasmota, Home Assistant, MQTT, or REST).
- For HA plugs, configures the service with current settings from DB.
- For MQTT plugs, returns data from the subscription service.
- For REST plugs, polls the status URL with JSON path extraction.
- """
- if plug.plug_type == "homeassistant":
- return await (await _configured_homeassistant(db)).get_energy(plug)
- elif plug.plug_type == "mqtt":
- # MQTT plugs report "today" energy, not lifetime total
- # For per-print tracking, we use "today" as the counter (resets at midnight)
- mqtt_data = mqtt_relay.smart_plug_service.get_plug_data(plug.id)
- if mqtt_data:
- return {
- "power": mqtt_data.power,
- "today": mqtt_data.energy,
- "total": mqtt_data.energy, # Use today as total for per-print calculations
- }
- return None
- elif plug.plug_type == "rest":
- return await rest_smart_plug_service.get_energy(plug)
- else:
- return await tasmota_service.get_energy(plug)
- async def read_plug(plug: SmartPlug, db: AsyncSession) -> tuple[str | None, float | None]:
- """The plug's switch state ("ON", "OFF" or None if unknown) and power in watts.
- An unreachable plug reads as (None, None). MQTT plugs answer from the last
- message received, without contacting the device.
- """
- if plug.plug_type == "mqtt":
- data = mqtt_relay.smart_plug_service.get_plug_data(plug.id)
- if not data or not mqtt_relay.smart_plug_service.is_reachable(plug.id):
- return None, None
- return data.state, data.power
- if plug.plug_type == "homeassistant":
- service = await _configured_homeassistant(db)
- elif plug.plug_type == "rest":
- service = rest_smart_plug_service
- else:
- service = tasmota_service
- status = await service.get_status(plug)
- if not status.get("reachable"):
- return None, None
- energy = await get_plug_energy(plug, db)
- return status.get("state"), (energy or {}).get("power")
|