DD-WRT device_tracker multiplies known_devices entries

Hi,

I’m using the ddwrt component to track devices in my local network:

platform: ddwrt
host: 192.168.a.b
username: xxx
password: yyy

this works, but apparently all devices that are discovered that way are added to the known_devices.yaml file, regardless if they were already in there or not. This seems to happen when HA is restarted, maybe even at other times, too.
I just found over 50 instances of my fridge’s network interface in there…

This also means, I can’t manually assign attributes like name:, icon: etc. since it’s all superseded by another vanilla copy of the device entry on restart.

This looks like a bug to me - to my understanding, HA shouldn’t re-add a device that’s already in the known_devices file.

Sebastian

To clarify:

# date
Do 13. Jul 16:37:21 CEST 2017
# grep 68a86d2xxxx: known_devices.yaml  | wc -l
68
# docker restart hass
hass
# date
Do 13. Jul 16:37:41 CEST 2017
# sleep 60; grep 68a86d2xxxx: known_devices.yaml  | wc -l
69
# date
Do 13. Jul 16:38:57 CEST 2017

I had an issue like this but it turned out I corrupted the known_devices file by adding a blank in a name. HA would then stop reading the file and just add all devices to the end, over and over again.

Check your file and I think there was some warning in the log as well.

Thanks for that tip! I’ll look into it.

Sebastian

Ok, you were right!
Turning up the log level revealed some “duplicate entry” messages for the known_devices.yaml file.

I wrote a little python script to clean up the file. Maybe someone else finds it useful too:

#!/usr/bin/python3
#
# clean up duplicate entries from home-assistant's known_devices.yaml file
#

import sys
from collections import defaultdict

def main(known_devices_file):
  known_devices = defaultdict(dict);
  current_dev = None;

  # build the data structure; remove most if the identical dupes
  for line in open(known_devices_file, 'r'):
    if line.startswith('  '):
      try:
        (attr, value) = (line.rstrip().lstrip()).split(': ', 1)
      except:
        # attributes that don't have values set
        attr = line.rstrip(': \n').lstrip()
        value = ''
      if (attr == 'name' and not value.startswith('\'')):
        value = '\'' + value + '\''
      known_devices[current_dev][attr] = value
    else:
      current_dev = line.rstrip()


  # weed out duplicates of entries with custom names set
  keys_to_delete = set();
  for dev in known_devices.keys():
    dupelist = [];
    mac = known_devices[dev]['mac']
    if not mac == '':
      for otherdev in known_devices.keys():
        if (known_devices[otherdev]['mac'] == mac):
          dupelist.append(otherdev)
      if len(dupelist) > 1:
        # drop entries that only have names derived from mac address
        mac_name = mac.replace(':','').lower() + ':'
        dupelist.remove(mac_name)
        keys_to_delete.add(mac_name)
        if len(dupelist) > 1:
          print ('still having issues with this one: ' + dupelist)

  for key in keys_to_delete:
    del known_devices[key]

  for key in known_devices.keys():
    print(key)

if __name__ == "__main__":
    main(sys.argv[1])

Usage: cleanup_known_devices.py /PATH/TO/known_devices.yaml

The script will read the file and print out a cleaned up version of it to STDOUT, which can be redirected to a new known_devices.yaml file.

There’s not much error checking - use at own risk.

Sebastian