#!/usr/bin/env python3

##  Synopsis
##  ADS1115 lesen erstellt mit ChatGPT (ads_median.py) 
##  Auslesen der Werte AD Wandler ADS1115
##  Benötigt 12C    lauft daher am  PI  unter dem  System Python
##  Wandler  -30 bis +70grad
##  Ausgabe 0-10V   Spannungsteiler 15K zu 10K  Eingang 0-4V
##  Ausgabedatei in Ramdisk lt. CommandlIne Argument  ####
##  Version 1.1

import time
import statistics
import argparse
from datetime import datetime
from smbus2 import SMBus

# ----------------------------
# Konstanten
# ----------------------------
I2C_BUS = 1
I2C_ADDRESS = 0x48      # default, kann per CLI geändert werden
GAIN = 1
FS_VOLT = 4.096         # ±4.096 V bei Gain=1

# Spannungsteiler 15k/10k
DIV_K = 10.0 / (15.0 + 10.0)

# Temperaturbereich -30..70 °C
T_MIN = -30.0
T_MAX = 70.0

# ADS1115 Pointer
ADS1115_POINTER_CONVERT = 0x00
ADS1115_POINTER_CONFIG  = 0x01

GAIN_CONFIG = {
    2/3: 0x0000,
    1:   0x0200,
    2:   0x0400,
    4:   0x0600,
    8:   0x0800,
    16:  0x0A00
}

# Data Rate Bits für 16 SPS
SPS16 = 0x0020  # Bits 5-7 im Config-Register

# ----------------------------
# Einzelmessung
# ----------------------------
def read_ads1115(address, channel):
    if channel not in [0,1,2,3]:
        raise ValueError("channel 0..3")

    mux = 0x4000 | (channel << 12)

    config = 0x8000 | mux | GAIN_CONFIG[GAIN] | 0x0100 | SPS16 | 0x0003

    with SMBus(I2C_BUS) as bus:
        bus.write_i2c_block_data(address, ADS1115_POINTER_CONFIG,
                                 [(config>>8)&0xFF, config&0xFF])
        # ADS1115 Conversionszeit bei 16 SPS ≈ 62,5 ms
        time.sleep(0.065)
        data = bus.read_i2c_block_data(address, ADS1115_POINTER_CONVERT, 2)

    raw = (data[0]<<8) | data[1]
    if raw > 0x7FFF:
        raw -= 0x10000
    return raw

# ----------------------------
# Umrechnung
# ----------------------------
def raw_to_vadc(raw):
    return (raw / 32767.0) * FS_VOLT

def vadc_to_vin(vadc):
    return vadc / DIV_K

def vin_to_temp(vin):
    if vin <= 0: return T_MIN
    if vin >= 10: return T_MAX
    return T_MIN + (vin/10.0)*(T_MAX-T_MIN)

# ----------------------------
# Median über 15 Samples
# ----------------------------
def read_median(address, channel, samples=15):
    values = []
    for _ in range(samples):
        raw = read_ads1115(address, channel)
        vadc = raw_to_vadc(raw)
        vin = vadc_to_vin(vadc)
        values.append(vin)
    return statistics.median(values)

# ----------------------------
# CLI
# ----------------------------
def main():
    parser = argparse.ArgumentParser(description="ADS1115 reader mit Median 15, SPS16")
    parser.add_argument("address", type=lambda x: int(x,0), help="I2C Adresse, z.B. 0x48")
    parser.add_argument("channel", type=int, help="Kanal 0..3")
    parser.add_argument("-o","--outfile", type=str, help="Ausgabedatei")
    args = parser.parse_args()

    vin = read_median(args.address, args.channel)
    temp = vin_to_temp(vin)
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    #print(f"{temp:.1f}" )

    if args.outfile:
        ofile = args.outfile
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        ml = f"{timestamp},{temp:.1f}"                         # Ausgabe 1 Kommastelle
        try:
            with open(ofile, "w") as f:
                f.write(ml)
                print(ml)
        except Exception as e:
                print(f"Fehler beim Schreiben in {ofile}: {e}")        
            
          
            
if __name__ == "__main__":
    main()
