1
0
mirror of https://github.com/home-assistant/core.git synced 2025-08-11 14:29:58 +00:00
Files
.github
docs
homeassistant
auth
components
ads
alarm_control_panel
alexa
auth
automation
axis
binary_sensor
blink
bmw_connected_drive
calendar
camera
cast
climate
cloud
config
conversation
counter
cover
deconz
device_tracker
dialogflow
elkm1
emulated_hue
fan
frontend
geo_location
geofency
google_assistant
group
habitica
hangouts
hassio
homekit
homekit_controller
homematic
homematicip_cloud
http
hue
ifttt
ihc
image_processing
insteon
ios
lifx
light
lock
lovelace
luftdaten
mailbox
mailgun
media_player
mqtt
mysensors
nest
notify
onboarding
opentherm_gw
openuv
owntracks
persistent_notification
point
rainmachine
recorder
remember_the_milk
remote
scene
sensor
.translations
__init__.py
abode.py
ads.py
airvisual.py
alarmdecoder.py
alpha_vantage.py
amcrest.py
android_ip_webcam.py
apcupsd.py
api_streams.py
aqualogic.py
arduino.py
arest.py
arlo.py
arwn.py
asuswrt.py
awair.py
bbox.py
bh1750.py
bitcoin.py
blink.py
blockchain.py
bloomsky.py
bme280.py
bme680.py
bmw_connected_drive.py
bom.py
broadlink.py
buienradar.py
canary.py
cert_expiry.py
citybikes.py
coinbase.py
coinmarketcap.py
comed_hourly_pricing.py
comfoconnect.py
command_line.py
cpuspeed.py
crimereports.py
cups.py
currencylayer.py
daikin.py
darksky.py
deconz.py
deluge.py
demo.py
deutsche_bahn.py
dht.py
discogs.py
dnsip.py
dovado.py
dsmr.py
dte_energy_bridge.py
dublin_bus_transport.py
duke_energy.py
dwd_weather_warnings.py
dweet.py
dyson.py
ebox.py
ecobee.py
eddystone_temperature.py
edp_redy.py
efergy.py
eight_sleep.py
eliqonline.py
elkm1.py
emoncms.py
enocean.py
enphase_envoy.py
entur_public_transport.py
envirophat.py
envisalink.py
etherscan.py
fail2ban.py
fastdotcom.py
fedex.py
fibaro.py
fido.py
file.py
filesize.py
filter.py
fints.py
fitbit.py
fixer.py
flunearyou.py
folder.py
foobot.py
fritzbox_callmonitor.py
fritzbox_netmonitor.py
gearbest.py
geizhals.py
geo_rss_events.py
gitlab_ci.py
gitter.py
glances.py
google_travel_time.py
google_wifi.py
gpsd.py
greeneye_monitor.py
gtfs.py
habitica.py
haveibeenpwned.py
hddtemp.py
history_stats.py
hive.py
homematic.py
homematicip_cloud.py
hp_ilo.py
htu21d.py
huawei_lte.py
hydrawise.py
hydroquebec.py
ihc.py
imap.py
imap_email_content.py
influxdb.py
insteon.py
ios.py
iota.py
iperf3.py
irish_rail_transport.py
isy994.py
jewish_calendar.py
juicenet.py
kira.py
knx.py
kwb.py
lacrosse.py
lastfm.py
launch_library.py
linky.py
linux_battery.py
logi_circle.py
london_air.py
london_underground.py
loopenergy.py
luftdaten.py
lyft.py
magicseaweed.py
meteo_france.py
metoffice.py
mfi.py
mhz19.py
miflora.py
min_max.py
mitemp_bt.py
modbus.py
modem_callerid.py
mold_indicator.py
moon.py
mopar.py
mqtt.py
mqtt_room.py
mvglive.py
mychevy.py
mysensors.py
nederlandse_spoorwegen.py
nest.py
netatmo.py
netatmo_public.py
netdata.py
netgear_lte.py
neurio_energy.py
noaa_tides.py
nsw_fuel_station.py
nut.py
nzbget.py
octoprint.py
ohmconnect.py
onewire.py
openevse.py
openexchangerates.py
openhardwaremonitor.py
opensky.py
opentherm_gw.py
openuv.py
openweathermap.py
otp.py
pi_hole.py
pilight.py
plex.py
pocketcasts.py
point.py
pollen.py
postnl.py
pushbullet.py
pvoutput.py
pyload.py
qbittorrent.py
qnap.py
qwikswitch.py
radarr.py
rainbird.py
raincloud.py
rainmachine.py
random.py
rest.py
rflink.py
rfxtrx.py
ring.py
ripple.py
rmvtransport.py
rtorrent.py
ruter.py
sabnzbd.py
scrape.py
season.py
sense.py
sensehat.py
serial.py
serial_pm.py
seventeentrack.py
shodan.py
sht31.py
sigfox.py
simulated.py
skybeacon.py
skybell.py
sleepiq.py
sma.py
smappee.py
snmp.py
sochain.py
socialblade.py
sonarr.py
speedtest.py
spotcrime.py
sql.py
srp_energy.py
starlingbank.py
startca.py
statistics.py
steam_online.py
strings.moon.json
strings.season.json
supervisord.py
swiss_hydrological_data.py
swiss_public_transport.py
syncthru.py
synologydsm.py
systemmonitor.py
sytadin.py
tado.py
tahoma.py
tank_utility.py
tautulli.py
tcp.py
ted5000.py
teksavvy.py
tellduslive.py
tellstick.py
temper.py
template.py
tesla.py
thermoworks_smoke.py
thethingsnetwork.py
thinkingcleaner.py
tibber.py
time_date.py
toon.py
torque.py
tradfri.py
trafikverket_weatherstation.py
transmission.py
transport_nsw.py
travisci.py
twitch.py
uber.py
uk_transport.py
upnp.py
ups.py
uptime.py
uscis.py
usps.py
vasttrafik.py
velbus.py
vera.py
verisure.py
version.py
viaggiatreno.py
volkszaehler.py
volvooncall.py
vultr.py
waqi.py
waterfurnace.py
waze_travel_time.py
whois.py
wink.py
wirelesstag.py
worldclock.py
worldtidesinfo.py
worxlandroid.py
wsdot.py
wunderground.py
xbox_live.py
xiaomi_aqara.py
xiaomi_miio.py
yr.py
yweather.py
zabbix.py
zamg.py
zestimate.py
zha.py
zigbee.py
zoneminder.py
zwave.py
simplisafe
smhi
sonos
switch
system_log
telegram_bot
tellduslive
tibber
timer
tradfri
tts
twilio
unifi
upnp
vacuum
water_heater
weather
websocket_api
wink
wunderlist
zha
zone
zoneminder
zwave
__init__.py
abode.py
alarmdecoder.py
alert.py
amcrest.py
android_ip_webcam.py
apcupsd.py
api.py
apple_tv.py
aqualogic.py
arduino.py
arlo.py
asterisk_mbox.py
asuswrt.py
august.py
bbb_gpio.py
bloomsky.py
browser.py
canary.py
cloudflare.py
coinbase.py
comfoconnect.py
configurator.py
daikin.py
datadog.py
demo.py
device_sun_light_trigger.py
digital_ocean.py
discovery.py
dominos.py
doorbird.py
downloader.py
duckdns.py
dweet.py
dyson.py
ecobee.py
ecovacs.py
edp_redy.py
egardia.py
eight_sleep.py
emoncms_history.py
enocean.py
envisalink.py
eufy.py
evohome.py
feedreader.py
ffmpeg.py
fibaro.py
folder_watcher.py
foursquare.py
freedns.py
fritzbox.py
gc100.py
goalfeed.py
google.py
google_domains.py
graphite.py
greeneye_monitor.py
hdmi_cec.py
history.py
history_graph.py
hive.py
hlk_sw16.py
huawei_lte.py
hydrawise.py
influxdb.py
input_boolean.py
input_datetime.py
input_number.py
input_select.py
input_text.py
insteon_local.py
insteon_plm.py
intent_script.py
introduction.py
iota.py
isy994.py
joaoapps_join.py
juicenet.py
keyboard.py
keyboard_remote.py
kira.py
knx.py
konnected.py
lametric.py
lightwave.py
linode.py
lirc.py
litejet.py
logbook.py
logentries.py
logger.py
logi_circle.py
lupusec.py
lutron.py
lutron_caseta.py
map.py
matrix.py
maxcube.py
media_extractor.py
melissa.py
microsoft_face.py
mochad.py
modbus.py
mqtt_eventstream.py
mqtt_statestream.py
mychevy.py
mycroft.py
namecheapdns.py
neato.py
netatmo.py
netgear_lte.py
no_ip.py
nuheat.py
nuimo_controller.py
octoprint.py
panel_custom.py
panel_iframe.py
pilight.py
plant.py
prometheus.py
proximity.py
python_script.py
qwikswitch.py
rachio.py
rainbird.py
raincloud.py
raspihats.py
rest_command.py
rflink.py
rfxtrx.py
ring.py
route53.py
rpi_gpio.py
rpi_pfio.py
rss_feed_template.py
sabnzbd.py
satel_integra.py
script.py
scsgate.py
sense.py
services.yaml
shell_command.py
shiftr.py
shopping_list.py
sisyphus.py
skybell.py
sleepiq.py
smappee.py
snips.py
spaceapi.py
spc.py
spider.py
splunk.py
statsd.py
sun.py
tado.py
tahoma.py
tellstick.py
tesla.py
thethingsnetwork.py
thingspeak.py
toon.py
tplink_lte.py
tuya.py
upcloud.py
updater.py
usps.py
velbus.py
velux.py
vera.py
verisure.py
volvooncall.py
vultr.py
w800rf32.py
wake_on_lan.py
waterfurnace.py
watson_iot.py
webhook.py
weblink.py
wemo.py
wirelesstag.py
xiaomi_aqara.py
zabbix.py
zeroconf.py
zigbee.py
helpers
scripts
util
__init__.py
__main__.py
bootstrap.py
config.py
config_entries.py
const.py
core.py
data_entry_flow.py
exceptions.py
loader.py
monkey_patch.py
package_constraints.txt
requirements.py
setup.py
script
tests
virtualization
.coveragerc
.dockerignore
.gitattributes
.gitignore
.hound.yml
.ignore
.isort.cfg
.readthedocs.yml
.travis.yml
CLA.md
CODEOWNERS
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Dockerfile
LICENSE.md
MANIFEST.in
README.rst
mypy.ini
pylintrc
requirements_all.txt
requirements_docs.txt
requirements_test.txt
requirements_test_all.txt
setup.cfg
setup.py
tox.ini
core/homeassistant/components/sensor/mqtt.py
2018-11-30 16:53:56 +01:00

228 lines
8.6 KiB
Python

"""
Support for MQTT sensors.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.mqtt/
"""
import logging
import json
from datetime import timedelta
from typing import Optional
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components import sensor
from homeassistant.components.mqtt import (
ATTR_DISCOVERY_HASH, CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC,
CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS,
MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, subscription)
from homeassistant.components.mqtt.discovery import MQTT_DISCOVERY_NEW
from homeassistant.components.sensor import DEVICE_CLASSES_SCHEMA
from homeassistant.const import (
CONF_FORCE_UPDATE, CONF_NAME, CONF_VALUE_TEMPLATE, STATE_UNKNOWN,
CONF_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_DEVICE_CLASS, CONF_DEVICE)
from homeassistant.helpers.entity import Entity
from homeassistant.components import mqtt
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import HomeAssistantType, ConfigType
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util import dt as dt_util
_LOGGER = logging.getLogger(__name__)
CONF_EXPIRE_AFTER = 'expire_after'
CONF_JSON_ATTRS = 'json_attributes'
CONF_UNIQUE_ID = 'unique_id'
DEFAULT_NAME = 'MQTT Sensor'
DEFAULT_FORCE_UPDATE = False
DEPENDENCIES = ['mqtt']
PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv,
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
# Integrations should never expose unique_id through configuration.
# This is an exception because MQTT is a message transport, not a protocol.
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA,
}).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema)
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType,
async_add_entities, discovery_info=None):
"""Set up MQTT sensors through configuration.yaml."""
await _async_setup_entity(config, async_add_entities)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up MQTT sensors dynamically through MQTT discovery."""
async def async_discover_sensor(discovery_payload):
"""Discover and add a discovered MQTT sensor."""
config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(config, async_add_entities,
discovery_payload[ATTR_DISCOVERY_HASH])
async_dispatcher_connect(hass,
MQTT_DISCOVERY_NEW.format(sensor.DOMAIN, 'mqtt'),
async_discover_sensor)
async def _async_setup_entity(config: ConfigType, async_add_entities,
discovery_hash=None):
"""Set up MQTT sensor."""
async_add_entities([MqttSensor(config, discovery_hash)])
class MqttSensor(MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo,
Entity):
"""Representation of a sensor that can be updated using MQTT."""
def __init__(self, config, discovery_hash):
"""Initialize the sensor."""
self._config = config
self._unique_id = config.get(CONF_UNIQUE_ID)
self._state = STATE_UNKNOWN
self._sub_state = None
self._expiration_trigger = None
self._attributes = None
availability_topic = config.get(CONF_AVAILABILITY_TOPIC)
payload_available = config.get(CONF_PAYLOAD_AVAILABLE)
payload_not_available = config.get(CONF_PAYLOAD_NOT_AVAILABLE)
qos = config.get(CONF_QOS)
device_config = config.get(CONF_DEVICE)
MqttAvailability.__init__(self, availability_topic, qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash,
self.discovery_update)
MqttEntityDeviceInfo.__init__(self, device_config)
async def async_added_to_hass(self):
"""Subscribe to MQTT events."""
await super().async_added_to_hass()
await self._subscribe_topics()
async def discovery_update(self, discovery_payload):
"""Handle updated discovery message."""
config = PLATFORM_SCHEMA(discovery_payload)
self._config = config
await self.availability_discovery_update(config)
await self._subscribe_topics()
self.async_schedule_update_ha_state()
async def _subscribe_topics(self):
"""(Re)Subscribe to topics."""
template = self._config.get(CONF_VALUE_TEMPLATE)
if template is not None:
template.hass = self.hass
@callback
def message_received(topic, payload, qos):
"""Handle new MQTT messages."""
# auto-expire enabled?
expire_after = self._config.get(CONF_EXPIRE_AFTER)
if expire_after is not None and expire_after > 0:
# Reset old trigger
if self._expiration_trigger:
self._expiration_trigger()
self._expiration_trigger = None
# Set new trigger
expiration_at = (
dt_util.utcnow() + timedelta(seconds=expire_after))
self._expiration_trigger = async_track_point_in_utc_time(
self.hass, self.value_is_expired, expiration_at)
json_attributes = set(self._config.get(CONF_JSON_ATTRS))
if json_attributes:
self._attributes = {}
try:
json_dict = json.loads(payload)
if isinstance(json_dict, dict):
attrs = {k: json_dict[k] for k in
json_attributes & json_dict.keys()}
self._attributes = attrs
else:
_LOGGER.warning("JSON result was not a dictionary")
except ValueError:
_LOGGER.warning("MQTT payload could not be parsed as JSON")
_LOGGER.debug("Erroneous JSON: %s", payload)
if template is not None:
payload = template.async_render_with_possible_json_value(
payload, self._state)
self._state = payload
self.async_schedule_update_ha_state()
self._sub_state = await subscription.async_subscribe_topics(
self.hass, self._sub_state,
{'state_topic': {'topic': self._config.get(CONF_STATE_TOPIC),
'msg_callback': message_received,
'qos': self._config.get(CONF_QOS)}})
async def async_will_remove_from_hass(self):
"""Unsubscribe when removed."""
await subscription.async_unsubscribe_topics(self.hass, self._sub_state)
await MqttAvailability.async_will_remove_from_hass(self)
@callback
def value_is_expired(self, *_):
"""Triggered when value is expired."""
self._expiration_trigger = None
self._state = STATE_UNKNOWN
self.async_schedule_update_ha_state()
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def name(self):
"""Return the name of the sensor."""
return self._config.get(CONF_NAME)
@property
def unit_of_measurement(self):
"""Return the unit this state is expressed in."""
return self._config.get(CONF_UNIT_OF_MEASUREMENT)
@property
def force_update(self):
"""Force update."""
return self._config.get(CONF_FORCE_UPDATE)
@property
def state(self):
"""Return the state of the entity."""
return self._state
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes
@property
def unique_id(self):
"""Return a unique ID."""
return self._unique_id
@property
def icon(self):
"""Return the icon."""
return self._config.get(CONF_ICON)
@property
def device_class(self) -> Optional[str]:
"""Return the device class of the sensor."""
return self._config.get(CONF_DEVICE_CLASS)