mirror of
https://github.com/home-assistant/core.git
synced 2025-07-12 15:57:06 +00:00
commit
a4ee2bd8ef
@ -24,11 +24,6 @@ DOMAIN = "mqtt"
|
||||
|
||||
MQTT_CLIENT = None
|
||||
|
||||
DEFAULT_PORT = 1883
|
||||
DEFAULT_KEEPALIVE = 60
|
||||
DEFAULT_QOS = 0
|
||||
DEFAULT_RETAIN = False
|
||||
|
||||
SERVICE_PUBLISH = 'publish'
|
||||
EVENT_MQTT_MESSAGE_RECEIVED = 'mqtt_message_received'
|
||||
|
||||
@ -41,6 +36,16 @@ CONF_KEEPALIVE = 'keepalive'
|
||||
CONF_USERNAME = 'username'
|
||||
CONF_PASSWORD = 'password'
|
||||
CONF_CERTIFICATE = 'certificate'
|
||||
CONF_PROTOCOL = 'protocol'
|
||||
|
||||
PROTOCOL_31 = '3.1'
|
||||
PROTOCOL_311 = '3.1.1'
|
||||
|
||||
DEFAULT_PORT = 1883
|
||||
DEFAULT_KEEPALIVE = 60
|
||||
DEFAULT_QOS = 0
|
||||
DEFAULT_RETAIN = False
|
||||
DEFAULT_PROTOCOL = PROTOCOL_311
|
||||
|
||||
ATTR_TOPIC = 'topic'
|
||||
ATTR_PAYLOAD = 'payload'
|
||||
@ -51,7 +56,7 @@ MAX_RECONNECT_WAIT = 300 # seconds
|
||||
|
||||
|
||||
def publish(hass, topic, payload, qos=None, retain=None):
|
||||
""" Send an MQTT message. """
|
||||
"""Publish message to an MQTT topic."""
|
||||
data = {
|
||||
ATTR_TOPIC: topic,
|
||||
ATTR_PAYLOAD: payload,
|
||||
@ -66,9 +71,9 @@ def publish(hass, topic, payload, qos=None, retain=None):
|
||||
|
||||
|
||||
def subscribe(hass, topic, callback, qos=DEFAULT_QOS):
|
||||
""" Subscribe to a topic. """
|
||||
"""Subscribe to an MQTT topic."""
|
||||
def mqtt_topic_subscriber(event):
|
||||
""" Match subscribed MQTT topic. """
|
||||
"""Match subscribed MQTT topic."""
|
||||
if _match_topic(topic, event.data[ATTR_TOPIC]):
|
||||
callback(event.data[ATTR_TOPIC], event.data[ATTR_PAYLOAD],
|
||||
event.data[ATTR_QOS])
|
||||
@ -78,8 +83,7 @@ def subscribe(hass, topic, callback, qos=DEFAULT_QOS):
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
""" Get the MQTT protocol service. """
|
||||
|
||||
"""Start the MQTT protocol service."""
|
||||
if not validate_config(config, {DOMAIN: ['broker']}, _LOGGER):
|
||||
return False
|
||||
|
||||
@ -92,6 +96,12 @@ def setup(hass, config):
|
||||
username = util.convert(conf.get(CONF_USERNAME), str)
|
||||
password = util.convert(conf.get(CONF_PASSWORD), str)
|
||||
certificate = util.convert(conf.get(CONF_CERTIFICATE), str)
|
||||
protocol = util.convert(conf.get(CONF_PROTOCOL), str, DEFAULT_PROTOCOL)
|
||||
|
||||
if protocol not in (PROTOCOL_31, PROTOCOL_311):
|
||||
_LOGGER.error('Invalid protocol specified: %s. Allowed values: %s, %s',
|
||||
protocol, PROTOCOL_31, PROTOCOL_311)
|
||||
return False
|
||||
|
||||
# For cloudmqtt.com, secured connection, auto fill in certificate
|
||||
if certificate is None and 19999 < port < 30000 and \
|
||||
@ -102,7 +112,7 @@ def setup(hass, config):
|
||||
global MQTT_CLIENT
|
||||
try:
|
||||
MQTT_CLIENT = MQTT(hass, broker, port, client_id, keepalive, username,
|
||||
password, certificate)
|
||||
password, certificate, protocol)
|
||||
except socket.error:
|
||||
_LOGGER.exception("Can't connect to the broker. "
|
||||
"Please check your settings and the broker "
|
||||
@ -110,16 +120,16 @@ def setup(hass, config):
|
||||
return False
|
||||
|
||||
def stop_mqtt(event):
|
||||
""" Stop MQTT component. """
|
||||
"""Stop MQTT component."""
|
||||
MQTT_CLIENT.stop()
|
||||
|
||||
def start_mqtt(event):
|
||||
""" Launch MQTT component when Home Assistant starts up. """
|
||||
"""Launch MQTT component when Home Assistant starts up."""
|
||||
MQTT_CLIENT.start()
|
||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_mqtt)
|
||||
|
||||
def publish_service(call):
|
||||
""" Handle MQTT publish service calls. """
|
||||
"""Handle MQTT publish service calls."""
|
||||
msg_topic = call.data.get(ATTR_TOPIC)
|
||||
payload = call.data.get(ATTR_PAYLOAD)
|
||||
qos = call.data.get(ATTR_QOS, DEFAULT_QOS)
|
||||
@ -137,148 +147,161 @@ def setup(hass, config):
|
||||
|
||||
# pylint: disable=too-many-arguments
|
||||
class MQTT(object):
|
||||
""" Implements messaging service for MQTT. """
|
||||
"""Home Assistant MQTT client."""
|
||||
|
||||
def __init__(self, hass, broker, port, client_id, keepalive, username,
|
||||
password, certificate):
|
||||
password, certificate, protocol):
|
||||
"""Initialize Home Assistant MQTT client."""
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
self.userdata = {
|
||||
'hass': hass,
|
||||
'topics': {},
|
||||
'progress': {},
|
||||
}
|
||||
self.hass = hass
|
||||
self.topics = {}
|
||||
self.progress = {}
|
||||
|
||||
if protocol == PROTOCOL_31:
|
||||
proto = mqtt.MQTTv31
|
||||
else:
|
||||
proto = mqtt.MQTTv311
|
||||
|
||||
if client_id is None:
|
||||
self._mqttc = mqtt.Client(protocol=mqtt.MQTTv311)
|
||||
self._mqttc = mqtt.Client(protocol=proto)
|
||||
else:
|
||||
self._mqttc = mqtt.Client(client_id, protocol=mqtt.MQTTv311)
|
||||
|
||||
self._mqttc.user_data_set(self.userdata)
|
||||
self._mqttc = mqtt.Client(client_id, protocol=proto)
|
||||
|
||||
if username is not None:
|
||||
self._mqttc.username_pw_set(username, password)
|
||||
if certificate is not None:
|
||||
self._mqttc.tls_set(certificate)
|
||||
|
||||
self._mqttc.on_subscribe = _mqtt_on_subscribe
|
||||
self._mqttc.on_unsubscribe = _mqtt_on_unsubscribe
|
||||
self._mqttc.on_connect = _mqtt_on_connect
|
||||
self._mqttc.on_disconnect = _mqtt_on_disconnect
|
||||
self._mqttc.on_message = _mqtt_on_message
|
||||
self._mqttc.on_subscribe = self._mqtt_on_subscribe
|
||||
self._mqttc.on_unsubscribe = self._mqtt_on_unsubscribe
|
||||
self._mqttc.on_connect = self._mqtt_on_connect
|
||||
self._mqttc.on_disconnect = self._mqtt_on_disconnect
|
||||
self._mqttc.on_message = self._mqtt_on_message
|
||||
|
||||
self._mqttc.connect(broker, port, keepalive)
|
||||
|
||||
def publish(self, topic, payload, qos, retain):
|
||||
""" Publish a MQTT message. """
|
||||
"""Publish a MQTT message."""
|
||||
self._mqttc.publish(topic, payload, qos, retain)
|
||||
|
||||
def start(self):
|
||||
""" Run the MQTT client. """
|
||||
"""Run the MQTT client."""
|
||||
self._mqttc.loop_start()
|
||||
|
||||
def stop(self):
|
||||
""" Stop the MQTT client. """
|
||||
"""Stop the MQTT client."""
|
||||
self._mqttc.disconnect()
|
||||
self._mqttc.loop_stop()
|
||||
|
||||
def subscribe(self, topic, qos):
|
||||
""" Subscribe to a topic. """
|
||||
if topic in self.userdata['topics']:
|
||||
"""Subscribe to a topic."""
|
||||
assert isinstance(topic, str)
|
||||
|
||||
if topic in self.topics:
|
||||
return
|
||||
result, mid = self._mqttc.subscribe(topic, qos)
|
||||
_raise_on_error(result)
|
||||
self.userdata['progress'][mid] = topic
|
||||
self.userdata['topics'][topic] = None
|
||||
self.progress[mid] = topic
|
||||
self.topics[topic] = None
|
||||
|
||||
def unsubscribe(self, topic):
|
||||
""" Unsubscribe from topic. """
|
||||
"""Unsubscribe from topic."""
|
||||
result, mid = self._mqttc.unsubscribe(topic)
|
||||
_raise_on_error(result)
|
||||
self.userdata['progress'][mid] = topic
|
||||
self.progress[mid] = topic
|
||||
|
||||
def _mqtt_on_connect(self, _mqttc, _userdata, _flags, result_code):
|
||||
"""On connect callback.
|
||||
|
||||
def _mqtt_on_message(mqttc, userdata, msg):
|
||||
""" Message callback """
|
||||
userdata['hass'].bus.fire(EVENT_MQTT_MESSAGE_RECEIVED, {
|
||||
ATTR_TOPIC: msg.topic,
|
||||
ATTR_QOS: msg.qos,
|
||||
ATTR_PAYLOAD: msg.payload.decode('utf-8'),
|
||||
})
|
||||
Resubscribe to all topics we were subscribed to.
|
||||
"""
|
||||
if result_code != 0:
|
||||
_LOGGER.error('Unable to connect to the MQTT broker: %s', {
|
||||
1: 'Incorrect protocol version',
|
||||
2: 'Invalid client identifier',
|
||||
3: 'Server unavailable',
|
||||
4: 'Bad username or password',
|
||||
5: 'Not authorised'
|
||||
}.get(result_code, 'Unknown reason'))
|
||||
self._mqttc.disconnect()
|
||||
return
|
||||
|
||||
old_topics = self.topics
|
||||
|
||||
def _mqtt_on_connect(mqttc, userdata, flags, result_code):
|
||||
""" On connect, resubscribe to all topics we were subscribed to. """
|
||||
if result_code != 0:
|
||||
_LOGGER.error('Unable to connect to the MQTT broker: %s', {
|
||||
1: 'Incorrect protocol version',
|
||||
2: 'Invalid client identifier',
|
||||
3: 'Server unavailable',
|
||||
4: 'Bad username or password',
|
||||
5: 'Not authorised'
|
||||
}.get(result_code, 'Unknown reason'))
|
||||
mqttc.disconnect()
|
||||
return
|
||||
self.topics = {key: value for key, value in self.topics.items()
|
||||
if value is None}
|
||||
|
||||
old_topics = userdata['topics']
|
||||
for topic, qos in old_topics.items():
|
||||
# qos is None if we were in process of subscribing
|
||||
if qos is not None:
|
||||
self.subscribe(topic, qos)
|
||||
|
||||
userdata['topics'] = {}
|
||||
userdata['progress'] = {}
|
||||
def _mqtt_on_subscribe(self, _mqttc, _userdata, mid, granted_qos):
|
||||
"""Subscribe successful callback."""
|
||||
topic = self.progress.pop(mid, None)
|
||||
if topic is None:
|
||||
return
|
||||
self.topics[topic] = granted_qos[0]
|
||||
|
||||
for topic, qos in old_topics.items():
|
||||
# qos is None if we were in process of subscribing
|
||||
if qos is not None:
|
||||
mqttc.subscribe(topic, qos)
|
||||
def _mqtt_on_message(self, _mqttc, _userdata, msg):
|
||||
"""Message received callback."""
|
||||
self.hass.bus.fire(EVENT_MQTT_MESSAGE_RECEIVED, {
|
||||
ATTR_TOPIC: msg.topic,
|
||||
ATTR_QOS: msg.qos,
|
||||
ATTR_PAYLOAD: msg.payload.decode('utf-8'),
|
||||
})
|
||||
|
||||
def _mqtt_on_unsubscribe(self, _mqttc, _userdata, mid, granted_qos):
|
||||
"""Unsubscribe successful callback."""
|
||||
topic = self.progress.pop(mid, None)
|
||||
if topic is None:
|
||||
return
|
||||
self.topics.pop(topic, None)
|
||||
|
||||
def _mqtt_on_subscribe(mqttc, userdata, mid, granted_qos):
|
||||
""" Called when subscribe successful. """
|
||||
topic = userdata['progress'].pop(mid, None)
|
||||
if topic is None:
|
||||
return
|
||||
userdata['topics'][topic] = granted_qos
|
||||
def _mqtt_on_disconnect(self, _mqttc, _userdata, result_code):
|
||||
"""Disconnected callback."""
|
||||
self.progress = {}
|
||||
self.topics = {key: value for key, value in self.topics.items()
|
||||
if value is not None}
|
||||
|
||||
# Remove None values from topic list
|
||||
for key in list(self.topics):
|
||||
if self.topics[key] is None:
|
||||
self.topics.pop(key)
|
||||
|
||||
def _mqtt_on_unsubscribe(mqttc, userdata, mid, granted_qos):
|
||||
""" Called when subscribe successful. """
|
||||
topic = userdata['progress'].pop(mid, None)
|
||||
if topic is None:
|
||||
return
|
||||
userdata['topics'].pop(topic, None)
|
||||
# When disconnected because of calling disconnect()
|
||||
if result_code == 0:
|
||||
return
|
||||
|
||||
tries = 0
|
||||
wait_time = 0
|
||||
|
||||
def _mqtt_on_disconnect(mqttc, userdata, result_code):
|
||||
""" Called when being disconnected. """
|
||||
# When disconnected because of calling disconnect()
|
||||
if result_code == 0:
|
||||
return
|
||||
while True:
|
||||
try:
|
||||
if self._mqttc.reconnect() == 0:
|
||||
_LOGGER.info('Successfully reconnected to the MQTT server')
|
||||
break
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
tries = 0
|
||||
wait_time = 0
|
||||
|
||||
while True:
|
||||
try:
|
||||
if mqttc.reconnect() == 0:
|
||||
_LOGGER.info('Successfully reconnected to the MQTT server')
|
||||
break
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
wait_time = min(2**tries, MAX_RECONNECT_WAIT)
|
||||
_LOGGER.warning(
|
||||
'Disconnected from MQTT (%s). Trying to reconnect in %ss',
|
||||
result_code, wait_time)
|
||||
# It is ok to sleep here as we are in the MQTT thread.
|
||||
time.sleep(wait_time)
|
||||
tries += 1
|
||||
wait_time = min(2**tries, MAX_RECONNECT_WAIT)
|
||||
_LOGGER.warning(
|
||||
'Disconnected from MQTT (%s). Trying to reconnect in %ss',
|
||||
result_code, wait_time)
|
||||
# It is ok to sleep here as we are in the MQTT thread.
|
||||
time.sleep(wait_time)
|
||||
tries += 1
|
||||
|
||||
|
||||
def _raise_on_error(result):
|
||||
""" Raise error if error result. """
|
||||
"""Raise error if error result."""
|
||||
if result != 0:
|
||||
raise HomeAssistantError('Error talking to MQTT: {}'.format(result))
|
||||
|
||||
|
||||
def _match_topic(subscription, topic):
|
||||
""" Returns if topic matches subscription. """
|
||||
"""Test if topic matches subscription."""
|
||||
if subscription.endswith('#'):
|
||||
return (subscription[:-2] == topic or
|
||||
topic.startswith(subscription[:-1]))
|
||||
|
@ -72,8 +72,6 @@ DISCOVERY_COMPONENTS = [
|
||||
|
||||
def setup(hass, config):
|
||||
"""Setup the MySensors component."""
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
if not validate_config(config,
|
||||
{DOMAIN: [CONF_GATEWAYS]},
|
||||
_LOGGER):
|
||||
|
@ -17,24 +17,24 @@ REQUIREMENTS = ['blockchain==1.1.2']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
OPTION_TYPES = {
|
||||
'wallet': ['Wallet balance', 'BTC'],
|
||||
'exchangerate': ['Exchange rate (1 BTC)', ''],
|
||||
'exchangerate': ['Exchange rate (1 BTC)', None],
|
||||
'trade_volume_btc': ['Trade volume', 'BTC'],
|
||||
'miners_revenue_usd': ['Miners revenue', 'USD'],
|
||||
'btc_mined': ['Mined', 'BTC'],
|
||||
'trade_volume_usd': ['Trade volume', 'USD'],
|
||||
'difficulty': ['Difficulty', ''],
|
||||
'difficulty': ['Difficulty', None],
|
||||
'minutes_between_blocks': ['Time between Blocks', 'min'],
|
||||
'number_of_transactions': ['No. of Transactions', ''],
|
||||
'number_of_transactions': ['No. of Transactions', None],
|
||||
'hash_rate': ['Hash rate', 'PH/s'],
|
||||
'timestamp': ['Timestamp', ''],
|
||||
'mined_blocks': ['Minded Blocks', ''],
|
||||
'blocks_size': ['Block size', ''],
|
||||
'timestamp': ['Timestamp', None],
|
||||
'mined_blocks': ['Minded Blocks', None],
|
||||
'blocks_size': ['Block size', None],
|
||||
'total_fees_btc': ['Total fees', 'BTC'],
|
||||
'total_btc_sent': ['Total sent', 'BTC'],
|
||||
'estimated_btc_sent': ['Estimated sent', 'BTC'],
|
||||
'total_btc': ['Total', 'BTC'],
|
||||
'total_blocks': ['Total Blocks', ''],
|
||||
'next_retarget': ['Next retarget', ''],
|
||||
'total_blocks': ['Total Blocks', None],
|
||||
'next_retarget': ['Next retarget', None],
|
||||
'estimated_transaction_volume_usd': ['Est. Transaction volume', 'USD'],
|
||||
'miners_revenue_btc': ['Miners revenue', 'BTC'],
|
||||
'market_price_usd': ['Market price', 'USD']
|
||||
|
@ -20,7 +20,7 @@ REQUIREMENTS = ['http://github.com/mala-zaba/Adafruit_Python_DHT/archive/'
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SENSOR_TYPES = {
|
||||
'temperature': ['Temperature', ''],
|
||||
'temperature': ['Temperature', None],
|
||||
'humidity': ['Humidity', '%']
|
||||
}
|
||||
# Return cached results if last scan was less then this time ago
|
||||
|
@ -36,7 +36,7 @@ DEPENDENCIES = ['ecobee']
|
||||
SENSOR_TYPES = {
|
||||
'temperature': ['Temperature', TEMP_FAHRENHEIT],
|
||||
'humidity': ['Humidity', '%'],
|
||||
'occupancy': ['Occupancy', '']
|
||||
'occupancy': ['Occupancy', None]
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -16,8 +16,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
_RESOURCE = 'https://engage.efergy.com/mobile_proxy/'
|
||||
SENSOR_TYPES = {
|
||||
'instant_readings': ['Energy Usage', 'kW'],
|
||||
'budget': ['Energy Budget', ''],
|
||||
'cost': ['Energy Cost', ''],
|
||||
'budget': ['Energy Budget', None],
|
||||
'cost': ['Energy Cost', None],
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,13 +19,13 @@ _LOGGER = logging.getLogger(__name__)
|
||||
# Sensor types are defined like so:
|
||||
# Name, si unit, us unit, ca unit, uk unit, uk2 unit
|
||||
SENSOR_TYPES = {
|
||||
'summary': ['Summary', '', '', '', '', ''],
|
||||
'icon': ['Icon', '', '', '', '', ''],
|
||||
'summary': ['Summary', None, None, None, None, None],
|
||||
'icon': ['Icon', None, None, None, None, None],
|
||||
'nearest_storm_distance': ['Nearest Storm Distance',
|
||||
'km', 'm', 'km', 'km', 'm'],
|
||||
'nearest_storm_bearing': ['Nearest Storm Bearing',
|
||||
'°', '°', '°', '°', '°'],
|
||||
'precip_type': ['Precip', '', '', '', '', ''],
|
||||
'precip_type': ['Precip', None, None, None, None, None],
|
||||
'precip_intensity': ['Precip Intensity', 'mm', 'in', 'mm', 'mm', 'mm'],
|
||||
'precip_probability': ['Precip Probability', '%', '%', '%', '%', '%'],
|
||||
'temperature': ['Temperature', '°C', '°F', '°C', '°C', '°C'],
|
||||
|
@ -31,11 +31,11 @@ SENSOR_TYPES = {
|
||||
'swap_use_percent': ['Swap Use', '%'],
|
||||
'swap_use': ['Swap Use', 'GiB'],
|
||||
'swap_free': ['Swap Free', 'GiB'],
|
||||
'processor_load': ['CPU Load', ''],
|
||||
'process_running': ['Running', ''],
|
||||
'process_total': ['Total', ''],
|
||||
'process_thread': ['Thread', ''],
|
||||
'process_sleeping': ['Sleeping', '']
|
||||
'processor_load': ['CPU Load', None],
|
||||
'process_running': ['Running', None],
|
||||
'process_total': ['Total', None],
|
||||
'process_thread': ['Thread', None],
|
||||
'process_sleeping': ['Sleeping', None]
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -33,6 +33,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
# Define the S_TYPES and V_TYPES that the platform should handle as
|
||||
# states.
|
||||
s_types = [
|
||||
gateway.const.Presentation.S_DOOR,
|
||||
gateway.const.Presentation.S_MOTION,
|
||||
gateway.const.Presentation.S_SMOKE,
|
||||
gateway.const.Presentation.S_TEMP,
|
||||
gateway.const.Presentation.S_HUM,
|
||||
gateway.const.Presentation.S_BARO,
|
||||
@ -59,6 +62,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
s_types.extend([
|
||||
gateway.const.Presentation.S_COLOR_SENSOR,
|
||||
gateway.const.Presentation.S_MULTIMETER,
|
||||
gateway.const.Presentation.S_SPRINKLER,
|
||||
gateway.const.Presentation.S_WATER_LEAK,
|
||||
gateway.const.Presentation.S_SOUND,
|
||||
gateway.const.Presentation.S_VIBRATION,
|
||||
gateway.const.Presentation.S_MOISTURE,
|
||||
])
|
||||
not_v_types.extend([gateway.const.SetReq.V_STATUS, ])
|
||||
v_types = [member for member in gateway.const.SetReq
|
||||
|
@ -16,8 +16,8 @@ from homeassistant.helpers.entity import Entity
|
||||
REQUIREMENTS = ['pyowm==2.3.0']
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
SENSOR_TYPES = {
|
||||
'weather': ['Condition', ''],
|
||||
'temperature': ['Temperature', ''],
|
||||
'weather': ['Condition', None],
|
||||
'temperature': ['Temperature', None],
|
||||
'wind_speed': ['Wind speed', 'm/s'],
|
||||
'humidity': ['Humidity', '%'],
|
||||
'pressure': ['Pressure', 'mbar'],
|
||||
@ -71,7 +71,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
pass
|
||||
|
||||
if forecast == 1:
|
||||
SENSOR_TYPES['forecast'] = ['Forecast', '']
|
||||
SENSOR_TYPES['forecast'] = ['Forecast', None]
|
||||
dev.append(OpenWeatherMapSensor(data, 'forecast', unit))
|
||||
|
||||
add_devices(dev)
|
||||
|
@ -17,7 +17,7 @@ REQUIREMENTS = ['https://github.com/jamespcole/home-assistant-nzb-clients/'
|
||||
'#python-sabnzbd==0.1']
|
||||
|
||||
SENSOR_TYPES = {
|
||||
'current_status': ['Status', ''],
|
||||
'current_status': ['Status', None],
|
||||
'speed': ['Speed', 'MB/s'],
|
||||
'queue_size': ['Queue', 'MB'],
|
||||
'queue_remaining': ['Left', 'MB'],
|
||||
|
@ -18,7 +18,6 @@ from homeassistant.components import tellduslive
|
||||
ATTR_LAST_UPDATED = "time_last_updated"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
DEPENDENCIES = ['tellduslive']
|
||||
|
||||
SENSOR_TYPE_TEMP = "temp"
|
||||
SENSOR_TYPE_HUMIDITY = "humidity"
|
||||
@ -43,6 +42,8 @@ SENSOR_TYPES = {
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
""" Sets up Tellstick sensors. """
|
||||
if discovery_info is None:
|
||||
return
|
||||
sensors = tellduslive.NETWORK.get_sensors()
|
||||
devices = []
|
||||
|
||||
|
@ -15,7 +15,7 @@ from homeassistant.helpers.entity import Entity
|
||||
|
||||
REQUIREMENTS = ['transmissionrpc==0.11']
|
||||
SENSOR_TYPES = {
|
||||
'current_status': ['Status', ''],
|
||||
'current_status': ['Status', None],
|
||||
'download_speed': ['Down Speed', 'MB/s'],
|
||||
'upload_speed': ['Up Speed', 'MB/s']
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class VerisureThermometer(Entity):
|
||||
return TEMP_CELCIUS # can verisure report in fahrenheit?
|
||||
|
||||
def update(self):
|
||||
''' update sensor '''
|
||||
""" update sensor """
|
||||
verisure.update_climate()
|
||||
|
||||
|
||||
@ -96,5 +96,5 @@ class VerisureHygrometer(Entity):
|
||||
return "%"
|
||||
|
||||
def update(self):
|
||||
''' update sensor '''
|
||||
""" update sensor """
|
||||
verisure.update_climate()
|
||||
|
@ -21,7 +21,7 @@ REQUIREMENTS = ['xmltodict']
|
||||
|
||||
# Sensor types are defined like so:
|
||||
SENSOR_TYPES = {
|
||||
'symbol': ['Symbol', ''],
|
||||
'symbol': ['Symbol', None],
|
||||
'precipitation': ['Condition', 'mm'],
|
||||
'temperature': ['Temperature', '°C'],
|
||||
'windSpeed': ['Wind speed', 'm/s'],
|
||||
|
@ -15,11 +15,12 @@ from homeassistant.components import tellduslive
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
DEPENDENCIES = ['tellduslive']
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
""" Find and return Tellstick switches. """
|
||||
if discovery_info is None:
|
||||
return
|
||||
switches = tellduslive.NETWORK.get_switches()
|
||||
add_devices([TelldusLiveSwitch(switch["name"],
|
||||
switch["id"])
|
||||
|
@ -1,7 +1,7 @@
|
||||
# coding: utf-8
|
||||
""" Constants used by Home Assistant components. """
|
||||
|
||||
__version__ = "0.11.0"
|
||||
__version__ = "0.11.1"
|
||||
|
||||
# Can be used to specify a catch all when registering state or event listeners.
|
||||
MATCH_ALL = '*'
|
||||
|
@ -101,17 +101,18 @@ class Entity(object):
|
||||
state = str(self.state)
|
||||
attr = self.state_attributes or {}
|
||||
|
||||
if ATTR_FRIENDLY_NAME not in attr and self.name:
|
||||
attr[ATTR_FRIENDLY_NAME] = self.name
|
||||
if ATTR_FRIENDLY_NAME not in attr and self.name is not None:
|
||||
attr[ATTR_FRIENDLY_NAME] = str(self.name)
|
||||
|
||||
if ATTR_UNIT_OF_MEASUREMENT not in attr and self.unit_of_measurement:
|
||||
attr[ATTR_UNIT_OF_MEASUREMENT] = self.unit_of_measurement
|
||||
if ATTR_UNIT_OF_MEASUREMENT not in attr and \
|
||||
self.unit_of_measurement is not None:
|
||||
attr[ATTR_UNIT_OF_MEASUREMENT] = str(self.unit_of_measurement)
|
||||
|
||||
if ATTR_ICON not in attr and self.icon:
|
||||
attr[ATTR_ICON] = self.icon
|
||||
if ATTR_ICON not in attr and self.icon is not None:
|
||||
attr[ATTR_ICON] = str(self.icon)
|
||||
|
||||
if self.hidden:
|
||||
attr[ATTR_HIDDEN] = self.hidden
|
||||
attr[ATTR_HIDDEN] = bool(self.hidden)
|
||||
|
||||
# overwrite properties that have been set in the config file
|
||||
attr.update(_OVERWRITE.get(self.entity_id, {}))
|
||||
|
@ -144,8 +144,15 @@ class TestMQTTCallbacks(unittest.TestCase):
|
||||
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
self.hass = get_test_home_assistant(1)
|
||||
mock_mqtt_component(self.hass)
|
||||
self.calls = []
|
||||
# mock_mqtt_component(self.hass)
|
||||
|
||||
with mock.patch('paho.mqtt.client.Client'):
|
||||
mqtt.setup(self.hass, {
|
||||
mqtt.DOMAIN: {
|
||||
mqtt.CONF_BROKER: 'mock-broker',
|
||||
}
|
||||
})
|
||||
self.hass.config.components.append(mqtt.DOMAIN)
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
""" Stop down stuff we started. """
|
||||
@ -162,7 +169,7 @@ class TestMQTTCallbacks(unittest.TestCase):
|
||||
MQTTMessage = namedtuple('MQTTMessage', ['topic', 'qos', 'payload'])
|
||||
message = MQTTMessage('test_topic', 1, 'Hello World!'.encode('utf-8'))
|
||||
|
||||
mqtt._mqtt_on_message(None, {'hass': self.hass}, message)
|
||||
mqtt.MQTT_CLIENT._mqtt_on_message(None, {'hass': self.hass}, message)
|
||||
self.hass.pool.block_till_done()
|
||||
|
||||
self.assertEqual(1, len(calls))
|
||||
@ -173,36 +180,55 @@ class TestMQTTCallbacks(unittest.TestCase):
|
||||
|
||||
def test_mqtt_failed_connection_results_in_disconnect(self):
|
||||
for result_code in range(1, 6):
|
||||
mqttc = mock.MagicMock()
|
||||
mqtt._mqtt_on_connect(mqttc, {'topics': {}}, 0, result_code)
|
||||
self.assertTrue(mqttc.disconnect.called)
|
||||
mqtt.MQTT_CLIENT._mqttc = mock.MagicMock()
|
||||
mqtt.MQTT_CLIENT._mqtt_on_connect(None, {'topics': {}}, 0,
|
||||
result_code)
|
||||
self.assertTrue(mqtt.MQTT_CLIENT._mqttc.disconnect.called)
|
||||
|
||||
def test_mqtt_subscribes_topics_on_connect(self):
|
||||
prev_topics = {
|
||||
'topic/test': 1,
|
||||
'home/sensor': 2,
|
||||
'still/pending': None
|
||||
}
|
||||
mqttc = mock.MagicMock()
|
||||
mqtt._mqtt_on_connect(mqttc, {'topics': prev_topics}, 0, 0)
|
||||
self.assertFalse(mqttc.disconnect.called)
|
||||
from collections import OrderedDict
|
||||
prev_topics = OrderedDict()
|
||||
prev_topics['topic/test'] = 1,
|
||||
prev_topics['home/sensor'] = 2,
|
||||
prev_topics['still/pending'] = None
|
||||
|
||||
mqtt.MQTT_CLIENT.topics = prev_topics
|
||||
mqtt.MQTT_CLIENT.progress = {1: 'still/pending'}
|
||||
# Return values for subscribe calls (rc, mid)
|
||||
mqtt.MQTT_CLIENT._mqttc.subscribe.side_effect = ((0, 2), (0, 3))
|
||||
mqtt.MQTT_CLIENT._mqtt_on_connect(None, None, 0, 0)
|
||||
self.assertFalse(mqtt.MQTT_CLIENT._mqttc.disconnect.called)
|
||||
|
||||
expected = [(topic, qos) for topic, qos in prev_topics.items()
|
||||
if qos is not None]
|
||||
self.assertEqual(expected, [call[1] for call
|
||||
in mqttc.subscribe.mock_calls])
|
||||
self.assertEqual(
|
||||
expected,
|
||||
[call[1] for call in mqtt.MQTT_CLIENT._mqttc.subscribe.mock_calls])
|
||||
self.assertEqual({
|
||||
1: 'still/pending',
|
||||
2: 'topic/test',
|
||||
3: 'home/sensor',
|
||||
}, mqtt.MQTT_CLIENT.progress)
|
||||
|
||||
def test_mqtt_disconnect_tries_no_reconnect_on_stop(self):
|
||||
mqttc = mock.MagicMock()
|
||||
mqtt._mqtt_on_disconnect(mqttc, {}, 0)
|
||||
self.assertFalse(mqttc.reconnect.called)
|
||||
mqtt.MQTT_CLIENT._mqtt_on_disconnect(None, None, 0)
|
||||
self.assertFalse(mqtt.MQTT_CLIENT._mqttc.reconnect.called)
|
||||
|
||||
@mock.patch('homeassistant.components.mqtt.time.sleep')
|
||||
def test_mqtt_disconnect_tries_reconnect(self, mock_sleep):
|
||||
mqttc = mock.MagicMock()
|
||||
mqttc.reconnect.side_effect = [1, 1, 1, 0]
|
||||
mqtt._mqtt_on_disconnect(mqttc, {}, 1)
|
||||
self.assertTrue(mqttc.reconnect.called)
|
||||
self.assertEqual(4, len(mqttc.reconnect.mock_calls))
|
||||
mqtt.MQTT_CLIENT.topics = {
|
||||
'test/topic': 1,
|
||||
'test/progress': None
|
||||
}
|
||||
mqtt.MQTT_CLIENT.progress = {
|
||||
1: 'test/progress'
|
||||
}
|
||||
mqtt.MQTT_CLIENT._mqttc.reconnect.side_effect = [1, 1, 1, 0]
|
||||
mqtt.MQTT_CLIENT._mqtt_on_disconnect(None, None, 1)
|
||||
self.assertTrue(mqtt.MQTT_CLIENT._mqttc.reconnect.called)
|
||||
self.assertEqual(4, len(mqtt.MQTT_CLIENT._mqttc.reconnect.mock_calls))
|
||||
self.assertEqual([1, 2, 4],
|
||||
[call[1][0] for call in mock_sleep.mock_calls])
|
||||
|
||||
self.assertEqual({'test/topic': 1}, mqtt.MQTT_CLIENT.topics)
|
||||
self.assertEqual({}, mqtt.MQTT_CLIENT.progress)
|
||||
|
Loading…
x
Reference in New Issue
Block a user