import time
import atexit
import board
import configparser
import RPi.GPIO as GPIO

from datetime import datetime
from adafruit_ht16k33.segments import Seg7x4

config = configparser.RawConfigParser()
config.read(r'./config.ini')

# Voltage Sersor
VOLTAGE_SENSOR_MODEL = config.get('voltage_sensor', 'MODEL')

# ADC configuration
CLK = int(config.get('adc', 'CLK'))
MISO = int(config.get('adc', 'MISO'))
MOSI = int(config.get('adc', 'MOSI'))
CS = int(config.get('adc', 'CS'))
CHANNEL = 0 # By default read sensor 0

# Display configuration
i2c = board.I2C()
display = Seg7x4(i2c)

# Button
BUTTON = int(config.get('button', 'BUTTON'))

# Function called on push button (change sensor)
def handlePushButton(button):
    global CHANNEL
    CHANNEL += 1
    if ( CHANNEL > 8 ):
        CHANNEL = 0

    display.print("  :"+str(CHANNEL)+"-")


# On exit
def handleExit():
    print("GoodBye!")
    display.print("--:--")
    time.sleep(2)
    display.fill(0)


# Init program
def init():
    # Set display
    display.brightness = 1
    display.blink_rate = 0 # Between 0 and 3

    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)

    GPIO.setup(BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(MOSI, GPIO.OUT)
    GPIO.setup(MISO, GPIO.IN)
    GPIO.setup(CLK, GPIO.OUT)
    GPIO.setup(CS, GPIO.OUT)

    # Add button event
    GPIO.add_event_detect(BUTTON, GPIO.FALLING, callback=handlePushButton, bouncetime=250)

    pass


# Convert value to volt
def convertToVoltage(value):
    correction = 1
    if ( VOLTAGE_SENSOR_MODEL == "arceli" ):
        correction = 2

    return value * ( 3.3 / 1024 ) * 5 / correction


# Convert volt to celcius value
def convertToCelcius(value):
    return ( ( 3300.0 / 1024.0 ) - 100.0 ) / 10.0 - 40.0


#read SPI data from MCP3008(or MCP3204) chip,8 possible adc's (0 thru 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if ((adcnum > 7) or (adcnum < 0)):
        return -1

    GPIO.output(cspin, True)
    GPIO.output(clockpin, False)  # start clock low
    GPIO.output(cspin, False)     # bring CS low

    commandout = adcnum
    commandout |= 0x18  # start bit + single-ended bit
    commandout <<= 3    # we only need to send 5 bits here
    for i in range(5):
        if (commandout & 0x80):
            GPIO.output(mosipin, True)
        else:
            GPIO.output(mosipin, False)

        commandout <<= 1
        GPIO.output(clockpin, True)
        GPIO.output(clockpin, False)

    adcout = 0

    # read in one empty bit, one null bit and 10 ADC bits
    for i in range(12):
        GPIO.output(clockpin, True)
        GPIO.output(clockpin, False)
        adcout <<= 1
        if (GPIO.input(misopin)):
            adcout |= 0x1

    GPIO.output(cspin, True)

    #adcout >>= 1       # first bit is 'null' so drop it
    return adcout


# Main programm
def main():
    init()
    time.sleep(2)
    print("Let's go!")

    while True:
        if ( CHANNEL == 8 ): # Last sensor => clock mode
            now = datetime.now()
            printableValue = now.strftime("%H:%M")
        else:
            # Get current sensor value
            ad_value = readadc(CHANNEL, CLK, MOSI, MISO, CS)
            value = 0

            # Convert value in readable Volt or Celcius
            if ( CHANNEL == 0 ):
                value = convertToVoltage(ad_value)
            else:
                value = convertToCelcius(ad_value)

            # Format value with 2 decimals
            printableValue = f"{value:.02f}"

        # Clear display
        display.fill(0)
        # Print new value
        display.print(str(printableValue))

        # Wait between next loop
        time.sleep(10)


atexit.register(handleExit)

if __name__ =='__main__':
    try:
        main()
    except KeyboardInterrupt:
        pass
