# Configure rtl_433_ESP decoders (enable or disable specific protocols). # # Newer rtl_433_ESP releases mark some decoders with `.disabled = 1` (e.g. # `esa_energy` since v0.6.x) and enable many noisy OOK decoders by default. # This script patches the decoder definitions inside the downloaded library in # .pio/libdeps// before compilation. # # Usage (in the environment section): # extra_scripts = # ${env.extra_scripts} # scripts/enable_rtl433_decoders.py # custom_rtl_433_enable_decoders = esa_energy # custom_rtl_433_disable_decoders = # skylink_motion # acurite_rain_896 # # Must run as a normal (post) script: lib_deps are installed while the platform # builder script runs, so a "pre:" script would not find the library on a clean # build. Sources are only compiled after all scripts have been read, and SCons # recompiles patched files because their content changed. import glob import os import re Import("env") def patch_decoders(libdeps_dir, enable_decoders, disable_decoders): """Patch `.disabled` for the given r_device names in rtl_433_ESP.""" device_files = glob.glob( os.path.join(libdeps_dir, "**", "src", "rtl_433", "devices", "*.c"), recursive=True, ) enable_status = {name: "not found" for name in enable_decoders} disable_status = {name: "not found" for name in disable_decoders} for path in device_files: with open(path, "r", encoding="utf-8", newline="") as f: content = f.read() changed = False for name in enable_decoders: block_re = re.compile( r"(r_device\s+(?:const\s+)?" + re.escape(name) + r"\s*=\s*\{)(.*?)(\};)", re.DOTALL, ) match = block_re.search(content) if not match: continue body = match.group(2) new_body, count = re.subn( r"(\.disabled\s*=\s*)[1-9]\d*", r"\g<1>0", body ) if count: content = content[: match.start(2)] + new_body + content[match.end(2) :] changed = True enable_status[name] = "enabled" else: enable_status[name] = "already enabled" for name in disable_decoders: block_re = re.compile( r"(r_device\s+(?:const\s+)?" + re.escape(name) + r"\s*=\s*\{)(.*?)(\};)", re.DOTALL, ) match = block_re.search(content) if not match: continue body = match.group(2) if re.search(r"\.disabled\s*=\s*[1-9]\d*", body): disable_status[name] = "already disabled" continue if re.search(r"\.disabled\s*=\s*0\b", body): new_body = re.sub(r"(\.disabled\s*=\s*)0\b", r"\g<1>1", body) else: nl = "\r\n" if "\r\n" in body else "\n" new_body, count = re.subn( r"([ \t]*\.fields\s*=)", r" .disabled = 1," + nl + r"\g<1>", body, count=1, ) if not count: new_body = body + " .disabled = 1," + nl content = content[: match.start(2)] + new_body + content[match.end(2) :] changed = True disable_status[name] = "disabled" if changed: with open(path, "w", encoding="utf-8", newline="") as f: f.write(content) return enable_status, disable_status enable_list = env.GetProjectOption("custom_rtl_433_enable_decoders", "").split() disable_list = env.GetProjectOption("custom_rtl_433_disable_decoders", "").split() if enable_list or disable_list: libdeps_dir = os.path.join(env.subst("$PROJECT_LIBDEPS_DIR"), env.subst("$PIOENV")) enable_status, disable_status = patch_decoders(libdeps_dir, enable_list, disable_list) for name, state in enable_status.items(): print("rtl_433_ESP decoder %s: %s" % (name, state)) for name, state in disable_status.items(): print("rtl_433_ESP decoder %s: %s" % (name, state)) missing = [ name for name, state in list(enable_status.items()) + list(disable_status.items()) if state == "not found" ] if missing: print( "Error: rtl_433_ESP decoder(s) not found in %s: %s" % (libdeps_dir, ", ".join(missing)) ) env.Exit(1)