Orange pi zero, network by lan and ipv6 disabled.
My router is tp link c2600 and i don’t have any disconnections nor any other issues with it.
Could you please add an aditional device tracker using the same custom component (ping_arp) for your router? Something like this:
device_tracker:
- platform: ping_arp
count: 5
consider_home: 30
hosts:
iphone: <iphone ip>
router: <router ip>
and leave it for, lets say 24 hours, and then compare the history of your iphone and your router and check if the not_home moments of your iphone correspond with those of your router.
great idea, i’m not home for some days but i will tell you if it worked. thanks
Well I tried with 3 iPhones on a similar router (tp link C3150) and all iphones got their status “not_home” at the same moment…
So it looks like a router issue indeed. Any idea of what setting to change ?
try to set consider_home: 180
(3 minutes) and go decreasing this value till you get a consistent status
Hey please see this as it may help improve this component
Hi,
You may want to mention that you need to install “arp” otherwise you end up with an error “arp directory not found”.
On a Debian (hassbian, ubuntu etc) system it would be something like “sudo apt-get install net-tools nmap”.
I’ve just installed it and will see how the iOS devices perform over night.
Thanks for the share, much appreciated.
Simon
I set “consider_home” to 180 but it has no effect, my phone is still not home for 1 minutes, times to times.
What router do you have and what is your iOS version ?
it still don’t work for me as consider_home has no effect
Update :
I added my router to the component and it is always online, no disconnection. Whereas my iPhone disconnect times to times.
I made tests in 2 different house with 2 routers, 4 iPhones and 2 different HA system. Same issue. So I guess the bluetooth beacon is the only way to track iPhones.
Your custom_component Ping + Arp worked fine until HA 0.91.4.
From the HA 0.92.0b1 that does not work anymore. I get the following error message under “Check Configuration”: “Integration ping_arp not found when trying to verify its device_tracker platform.”
Can you please check that once?
Just need to create an empy file __init__.py
and it’ll be back working
is a manifest.json file needed?
I would say that it is not necessary
After upgrading to 0.94.0 I am getting
Platform not found: device_tracker.composite
Platform not found: device_tracker.ping_arp
when doing a configuration check, device trackers are not updated.
Me too, “Platform not found: device_tracker.ping_arp” after upgrading to 0.94.0.
Got it fixed by modifying device_tracker.py
"""
Tracks devices by sending a ICMP echo request (ping) and query arp table.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ping/
"""
import logging
import subprocess
import sys
import re
from datetime import timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.device_tracker import (
PLATFORM_SCHEMA)
from homeassistant.components.device_tracker.const import (
CONF_SCAN_INTERVAL, SCAN_INTERVAL, SOURCE_TYPE_ROUTER)
from homeassistant import util
from homeassistant import const
_LOGGER = logging.getLogger(__name__)
CONF_PING_COUNT = 'count'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(const.CONF_HOSTS): {cv.string: cv.string},
vol.Optional(CONF_PING_COUNT, default=1): cv.positive_int,
})
class Host:
"""Host object with ping detection."""
def __init__(self, ip_address, dev_id, hass, config):
"""Initialize the Host pinger."""
self.hass = hass
self.ip_address = ip_address
self.dev_id = dev_id
self._count = config[CONF_PING_COUNT]
self._ping_cmd = ['ping', '-n', '-q', '-c1', '-W1', self.ip_address]
self._parp_cmd = ['arp', '-n', self.ip_address]
def ping(self):
"""Send an ICMP echo request and return True if success."""
pinger = subprocess.Popen(self._ping_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
try:
pinger.communicate()
return pinger.returncode == 0
except subprocess.CalledProcessError:
return False
def parp(self):
"""Get the MAC address for a given IP."""
arp = subprocess.Popen(self._parp_cmd, stdout=subprocess.PIPE)
out, _ = arp.communicate()
match = re.search(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})', str(out))
if match:
return True
return False
def update(self, see):
"""Update device state by sending one or more ping messages."""
failed = 0
while failed < self._count: # check more times if host is unreachable
if self.ping():
see(dev_id=self.dev_id, source_type=SOURCE_TYPE_ROUTER)
_LOGGER.info("Ping OK from %s", self.ip_address)
return True
_LOGGER.info("No response from %s failed=%d", self.ip_address, failed)
if self.parp():
see(dev_id=self.dev_id, source_type=SOURCE_TYPE_ROUTER)
_LOGGER.info("Arp OK from %s", self.ip_address)
return True
_LOGGER.info("No MAC address found")
failed += 1
def setup_scanner(hass, config, see, discovery_info=None):
"""Set up the Host objects and return the update function."""
hosts = [Host(ip, dev_id, hass, config) for (dev_id, ip) in
config[const.CONF_HOSTS].items()]
interval = config.get(CONF_SCAN_INTERVAL, timedelta(seconds=len(hosts) * config[CONF_PING_COUNT]) + DEFAULT_SCAN_INTERVAL)
_LOGGER.info("Started ping tracker with interval=%s on hosts: %s", interval, ",".join([host.ip_address for host in hosts]))
def update_interval(now):
"""Update all the hosts on every interval time."""
try:
for host in hosts:
host.update(see)
finally:
hass.helpers.event.track_point_in_utc_time(
update_interval, util.dt.utcnow() + interval)
update_interval(None)
return True
Doesn’t work; devices do not show up in the integrations page…
Hi Anilet,
I had to change default_scan_interval to just scan_interval on line 87 to get it to start working. Thanks for posting, I would have never figured it out.
FYI…this is what works for me.
"""
Tracks devices by sending a ICMP echo request (ping) and query arp table.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ping/
"""
import logging
import subprocess
import sys
import re
from datetime import timedelta
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.components.device_tracker import (
PLATFORM_SCHEMA)
from homeassistant.components.device_tracker.const import (
CONF_SCAN_INTERVAL, SCAN_INTERVAL, SOURCE_TYPE_ROUTER)
from homeassistant import util
from homeassistant import const
_LOGGER = logging.getLogger(__name__)
CONF_PING_COUNT = 'count'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(const.CONF_HOSTS): {cv.string: cv.string},
vol.Optional(CONF_PING_COUNT, default=1): cv.positive_int,
})
class Host:
"""Host object with ping detection."""
def __init__(self, ip_address, dev_id, hass, config):
"""Initialize the Host pinger."""
self.hass = hass
self.ip_address = ip_address
self.dev_id = dev_id
self._count = config[CONF_PING_COUNT]
self._ping_cmd = ['ping', '-n', '-q', '-c1', '-W1', self.ip_address]
self._parp_cmd = ['arp', '-n', self.ip_address]
def ping(self):
"""Send an ICMP echo request and return True if success."""
pinger = subprocess.Popen(self._ping_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
try:
pinger.communicate()
return pinger.returncode == 0
except subprocess.CalledProcessError:
return False
def parp(self):
"""Get the MAC address for a given IP."""
arp = subprocess.Popen(self._parp_cmd, stdout=subprocess.PIPE)
out, _ = arp.communicate()
match = re.search(r'(([0-9A-Fa-f]{1,2}\:){5}[0-9A-Fa-f]{1,2})', str(out))
if match:
return True
return False
def update(self, see):
"""Update device state by sending one or more ping messages."""
failed = 0
while failed < self._count: # check more times if host is unreachable
if self.ping():
see(dev_id=self.dev_id, source_type=SOURCE_TYPE_ROUTER)
_LOGGER.info("Ping OK from %s", self.ip_address)
return True
_LOGGER.info("No response from %s failed=%d", self.ip_address, failed)
if self.parp():
see(dev_id=self.dev_id, source_type=SOURCE_TYPE_ROUTER)
_LOGGER.info("Arp OK from %s", self.ip_address)
return True
_LOGGER.info("No MAC address found")
failed += 1
def setup_scanner(hass, config, see, discovery_info=None):
"""Set up the Host objects and return the update function."""
hosts = [Host(ip, dev_id, hass, config) for (dev_id, ip) in
config[const.CONF_HOSTS].items()]
interval = config.get(CONF_SCAN_INTERVAL, timedelta(seconds=len(hosts) * config[CONF_PING_COUNT]) + SCAN_INTERVAL)
_LOGGER.info("Started ping tracker with interval=%s on hosts: %s", interval, ",".join([host.ip_address for host in hosts]))
def update_interval(now):
"""Update all the hosts on every interval time."""
try:
for host in hosts:
host.update(see)
finally:
hass.helpers.event.track_point_in_utc_time(
update_interval, util.dt.utcnow() + interval)
update_interval(None)
return True
@Twit HA restarted without error and I assumed everything working, anyway thanks for figuring it out.