Use a unique id for each icmplib ping to avoid mixing unrelated responses (#39830)

This commit is contained in:
J. Nick Koston 2020-09-09 15:19:14 -05:00 committed by GitHub
parent b0b0b15d9d
commit b7ad83c655
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 12 deletions

View File

@ -1,4 +1,28 @@
"""The ping component.""" """The ping component."""
from homeassistant.core import callback
DOMAIN = "ping" DOMAIN = "ping"
PLATFORMS = ["binary_sensor"] PLATFORMS = ["binary_sensor"]
PING_ID = "ping_id"
DEFAULT_START_ID = 129
MAX_PING_ID = 65534
@callback
def async_get_next_ping_id(hass):
"""Find the next id to use in the outbound ping.
Must be called in async
"""
current_id = hass.data.setdefault(DOMAIN, {}).get(PING_ID, DEFAULT_START_ID)
if current_id == MAX_PING_ID:
next_id = DEFAULT_START_ID
else:
next_id = current_id + 1
hass.data[DOMAIN][PING_ID] = next_id
return next_id

View File

@ -1,6 +1,7 @@
"""Tracks the latency of a host by sending ICMP echo requests (ping).""" """Tracks the latency of a host by sending ICMP echo requests (ping)."""
import asyncio import asyncio
from datetime import timedelta from datetime import timedelta
from functools import partial
import logging import logging
import re import re
import sys import sys
@ -14,7 +15,7 @@ from homeassistant.const import CONF_HOST, CONF_NAME
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.reload import setup_reload_service from homeassistant.helpers.reload import setup_reload_service
from . import DOMAIN, PLATFORMS from . import DOMAIN, PLATFORMS, async_get_next_ping_id
from .const import PING_TIMEOUT from .const import PING_TIMEOUT
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -131,20 +132,28 @@ class PingData:
class PingDataICMPLib(PingData): class PingDataICMPLib(PingData):
"""The Class for handling the data retrieval using icmplib.""" """The Class for handling the data retrieval using icmplib."""
def ping(self):
"""Send ICMP echo request and return details."""
return icmp_ping(self._ip_address, count=self._count)
async def async_update(self) -> None: async def async_update(self) -> None:
"""Retrieve the latest details from the host.""" """Retrieve the latest details from the host."""
data = await self.hass.async_add_executor_job(self.ping) _LOGGER.warning("ping address: %s", self._ip_address)
data = await self.hass.async_add_executor_job(
partial(
icmp_ping,
self._ip_address,
count=self._count,
id=async_get_next_ping_id(self.hass),
)
)
self.available = data.is_alive
if not self.available:
self.data = False
return
self.data = { self.data = {
"min": data.min_rtt, "min": data.min_rtt,
"max": data.max_rtt, "max": data.max_rtt,
"avg": data.avg_rtt, "avg": data.avg_rtt,
"mdev": "", "mdev": "",
} }
self.available = data.is_alive
class PingDataSubProcess(PingData): class PingDataSubProcess(PingData):

View File

@ -15,8 +15,10 @@ from homeassistant.components.device_tracker.const import (
SOURCE_TYPE_ROUTER, SOURCE_TYPE_ROUTER,
) )
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.async_ import run_callback_threadsafe
from homeassistant.util.process import kill_subprocess from homeassistant.util.process import kill_subprocess
from . import async_get_next_ping_id
from .const import PING_ATTEMPTS_COUNT, PING_TIMEOUT from .const import PING_ATTEMPTS_COUNT, PING_TIMEOUT
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -76,15 +78,22 @@ class HostSubProcess:
class HostICMPLib: class HostICMPLib:
"""Host object with ping detection.""" """Host object with ping detection."""
def __init__(self, ip_address, dev_id, _, config): def __init__(self, ip_address, dev_id, hass, config):
"""Initialize the Host pinger.""" """Initialize the Host pinger."""
self.hass = hass
self.ip_address = ip_address self.ip_address = ip_address
self.dev_id = dev_id self.dev_id = dev_id
self._count = config[CONF_PING_COUNT] self._count = config[CONF_PING_COUNT]
def ping(self): def ping(self):
"""Send an ICMP echo request and return True if success.""" """Send an ICMP echo request and return True if success."""
return icmp_ping(self.ip_address, count=PING_ATTEMPTS_COUNT).is_alive next_id = run_callback_threadsafe(
self.hass.loop, async_get_next_ping_id, self.hass
).result()
return icmp_ping(
self.ip_address, count=PING_ATTEMPTS_COUNT, id=next_id
).is_alive
def update(self, see): def update(self, see):
"""Update device state by sending one or more ping messages.""" """Update device state by sending one or more ping messages."""

View File

@ -3,6 +3,6 @@
"name": "Ping (ICMP)", "name": "Ping (ICMP)",
"documentation": "https://www.home-assistant.io/integrations/ping", "documentation": "https://www.home-assistant.io/integrations/ping",
"codeowners": [], "codeowners": [],
"requirements": ["icmplib==1.1.1"], "requirements": ["icmplib==1.1.3"],
"quality_scale": "internal" "quality_scale": "internal"
} }

View File

@ -789,7 +789,7 @@ ibm-watson==4.0.1
ibmiotf==0.3.4 ibmiotf==0.3.4
# homeassistant.components.ping # homeassistant.components.ping
icmplib==1.1.1 icmplib==1.1.3
# homeassistant.components.iglo # homeassistant.components.iglo
iglo==1.2.7 iglo==1.2.7

View File

@ -392,7 +392,7 @@ huawei-lte-api==1.4.12
iaqualink==0.3.4 iaqualink==0.3.4
# homeassistant.components.ping # homeassistant.components.ping
icmplib==1.1.1 icmplib==1.1.3
# homeassistant.components.influxdb # homeassistant.components.influxdb
influxdb-client==1.8.0 influxdb-client==1.8.0