scale_diag.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/env python3
  2. """NAU7802 Scale Diagnostic.
  3. Standalone diagnostic script — the NAU7802 driver lives in
  4. spoolbuddy/daemon/nau7802.py and is imported from there.
  5. """
  6. import logging
  7. import sys
  8. import time
  9. from pathlib import Path
  10. import smbus2
  11. # Add daemon package to sys.path so we can import the driver
  12. sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  13. from daemon.nau7802 import I2C_BUS, NAU7802, NAU7802_ADDR
  14. # Show driver debug output (init steps, etc.) during diagnostics
  15. logging.basicConfig(level=logging.DEBUG, format=" %(message)s")
  16. def main():
  17. print("=" * 60)
  18. print("NAU7802 Scale Diagnostic")
  19. print("=" * 60)
  20. print(f"Configured bus: {I2C_BUS}, address: 0x{NAU7802_ADDR:02X}")
  21. # Probe both common I2C buses and show where devices are actually visible.
  22. found_by_bus: dict[int, list[int]] = {}
  23. for bus_num in (0, 1):
  24. found_by_bus[bus_num] = []
  25. try:
  26. with smbus2.SMBus(bus_num) as probe_bus:
  27. for addr in range(0x03, 0x78):
  28. try:
  29. probe_bus.read_byte(addr)
  30. found_by_bus[bus_num].append(addr)
  31. except OSError:
  32. continue
  33. except FileNotFoundError:
  34. continue
  35. except PermissionError:
  36. continue
  37. for bus_num, addrs in found_by_bus.items():
  38. if addrs:
  39. pretty = " ".join(f"0x{a:02X}" for a in addrs)
  40. print(f"Bus {bus_num} devices: {pretty}")
  41. else:
  42. print(f"Bus {bus_num} devices: (none)")
  43. if NAU7802_ADDR not in found_by_bus.get(I2C_BUS, []):
  44. for alt in (1, 0):
  45. if alt != I2C_BUS and NAU7802_ADDR in found_by_bus.get(alt, []):
  46. print(f"\nHint: NAU7802 (0x{NAU7802_ADDR:02X}) appears on bus {alt}, not configured bus {I2C_BUS}.")
  47. print(f"Try: SPOOLBUDDY_I2C_BUS={alt} .../scale_diag.py")
  48. break
  49. scale = NAU7802()
  50. try:
  51. print("[1] Initializing...")
  52. scale.init()
  53. print(" Initialized OK")
  54. print("[2] Waiting for first reading...")
  55. for _ in range(200):
  56. if scale.data_ready():
  57. break
  58. time.sleep(0.010)
  59. else:
  60. print(" Timeout waiting for data ready")
  61. sys.exit(1)
  62. print("[3] Reading 10 samples (10 SPS = ~1 second)...")
  63. readings = []
  64. for i in range(10):
  65. # Wait for data ready
  66. for _ in range(200):
  67. if scale.data_ready():
  68. break
  69. time.sleep(0.010)
  70. raw = scale.read_raw()
  71. readings.append(raw)
  72. print(f" Sample {i + 1:2d}: {raw:>10d}")
  73. avg = sum(readings) / len(readings)
  74. spread = max(readings) - min(readings)
  75. print(f"\n Average: {avg:>10.0f}")
  76. print(f" Min: {min(readings):>10d}")
  77. print(f" Max: {max(readings):>10d}")
  78. print(f" Spread: {spread:>10d}")
  79. print("\n" + "=" * 60)
  80. print("Diagnostic complete!")
  81. print("=" * 60)
  82. except Exception as e:
  83. print(f"\nERROR: {e}")
  84. is_known_error = False
  85. if isinstance(e, OSError):
  86. if e.errno == 16: # Device or resource busy
  87. is_known_error = True
  88. print("\nI2C DEVICE BUSY (Errno 16): Another process is using the I2C bus.")
  89. print("This typically means the SpoolBuddy daemon is already reading the scale.")
  90. print("\nTo run this diagnostic, stop the daemon first:")
  91. print(" sudo systemctl stop bambuddy")
  92. print(" # Run diagnostic")
  93. print(" .../scale_diag.py")
  94. print(" # Restart daemon when done:")
  95. print(" sudo systemctl start bambuddy")
  96. elif e.errno == 121:
  97. is_known_error = True
  98. print("\nI2C NACK (Errno 121): the device did not acknowledge reads at 0x2A.")
  99. print("Check:")
  100. print(" - NAU7802 SDA/SCL are on the configured bus pins")
  101. print(" - 3.3V and GND are correct and stable")
  102. print(" - Sensor address is really 0x2A")
  103. print(" - No loose wire or swapped SDA/SCL")
  104. else:
  105. print(f"\nI2C Error (Errno {e.errno}): {e}")
  106. # Only print full traceback for unexpected errors
  107. if not is_known_error:
  108. import traceback
  109. traceback.print_exc()
  110. sys.exit(1)
  111. finally:
  112. scale.close()
  113. if __name__ == "__main__":
  114. main()