infra/roles/hass-utils/files/clean_known_devices.py

122 lines
3.5 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import os
import yaml
def make_parser():
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--read-path", help="path to known_devices.yaml file to clean up", default="/var/lib/hass/home-assistant/config/known_devices.yaml")
parser.add_argument("-w", "--write-path", help="path to write cleaned known_devices.yaml file to")
return parser
def read_known_devices(kd_path):
try:
with open(kd_path, "r") as f:
return yaml.safe_load(f)
except yaml.scanner.ScannerError:
raise SystemExit(f"invalid yaml: '{kd_path}'")
except FileNotFoundError:
raise SystemExit(f"file not found: '{kd_path}'")
def write_cleaned_known_devices(ckd_path, cleaned_known_devices):
with open(ckd_path, "w") as f:
yaml.dump(cleaned_known_devices, f)
def is_mac_item(entity_id, device):
"""Used to identify entries like:
5b_0f_df_82_de_94:
name: 5B:0F:DF:82:DE:94
mac: BLE_5B:0F:DF:82:DE:94
icon:
picture:
track: true
the yaml dict key is the mac address, using '_', as a delimter,
and the 'name' key has the mac address, in upper case, using the
usual ':' delimeter for mac addresses.
the 'mac' key has the mac address prefixed with 'BLE_'.
entity_id: the yaml-dict key
friendly_name: the 'name' key of the yaml-dict
"""
return is_mac(entity_id, delimiter="_") or is_mac(device['name'])
def is_mac(s, delimiter=":"):
parts = s.split(delimiter)
return len(parts) == 6 and all(is_hex(a) for a in parts)
def is_hex(s):
try:
int(s, 16)
return True
except ValueError:
return False
def iter_clean_known_devices(known_devices):
for entity_id, device in known_devices.items():
if not is_mac_item(entity_id, device):
yield entity_id, device
def clean_known_devices(known_devices):
return dict(iter_clean_known_devices(known_devices))
def rename_known_device(entity_id, device):
tracker_types = ["BLE", "BT"]
friendly_name = device['name']
try:
tracker_type, mac = device['mac'].split("_", 1)
except ValueError:
pass
if tracker_type in tracker_types and is_mac(mac):
prefix = tracker_type.lower()
entity_id_parts = entity_id.split("_")
friendly_name_parts = friendly_name.split(" ")
if entity_id_parts[0].lower() != prefix:
new_entity_id = f"{prefix}_{entity_id}"
tracker_type_friendly_alts = [tracker_type, f"({tracker_type})", f"[{tracker_type}]"]
if not any(a.upper() in tracker_type_friendly_alts for a in friendly_name_parts):
new_friendly_name = f"{friendly_name} ({tracker_type})"
def main():
parser = make_parser()
args = parser.parse_args()
known_devices = read_known_devices(args.read_path)
print(f"known_devices.yaml: {len(known_devices)} devices")
cleaned_known_devices = clean_known_devices(known_devices)
print(f"cleaned known_devices.yaml: {len(cleaned_known_devices)} devices")
print(f"removed from known_devices.yaml: {len(known_devices) - len(cleaned_known_devices)} devices")
if args.write_path is not None:
write_cleaned_known_devices(args.write_path, cleaned_known_devices)
print(f"wrote cleaned known_devices.yaml to '{args.write_path}'")
#diff = set(known_devices) - set(cleaned_known_devices)
#for item in diff:
# import json
# print(json.dumps({item: known_devices[item]}, indent=2))
if __name__ == "__main__":
main()