cat > ads_stream.py <<'PY' import sys, time, struct, smbus BUS=1; ADDR=0x48; REG_CONV=0x00; REG_CONFIG=0x01 bus = smbus.SMBus(BUS) # Continuous, AIN0, PGA ±4.096V, 860 SPS (chip-side) config = 0x8000 | 0x4000 | 0x0200 | 0x0000 | 0x00E0 | 0x0003 bus.write_i2c_block_data(ADDR, REG_CONFIG, [(config>>8)&0xFF, config&0xFF]) FS=4.096 def read_v(): raw = bus.read_word_data(ADDR, REG_CONV) raw = ((raw & 0xFF) << 8) | (raw >> 8) if raw & 0x8000: raw -= 1<<16 return raw * FS / 32768.0 # target: ~860 samples/sec (sleep to avoid pointless 3k reads of same value) TARGET_SPS = 860 dt = 1.0 / TARGET_SPS t_next = time.perf_counter() # binary: float32 volts pack = struct.Struct(" now: time.sleep(t_next - now) else: # if we fell behind, resync t_next = now PY cat > plot_stream.py <<'PY' import sys, struct, time from collections import deque import matplotlib.pyplot as plt WINDOW_SECONDS = 0.5 DISPLAY_SPS = 200 # plot points/sec (decimated) DRAW_FPS = 25 N = int(WINDOW_SECONDS * DISPLAY_SPS) ys = deque([0.0]*N, maxlen=N) xs = [i / DISPLAY_SPS for i in range(N)] plt.ion() fig, ax = plt.subplots() line, = ax.plot(xs, list(ys)) ax.set_title(f"ADS1115 AIN0 (streamed) {WINDOW_SECONDS}s window") ax.set_xlabel("Time (s)") ax.set_ylabel("Volts") ax.set_xlim(0, WINDOW_SECONDS) ax.set_ylim(-0.5, 3.5) unpack = struct.Struct("= 4: v = unpack(buf[:4])[0] del buf[:4] k += 1 if k % skip == 0: ys.append(v) now = time.perf_counter() if now - last_draw >= draw_interval: line.set_ydata(list(ys)) fig.canvas.draw_idle() plt.pause(0.001) last_draw = now PY