Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion homeassistant/components/tasmota/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
unique_id_from_hash,
)

import homeassistant.components.sensor as sensor
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity_registry import async_entries_for_device
from homeassistant.helpers.typing import HomeAssistantType

from .const import DOMAIN
Expand Down Expand Up @@ -117,8 +119,38 @@ async def async_device_discovered(payload, mac):
for (tasmota_entity_config, discovery_hash) in tasmota_entities:
await _discover_entity(tasmota_entity_config, discovery_hash, platform)

async def async_sensors_discovered(sensors, mac):
"""Handle discovery of (additional) sensors."""
platform = sensor.DOMAIN
await _load_platform(platform)

device_registry = await hass.helpers.device_registry.async_get_registry()
entity_registry = await hass.helpers.entity_registry.async_get_registry()
device = device_registry.async_get_device(set(), {("mac", mac)})

if device is None:
_LOGGER.warning("Got sensors for unknown device mac: %s", mac)
return

orphaned_entities = {
entry.unique_id
for entry in async_entries_for_device(entity_registry, device.id)
if entry.domain == sensor.DOMAIN and entry.platform == DOMAIN
}
for (tasmota_sensor_config, discovery_hash) in sensors:
if tasmota_sensor_config:
orphaned_entities.discard(tasmota_sensor_config.unique_id)
await _discover_entity(tasmota_sensor_config, discovery_hash, platform)
for unique_id in orphaned_entities:
entity_id = entity_registry.async_get_entity_id(platform, DOMAIN, unique_id)
if entity_id:
_LOGGER.debug("Removing entity: %s %s", platform, entity_id)
entity_registry.async_remove(entity_id)

hass.data[DATA_CONFIG_ENTRY_LOCK] = asyncio.Lock()
hass.data[CONFIG_ENTRY_IS_SETUP] = set()

tasmota_discovery = TasmotaDiscovery(discovery_topic, tasmota_mqtt)
await tasmota_discovery.start_discovery(async_device_discovered, None)
await tasmota_discovery.start_discovery(
async_device_discovered, async_sensors_discovered
)
2 changes: 1 addition & 1 deletion homeassistant/components/tasmota/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Tasmota (beta)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/tasmota",
"requirements": ["hatasmota==0.0.10"],
"requirements": ["hatasmota==0.0.11"],
"dependencies": ["mqtt"],
"mqtt": ["tasmota/discovery/#"],
"codeowners": ["@emontnemery"]
Expand Down
161 changes: 161 additions & 0 deletions homeassistant/components/tasmota/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
"""Support for Tasmota sensors."""
import logging
from typing import Optional

from hatasmota.const import (
SENSOR_AMBIENT,
SENSOR_APPARENT_POWERUSAGE,
SENSOR_BATTERY,
SENSOR_CCT,
SENSOR_CO2,
SENSOR_COLOR_BLUE,
SENSOR_COLOR_GREEN,
SENSOR_COLOR_RED,
SENSOR_CURRENT,
SENSOR_DEWPOINT,
SENSOR_DISTANCE,
SENSOR_ECO2,
SENSOR_FREQUENCY,
SENSOR_HUMIDITY,
SENSOR_ILLUMINANCE,
SENSOR_MOISTURE,
SENSOR_PB0_3,
SENSOR_PB0_5,
SENSOR_PB1,
SENSOR_PB2_5,
SENSOR_PB5,
SENSOR_PB10,
SENSOR_PM1,
SENSOR_PM2_5,
SENSOR_PM10,
SENSOR_POWERFACTOR,
SENSOR_POWERUSAGE,
SENSOR_PRESSURE,
SENSOR_PRESSUREATSEALEVEL,
SENSOR_PROXIMITY,
SENSOR_REACTIVE_POWERUSAGE,
SENSOR_TEMPERATURE,
SENSOR_TODAY,
SENSOR_TOTAL,
SENSOR_TOTAL_START_TIME,
SENSOR_TVOC,
SENSOR_VOLTAGE,
SENSOR_WEIGHT,
SENSOR_YESTERDAY,
)

from homeassistant.components import sensor
from homeassistant.const import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_ILLUMINANCE,
DEVICE_CLASS_POWER,
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_TEMPERATURE,
)
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import Entity

from .const import DOMAIN as TASMOTA_DOMAIN
from .discovery import TASMOTA_DISCOVERY_ENTITY_NEW
from .mixins import TasmotaAvailability, TasmotaDiscoveryUpdate

_LOGGER = logging.getLogger(__name__)

SENSOR_DEVICE_CLASS_MAP = {
SENSOR_AMBIENT: DEVICE_CLASS_ILLUMINANCE,
SENSOR_APPARENT_POWERUSAGE: DEVICE_CLASS_POWER,
Comment thread
emontnemery marked this conversation as resolved.
SENSOR_BATTERY: DEVICE_CLASS_BATTERY,
SENSOR_HUMIDITY: DEVICE_CLASS_HUMIDITY,
SENSOR_ILLUMINANCE: DEVICE_CLASS_ILLUMINANCE,
SENSOR_POWERUSAGE: DEVICE_CLASS_POWER,
SENSOR_PRESSURE: DEVICE_CLASS_PRESSURE,
SENSOR_PRESSUREATSEALEVEL: DEVICE_CLASS_PRESSURE,
SENSOR_REACTIVE_POWERUSAGE: DEVICE_CLASS_POWER,
SENSOR_TEMPERATURE: DEVICE_CLASS_TEMPERATURE,
SENSOR_TODAY: DEVICE_CLASS_POWER,
SENSOR_TOTAL: DEVICE_CLASS_POWER,
SENSOR_YESTERDAY: DEVICE_CLASS_POWER,
}

SENSOR_ICON_MAP = {
SENSOR_CCT: "mdi:temperature-kelvin",
SENSOR_CO2: "mdi:molecule-co2",
SENSOR_COLOR_BLUE: "mdi:palette",
SENSOR_COLOR_GREEN: "mdi:palette",
SENSOR_COLOR_RED: "mdi:palette",
SENSOR_CURRENT: "mdi:alpha-a-circle-outline",
SENSOR_DEWPOINT: "mdi:weather-rainy",
SENSOR_DISTANCE: "mdi:leak",
SENSOR_ECO2: "mdi:molecule-co2",
SENSOR_FREQUENCY: "mdi:current-ac",
SENSOR_MOISTURE: "mdi:cup-water",
SENSOR_PB0_3: "mdi:flask",
SENSOR_PB0_5: "mdi:flask",
SENSOR_PB10: "mdi:flask",
SENSOR_PB1: "mdi:flask",
SENSOR_PB2_5: "mdi:flask",
SENSOR_PB5: "mdi:flask",
SENSOR_PM10: "mdi:air-filter",
SENSOR_PM1: "mdi:air-filter",
SENSOR_PM2_5: "mdi:air-filter",
SENSOR_POWERFACTOR: "mdi:alpha-f-circle-outline",
SENSOR_PROXIMITY: "mdi:ruler",
SENSOR_TOTAL_START_TIME: "mdi:progress-clock",
SENSOR_TVOC: "mdi:air-filter",
SENSOR_VOLTAGE: "mdi:alpha-v-circle-outline",
SENSOR_WEIGHT: "mdi:scale",
}


async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up Tasmota sensor dynamically through discovery."""

async def async_discover_sensor(tasmota_entity, discovery_hash):
"""Discover and add a Tasmota sensor."""
async_add_entities(
[
TasmotaSensor(
tasmota_entity=tasmota_entity, discovery_hash=discovery_hash
)
]
)

async_dispatcher_connect(
hass,
TASMOTA_DISCOVERY_ENTITY_NEW.format(sensor.DOMAIN, TASMOTA_DOMAIN),
async_discover_sensor,
)


class TasmotaSensor(TasmotaAvailability, TasmotaDiscoveryUpdate, Entity):
"""Representation of a Tasmota sensor."""

def __init__(self, **kwds):
"""Initialize the Tasmota sensor."""
self._state = False

super().__init__(
discovery_update=self.discovery_update,
**kwds,
)

@property
def device_class(self) -> Optional[str]:
"""Return the device class of the sensor."""
return SENSOR_DEVICE_CLASS_MAP.get(self._tasmota_entity.quantity)

@property
def icon(self):
"""Return the icon."""
return SENSOR_ICON_MAP.get(self._tasmota_entity.quantity)
Comment thread
MartinHjelmare marked this conversation as resolved.

@property
def state(self):
"""Return the state of the entity."""
return self._state

@property
def unit_of_measurement(self):
"""Return the unit this state is expressed in."""
return self._tasmota_entity.unit
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ hass-nabucasa==0.37.0
hass_splunk==0.1.1

# homeassistant.components.tasmota
hatasmota==0.0.10
hatasmota==0.0.11

# homeassistant.components.jewish_calendar
hdate==0.9.5
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ hangups==0.4.11
hass-nabucasa==0.37.0

# homeassistant.components.tasmota
hatasmota==0.0.10
hatasmota==0.0.11

# homeassistant.components.jewish_calendar
hdate==0.9.5
Expand Down
Loading