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