OpenWRT/appdaemon: Let appdaemon/home assistant see what's connected to your router without root

Hi,

I have been trying and failing to set up openwrt as a device tracker. Neither ubus nor luci worked (for some reason) and I wasn’t happy with giving Home Assistant root access to my router. Not that I distrust Home Assistant, but if I make a config error I don’t want to hand over my root password to my router.

What we’ll do: We will register a http endpoint in appdaemon and then use openwrt to send data to that appdaemon endpoint. I am confident this would work with with home assistant webhooks too, but I am using appdaemon.

I am using different interfaces for different purposes (br-lan.100, for example, are all personal devices). Make sure to edit the openwrt command to use your interface.

I wanted to keep this guide easy to follow so I’ll just show how to get the data into appdaemon. What you want to do with it is up to you then.

Appdaemon

app.py

import hassapi as hass
import globals

class OpenWRTDeviceTracker(hass.Hass):

    def initialize(self):
        self.register_endpoint(self.openwrt_cb, "openwrt")

    def openwrt_cb(self, data, kwargs):
        ips = data["ips"].split(",")
        self.log(f"data: {ips}")
        return "", 200



This registers an endpoint called openwrt. This is for demo purposes only, consider using a GUID so that attackers can’t just guess the endpoint and send data to your appdaemon.
After having received the data it prints the IPs it received from openwrt.

app.yaml

openwrt_device_tracker_lan100:
  module: app
  class: OpenWRTDeviceTracker

OpenWRT

It’s a one liner in a crontab, but here are the three parts it consists of:

Create a list of all IP adresses that are currently in the arp list of your router. arp-scan returns a number of IP adresses and awk turns them into a comma-separated string. If your interface is not called br-lan.100 rename it here.

lan100_ips=“$(arp-scan --interface=br-lan.100 --localnet --plain --quiet --format=‘${ip}’|awk 'BEGIN { ORS=”" } { print p $0; p=“,” } END { print “\n” }')"

Json-format the string:

ips_list={"ips":"$lan100_ips"}

Send the data to appdaemon. The openwrt used in the url is name of the endpoint registered using register_endpoint

uclient-fetch --post-data=$ips_list http://homeassistant.lan:5050/api/appdaemon/openwrt

Add this to your crontab using crontab -e like this.

* * * * * lan100_ips="$(arp-scan --interface=br-lan.100 --localnet --plain --quiet --format='${ip}'|awk 'BEGIN { ORS="" } { print p $0; p="," } END { print "\n" }')"&& ips_list={\"ips\":\"$lan100_ips\"} && uclient-fetch --post-data=$ips_list http://homeassistant.lan:5050/api/appdaemon/openwrt

That will run it every minute. Adjust according to your needs.

2 Likes

You could’ve used collectd (with mqtt) or ssh (with keys), which are safer alternatives if your concern is security.

Thanks, I’ll look into collectd, but if I use ssh somebody could still get a hold of the keys. That’s not the case here.