- index.html: remove duplicated sections/IDs, restore card CSS, add fetch timeout and error handling, label relay and lithium type values - app.py: close inverter connection in finally, socket timeout, lock plus 2s cache, debug off, friendly missing-config error, HTTP 502 on failure - app.py: fix register scaling per Deye Modbus V118 (battery temp +1000 offset, charge efficiency 0.1%, block 5 off-by-one for 312-325) - read_registers.py: drop hard-coded IP/serial (env or config.py), use argparse type validators, unify INVERTER_SLAVE_ID, document limits - extract_pdf.py: main guard, argparse, output next to script, pypdf in docs/requirements.txt; pin requirements Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
"""Search a Deye Modbus manual PDF for specific register numbers.
|
|
|
|
Usage:
|
|
python docs/extract_pdf.py [--pdf PATH] [--registers 94 245 320] [--output PATH]
|
|
|
|
Requires pypdf (pip install -r docs/requirements.txt). By default the first
|
|
*.pdf in this folder is used and pdf_output.txt is written next to this script.
|
|
"""
|
|
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
try:
|
|
import pypdf
|
|
except ImportError:
|
|
sys.exit("ERROR: pypdf is required. Install with: pip install -r docs/requirements.txt")
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
def extract_text_from_pdf(pdf_path):
|
|
reader = pypdf.PdfReader(pdf_path)
|
|
return "\n".join((page.extract_text() or "") for page in reader.pages)
|
|
|
|
|
|
def find_default_pdf():
|
|
pdfs = sorted(glob.glob(os.path.join(HERE, "*.pdf")))
|
|
return pdfs[0] if pdfs else None
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
|
parser.add_argument("--pdf", default=find_default_pdf(), help="PDF manual (default: first *.pdf in docs/)")
|
|
parser.add_argument("--registers", nargs="+", type=int, default=[94, 245, 320], help="register numbers to find")
|
|
parser.add_argument("--output", default=os.path.join(HERE, "pdf_output.txt"), help="output file")
|
|
args = parser.parse_args()
|
|
|
|
if not args.pdf or not os.path.isfile(args.pdf):
|
|
sys.exit("ERROR: PDF not found. Pass --pdf PATH or place a PDF in docs/.")
|
|
|
|
print("Searching for registers...")
|
|
lines = extract_text_from_pdf(args.pdf).split("\n")
|
|
|
|
with open(args.output, "w", encoding="utf-8") as f:
|
|
for i, line in enumerate(lines):
|
|
for reg in args.registers:
|
|
if re.search(r"\b" + str(reg) + r"\b", line):
|
|
f.write(f"MATCH {reg}: {line.strip()}\n")
|
|
for j in range(max(0, i - 5), min(len(lines), i + 6)):
|
|
if j != i:
|
|
f.write(f" CTX: {lines[j].strip()}\n")
|
|
f.write("-" * 20 + "\n")
|
|
|
|
print(f"Done. Check {args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|