De-syncing binary_sensor.ping (#17056)

* Quick and dirty asyncing of binary_sensor.ping

* Minor changes
This commit is contained in:
Thomas Lovén 2018-10-02 11:43:34 +02:00 committed by Fabian Affolter
parent 20601cfc2d
commit 11d5671ee0

View File

@ -4,18 +4,19 @@ Tracks the latency of a host by sending ICMP echo requests (ping).
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.ping/ https://home-assistant.io/components/binary_sensor.ping/
""" """
import logging import asyncio
import subprocess
import re
import sys
from datetime import timedelta from datetime import timedelta
import logging
import re
import subprocess
import sys
import voluptuous as vol import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA) PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.const import CONF_NAME, CONF_HOST from homeassistant.const import CONF_HOST, CONF_NAME
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -48,13 +49,14 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
}) })
def setup_platform(hass, config, add_entities, discovery_info=None): async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None):
"""Set up the Ping Binary sensor.""" """Set up the Ping Binary sensor."""
name = config.get(CONF_NAME) name = config.get(CONF_NAME)
host = config.get(CONF_HOST) host = config.get(CONF_HOST)
count = config.get(CONF_PING_COUNT) count = config.get(CONF_PING_COUNT)
add_entities([PingBinarySensor(name, PingData(host, count))], True) async_add_entities([PingBinarySensor(name, PingData(host, count))], True)
class PingBinarySensor(BinarySensorDevice): class PingBinarySensor(BinarySensorDevice):
@ -91,9 +93,9 @@ class PingBinarySensor(BinarySensorDevice):
ATTR_ROUND_TRIP_TIME_MIN: self.ping.data['min'], ATTR_ROUND_TRIP_TIME_MIN: self.ping.data['min'],
} }
def update(self): async def async_update(self):
"""Get the latest data.""" """Get the latest data."""
self.ping.update() await self.ping.update()
class PingData: class PingData:
@ -114,12 +116,13 @@ class PingData:
'ping', '-n', '-q', '-c', str(self._count), '-W1', 'ping', '-n', '-q', '-c', str(self._count), '-W1',
self._ip_address] self._ip_address]
def ping(self): async def ping(self):
"""Send ICMP echo request and return details if success.""" """Send ICMP echo request and return details if success."""
pinger = subprocess.Popen( pinger = await asyncio.create_subprocess_shell(
self._ping_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) ' '.join(self._ping_cmd), stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
try: try:
out = pinger.communicate() out = await pinger.communicate()
_LOGGER.debug("Output is %s", str(out)) _LOGGER.debug("Output is %s", str(out))
if sys.platform == 'win32': if sys.platform == 'win32':
match = WIN32_PING_MATCHER.search(str(out).split('\n')[-1]) match = WIN32_PING_MATCHER.search(str(out).split('\n')[-1])
@ -128,7 +131,8 @@ class PingData:
'min': rtt_min, 'min': rtt_min,
'avg': rtt_avg, 'avg': rtt_avg,
'max': rtt_max, 'max': rtt_max,
'mdev': ''} 'mdev': '',
}
if 'max/' not in str(out): if 'max/' not in str(out):
match = PING_MATCHER_BUSYBOX.search(str(out).split('\n')[-1]) match = PING_MATCHER_BUSYBOX.search(str(out).split('\n')[-1])
rtt_min, rtt_avg, rtt_max = match.groups() rtt_min, rtt_avg, rtt_max = match.groups()
@ -136,18 +140,20 @@ class PingData:
'min': rtt_min, 'min': rtt_min,
'avg': rtt_avg, 'avg': rtt_avg,
'max': rtt_max, 'max': rtt_max,
'mdev': ''} 'mdev': '',
}
match = PING_MATCHER.search(str(out).split('\n')[-1]) match = PING_MATCHER.search(str(out).split('\n')[-1])
rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups() rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups()
return { return {
'min': rtt_min, 'min': rtt_min,
'avg': rtt_avg, 'avg': rtt_avg,
'max': rtt_max, 'max': rtt_max,
'mdev': rtt_mdev} 'mdev': rtt_mdev,
}
except (subprocess.CalledProcessError, AttributeError): except (subprocess.CalledProcessError, AttributeError):
return False return False
def update(self): async def update(self):
"""Retrieve the latest details from the host.""" """Retrieve the latest details from the host."""
self.data = self.ping() self.data = await self.ping()
self.available = bool(self.data) self.available = bool(self.data)