Ping + Arp custom_component device tracker

Hello @Cadish
please, where did you specify or modify to consider another iface in the code?

Just within your config:

 - platform: ping_arp
   count: 5
   scan_interval: 60
   iface: eno1
   hosts: 
       host1: 192.168.1.1
       host2: 192.168.1.2
1 Like

Thanks @Cadish, but you are talking and tested it on the ping_arp component

 of @JBelinchon,  or the ha_ping_arp component of @balrog???? 

Dear @Cadish, when i try to use ping_arp component in the last version of home assistant, I got the error message:
DEFAULT_SCAN_INTERVAL does not exist!
So I commented on this parameter to not be imported.

The iface option was also not active, so I set
CONF_IFACE = "iface"
vol.Optional (CONF_IFACE, default = ''): cv.string,
and
self._iface = config [CONF_IFACE]
self._parp_cmd = ['arp', '-n', self.ip_address, '-i', self._iface ]
and instead of passing the scan_interval parameter you have
to pass the interval_seconds parameter:

This is the custom component I’m using (I believe it’s the one of @rdehuyss)

"""
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'
CONF_IFACE = 'iface'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(const.CONF_HOSTS): {cv.string: cv.string},
    vol.Optional(CONF_PING_COUNT, default=1): cv.positive_int,
    vol.Optional(CONF_IFACE): cv.string,
})


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._iface = config[CONF_IFACE]

        if self._iface:
            self._ping_cmd = ['ping', '-I', self._iface, '-n', '-q', '-c1', '-W1', self.ip_address]
            self._parp_cmd = ['arp', '-i', self._iface, '-n', self.ip_address]
        else:
            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

Thanks, i will take a look

Hi, what is now the latest code which I can use for ping+arp function?

  • Can somebody give me some example of config…

Thank you for answer…

Hi Ronald @rdehuyss,

As my housemates and myself are using Android devices and I found the default ping integration not to be reliable, I want to give ā€˜your’ version with PING and ARP a try.

I already have a custom_components folder in my config folder. In the custom_components folder I made a subfolder called ā€˜ping_arp’. Inside are 2 files:
ini.py without any content and device_tracker.py where I copied / paste your code.
Furthermore in configuration.yaml I’v put:

  - platform: ping_arp
    count: 5
    consider_home: 180
    iface: eth1
    hosts:
      name1_ping_arp: 192.168.100.50
      name2_ping_arp: 192.168.100.51

When I check my configuration, before I want to restart I get an error:

Configuration invalid:
Platform error sensor.ping_arp - No module named 'custom_components.ping_arp.sensor'

I’m using HA OS core-2021.3.4

Could you please help me on the configuration to get it up and running?
How should work it? Will it create new entities ā€˜name1’ and ā€˜name2’ and will their state change between ā€˜home’ and ā€˜not_home’ based on the ping/arp result?

Thanks in advance!

remove the configuration for the ā€œplatform:ā€ and restart HA.

Then add the code for the ping_arp sensor back in.

tight now it is checking the code against things it has previously loaded but the new custom integration isn’t included in that since you never restarted HA after installing it so HA doesn’t know about it yet.

Hi, @finity,
Thanks for your reply,
I followed your instructions. After I removed ā€œplatform:ā€ from my configuration.yaml, the configuration check passed, with the 2 new files in custom_components/ping_arp folder.
I restarted HA and put back the ā€œplatform:ā€ in the configuration.yaml.
Checked once more the configuration and it gives the same error:

Platform error sensor.ping_arp - No module named 'custom_components.ping_arp.sensor'

from the error it seems you put the ping_arp code under the ā€œsensor:ā€ section of your configuration.yaml?

If so then you need to move it to the ā€œdevice_tracker:ā€ section.

Thanks, I forgot to put the code under device_tracker.
Could restart HA after a successfull configuration check.
I suspected to have 2 new entities but it seems it doesn’t work like that or the iface: xxx is incorrect.
I’m currently not at home so probably the interface is not correct named.
I have to check the correct name but I guess I’m not able to see that in the HA GUI.

@finity, thanks for your help once more.
I checked the interface in the HA command line and found enp0s3 as ethernet interface:
Schermafbeelding 2021-03-23 om 21.16.24

A strange name but I entered it in the config, restarted HA and had indeed the new entities. Tried by putting my phone in flightmode and… it worked. Me happy :wink:

2 Likes

I did as instructed. Added the py file to custom_components/ping_arp, rebooted. But if I try to add the config it errors saying the platform ping_arp is unrecognized.

You need a manifest.json file in the directory too now, here is my dummy one:

{
  "domain": "ping_arp",
  "name": "Ping ARP",
  "documentation": "https://www.example.com",
  "dependencies": [],
  "codeowners": [],
  "requirements": [],
  "iot_class": "local_polling",
  "version": "0.1.0"
}
1 Like

Just for anyone else’s benefit I’ve uploaded my working directory to https://github.com/jamespo/home-assistant

3 Likes

Hi all and @jamespo in particular. Many thanks for sharing your working directory. Could you also please share the lines in your configuration.yaml?

I keep getting the error message Platform error device_tracker.ping_arp - Integration ā€˜ping_arp’ not found, when testing my configuration.

I copied all your documents to the folder: /config/custom_components/ping_arp/

I hope anyone can help as this sounds like an interesting iphone tracker!

@ventusgallus

device_tracker:
  - platform: ping_arp
    count: 5
    scan_interval: 60
    iface: eth0
    hosts:
      7t: 192.168.0.137
      iphone: 192.168.0.146

It looks like everything is working well with the installation but I did not get any new device_track
I use this configuration :

device_tracker:
  - platform: ping_arp
    count: 5
    scan_interval: 60
    iface: eth0
    hosts:
        test: 192.168.1.113

@jamespo I’ve added your files to custom_components/ping_arp and restarted HA. Then when I add the device tracker to configuration.yaml when I check the configuration in developer tools before restarting I just get the below error:

Configuration Invalid: Platform error device_tracker.ping_arp - Integration 'ping_arp' not found.

configuration.yaml

  - platform: ping_arp
    count: 5
    scan_interval: 60
    iface: eno1
    hosts: 
      host1: 192.168.1.157