from machine import I2C,Pin,RTC,Timer
import time,uio,dht,neopixel,json,os


#config
default_cycle_time = 100#ms
default_cycle_freq = 15#min
default_temp_freq = 15#min
default_temp_time = 5000#ms
off_time=(22,0)
on_time=(7,0)
off = False

fahrenheit = True

#status
mode = 0
unique = True

########################################
####       cfg                      ####
########################################

def load_cfg():
  f = open("conf.json",'r')
  t = f.read()
  conf = json.loads(t)
  default_cycle_time=conf["default_cycle_time"]
  default_cycle_freq=conf["default_cycle_freq"]
  default_temp_freq=conf["default_temp_freq"]
  default_temp_time=conf["default_temp_time"]
  cur_back_colour=conf["back_colour"]
  new_back_colour=conf["back_colour"]
  cur_bottle_colour=conf["bottle_colour"]
  new_bottle_colour=conf["bottle_colour"]
  fahrenheit=conf["fahrenheit"]
  off_time=(conf["off_time_h"],conf["off_time_m"])
  on_time=(conf["on_time_h"],conf["on_time_m"])

def check_cfg():
  if not 'conf.json' in os.listdir():
    print("Creating default config")
    default_cfg()

def default_cfg():
  conf = {}
  conf["default_cycle_time"] = 100
  conf["default_cycle_freq"] = 15
  conf["default_temp_freq"] = 5000
  conf["default_temp_time"] = 15
  conf["back_colour"] = 1
  conf["bottle_colour"] = 1
  conf["fahrenheit"] = 1
  conf["off_time_h"] = 22
  conf["off_time_m"] = 0
  conf["on_time_h"] = 7
  conf["on_time_m"] = 0
  j = json.dumps(conf)
  f = open("conf.json", 'w')
  f.write(j)
  f.close()


########################################
####       static                   ####
########################################
#numbers = { -1:b'\x02\x00\x00', 0:b'\x02\x00\x40', 1:b'\x02\x20\x00', 2:b'\x02\x40\x00', 3:b'\x02\x80\x00', 4:b'\x02\x00\x01', 5:b'\x02\x00\x02', 6:b'\x02\x00\x04', 7:b'\x02\x00\x08', 8:b'\x02\x00\x10', 9:b'\x02\x00\x20'}
numbers = { -1:b'\x02\x00\x00', 0:b'\x02\x00\x20', 1:b'\x02\x00\x40', 2:b'\x02\x10\x00', 3:b'\x02\x20\x00', 4:b'\x02\x40\x00', 5:b'\x02\x80\x00', 6:b'\x02\x00\x01', 7:b'\x02\x00\x02', 8:b'\x02\x00\x08', 9:b'\x02\x00\x10', -2:b'\x02\x00\x04', -3:b'\x02\x00\xff', -4:b'\x02\xff\x00', -5:'\x02\xff\xff'}
numbers_d = { -1:b'\x02\x00\x00', 0:b'\x02\x00\x24', 1:b'\x02\x00\x44', 2:b'\x02\x10\x04', 3:b'\x02\x20\x04', 4:b'\x02\x40\x04', 5:b'\x02\x80\x04', 6:b'\x02\x00\x05', 7:b'\x02\x00\x06', 8:b'\x02\x00\x0c', 9:b'\x02\x00\x14'}
colours = {0:(0,0,0),1:(100,100,100),2:(100,0,0),3:(0,100,0),4:(0,0,100),5:(100,100,0),6:(100,0,100),7:(0,0,100)}
bcolours = {0:(0,0,0,0),1:(100,100,100,0),2:(100,0,0,0),3:(0,100,0,0),4:(0,0,100,0),5:(100,100,0,0),6:(100,0,100,0),7:(0,0,100,0)}
colour_count = len(colours)


cur_back_colour = 0
new_back_colour = 0
cur_bottle_colour = 0
new_bottle_colour = 0

tubes = {1:32,2:33,3:34,4:35}

last = [1,3,3,7]

i2c = I2C(-1,Pin(25),Pin(33))
rtc = RTC()
rtc.datetime((2020,1,1,1,1,1,1,1)
timer = Timer(0)

btn1 = Pin(32, Pin.IN)
btn2 = Pin(27, Pin.IN)
btn3 = Pin(13, Pin.IN)
btn4 = Pin(4, Pin.IN)

backlight = neopixel.NeoPixel(Pin(16),8)
bottlelight = neopixel.NeoPixel(Pin(23),2,bpp=4)


########################################
####       func                     ####
########################################

def set_tube(tube,number):
  i2c.writeto(tubes[tube],numbers[number])
  last[tube-1] = number

def set_tube_d(tube,number):
  i2c.writeto(tubes[tube],numbers_d[number])
  last[tube-1] = number

def set_tube_all_d(n1,n2,n3,n4,d1,d2,d3,d4):
  if d1:
    set_tube_d(1,n1)
  else:
    set_tube(1,n1)

  if d2:
    set_tube_d(2,n2)
  else:
    set_tube(2,n2)

  if d3:
    set_tube_d(3,n3)
  else:
    set_tube(3,n3)

  if d4:
    set_tube_d(4,n4)
  else:
    set_tube(4,n4)
  

def set_tube_all(n1,n2,n3,n4):
  set_tube(1,n1)
  set_tube(2,n2)
  set_tube(3,n3)
  set_tube(4,n4)

def set_off_all():
  for tube in range(1,5):
    set_off_tube(tube)

def set_off_tube(tube):
  set_tube(tube,-1)

def cycle_to_reset(tube,value,delay):
  set_off_tube(tube)
  for c in range(0,value+1):
    set_tube(tube,c)
    time.sleep_ms(delay)

def cycle_to_all_reset(n1,n2,n3,n4,delay):
    set_off_all()
    cycle_to(1,n1,delay)
    cycle_to(2,n2,delay)
    cycle_to(3,n3,delay)
    cycle_to(4,n4,delay)

def cycle_to(tube, value, delay):
  c = last[tube-1]
  while c != value:
    c += 1
    if c > 9:
      c = 0
    set_tube(tube,c)
    time.sleep_ms(delay)

def cycle_to_all(n1,n2,n3,n4,delay):
    cycle_to(1,n1,delay)
    cycle_to(2,n2,delay)
    cycle_to(3,n3,delay)
    cycle_to(4,n4,delay)

def cycle_tube(tube, delay):
  l = last[tube-1]
  c = l+1
  while c != l:
    if c > 9:
      c = -1
    set_tube(tube,c)
    c += 1
    time.sleep_ms(delay)
  set_tube(tube,l)

def cycle_tube_all(delay):
  for tube in range(1,5):
    cycle_tube(tube,delay)

def cycle_delay(tube, delay):
  for number in range(0,10):
    set_tube(tube,number)
    time.sleep_ms(delay)
  set_tube(tube,-1)

def cycle_delay_all(delay):
  for tube in range(1,5):
    cycle_tube_delay(tube,delay)

def set_now():
  t = rtc.datetime()
  n = t[4]//10,t[4]%10,t[5]//10,t[5]%10
  if n[0]!=last[0] or n[1]!=last[1] or n[2]!=last[2] or n[3]!=last[3]:
    set_tube_all(t[4]//10,t[4]%10,t[5]//10,t[5]%10)

def cycle_now():
  t = rtc.datetime()
  n = t[4]//10,t[4]%10,t[5]//10,t[5]%10
  if n[0]!=last[0] or n[1]!=last[1] or n[2]!=last[2] or n[3]!=last[3]:
    cycle_to_all(t[4]//10,t[4]%10,t[5]//10,t[5]%10,default_cycle_time)

def set_now_and_cycle():
  t = rtc.datetime()
  n = t[4]//10,t[4]%10,t[5]//10,t[5]%10
  if n[0]!=last[0] or n[1]!=last[1] or n[2]!=last[2] or n[3]!=last[3]:
    set_tube_all(t[4]//10,t[4]%10,t[5]//10,t[5]%10)

########################################
####       backlight                ####
########################################

def set_backlight(colour):
  for i in range(0,8):
    backlight[i]=colours[colour]
  backlight.write()

def check_backlight():
  global new_back_colour
  global cur_back_colour
  global colour_count
  if new_back_colour > colour_count-1:
    new_back_colour = 0
  if new_back_colour < 0:
    new_back_colour = colour_count - 1
  if new_back_colour != cur_back_colour:
    set_backlight(new_back_colour)
    cur_back_colour = new_back_colour

########################################
####       bottlelight             ####
########################################

def set_bottlelight(colour):
  for i in range(0,2):
    bottlelight[i]=bcolours[colour]
  bottlelight.write()

def check_bottlelight():
  global new_bottle_colour
  global cur_bottle_colour
  global colour_count
  if new_bottle_colour > colour_count-1:
    new_bottle_colour = 0
  if new_bottle_colour < 0:
    new_bottle_colour = colour_count - 1
  if new_bottle_colour != cur_bottle_colour:
    set_bottlelight(new_bottle_colour)
    cur_bottle_colour = new_bottle_colour
 
########################################
####       clock                    ####
########################################

def timed():
  t = rtc.datetime()
  global off
  if not off:
    if not t[5]%default_cycle_freq:
      cycle_tube_all(default_cycle_time)
    if not t[5]%default_temp_freq:
      show_temp()
    if not t[5]%10:
      check_backlight()
      check_bottlelight()
  if t[4] == on_time[0] and t[5] == on_time[1]:
    off = False
  if t[4] == off_time[0] and t[5] == off_time[1]:
    off = True
  
     

def tick(timer):
  global off
  if not off:
    stop_time()
    set_now_and_cycle()
    start_time()
  timed()

def tick_set(time):
    if mode == 1:
      check_backlight()
    if mode == 2:
      check_bottlelight()
  
def start_time():
  timer.init(period=1000, mode=Timer.PERIODIC,callback=tick)

def start_set():
  timer.init(period=1000, mode=Timer.PERIODIC,callback=tick_set)

def stop_time():
  timer.deinit()


########################################
####       settings                 ####
########################################

#tr27
#br32
#tl13
#bl4

def modes():
  global mode
  if mode == 1:#backlight
    print("mode 1: backlight")
    set_tube_all(-1,-1,-1,-2)
  elif mode == 2:#bottlelight
    print("mode 2: bottlelight")
    set_tube_all(-1,-1,-2,-1)
  elif mode == 3:#year
    print("mode 3: year")
    set_tube_all(-1,-1,-2,-2)
  elif mode == 4:#month
    print("mode 4: month")
    set_tube_all(-1,-2,-1,-1)
  elif mode == 5:#day
    print("mode 5: day")
    set_tube_all(-1,-2,-1,-2)
  elif mode == 6:#hour
    print("mode 6: hour")
    set_tube_all(-1,-2,-2,-1)
  elif mode == 7:#min
    print("mode 7: minute")
    set_tube_all(-1,-2,-2,-2)
  else:
    mode = 0
    set_tube_all(-2,-2,-2,-2)
    start_time()

def callback(p):
  global mode
  des_buttons()
  trtc = RTC()
  if p==Pin(32):
    stop_time()
    start_set()
    mode -= 1
    modes()
    
  elif p==Pin(27):
    stop_time()
    start_set()
    mode += 1
    modes()

  elif p==Pin(13):
    if mode == 1:# backlight
      print("increasing backlight colour")
      global new_back_colour
      new_back_colour += 1
    elif mode == 2: #bottlelight:
      print("increasing bottlelight colour")
      global new_bottle_colour
      new_bottle_colour += 1 
    elif mode == 3: #year
      print("increasing year")
      n = trtc.datetime()
      nl = list(n)
      nl[0] = nl[0]+1
      n=tuple(nl)
      trtc.init(n)
      nt = str(n[0])
      print(n)
      set_tube_all_d(int(nt[0]),int(nt[1]),int(nt[2]),int(nt[3]),False,False,True,True)
    elif mode == 4: #month
      print("increasing month")
      n = trtc.datetime()
      nl = list(n)
      nl[1] = nl[1]+1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[1]//10,n[1]%10,n[2]//10,n[2]%10,False,True,False,False)
    elif mode == 5: #day
      print("increasing day")
      n = trtc.datetime()
      nl = list(n)
      nl[2] = nl[2]+1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[1]//10,n[1]%10,n[2]//10,n[2]%10,False,True,False,True)
    elif mode == 6: #hour
      print("increasing hour")
      n = trtc.datetime()
      nl = list(n)
      nl[4] = nl[4]+1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[4]//10,n[4]%10,n[5]//10,n[5]%10,False,True,True,False)
    elif mode == 7: #minute
      print("increasing minute")
      n = trtc.datetime()
      nl = list(n)
      nl[5] = nl[5]+1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[4]//10,n[4]%10,n[5]//10,n[5]%10,False,True,True,True)

  elif p==Pin(4):
    if mode == 1:# backlight
      print("decreasing backlight colour")
      global new_back_colour
      new_back_colour -= 1
    elif mode == 2: #bottlelight:
      print("decreasing bottlelight colour")
      global new_bottle_colour
      new_bottle_colour -= 1 
    elif mode == 3: #year
      print("decreasing year")
      n = trtc.datetime()
      nl = list(n)
      nl[0] = nl[0]-1
      n=tuple(nl)
      trtc.init(n)
      nt = str(n[0])
      print(n)
      set_tube_all_d(int(nt[0]),int(nt[1]),int(nt[2]),int(nt[3]),False,False,True,True)
    elif mode == 4: #month
      print("decreasing month")
      n = trtc.datetime()
      nl = list(n)
      nl[1] = nl[1]-1
      n=tuple(nl)
      trtc.init(n)
      nt = str(n[1])
      print(n)
      set_tube_all_d(n[1]//10,n[1]%10,n[2]//10,n[2]%10,False,True,False,False)
    elif mode == 5: #day
      print("decreasing day")
      n = trtc.datetime()
      nl = list(n)
      nl[2] = nl[2]-1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(-1,-1,n[2]//10,n[2]%10,False,True,False,True)
    elif mode == 6: #hour
      print("decreasing hour")
      n = trtc.datetime()
      nl = list(n)
      nl[4] = nl[4]-1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[4]//10,n[4]%10,n[5]//10,n[5]%10,True,True,True,False)
    elif mode == 7: #minute
      print("decreasing minute")
      n = trtc.datetime()
      nl = list(n)
      nl[5] = nl[5]-1
      n=tuple(nl)
      trtc.init(n)
      print(n)
      set_tube_all_d(n[4]//10,n[4]%10,n[5]//10,n[5]%10,False,True,True,True)

  else:
    print("No idea where that button came from!!")
    mode = 0
  init_buttons()

def des_buttons():
  global btn1
  global btn2
  global btn3
  global btn4
  btn1 = Pin(32, Pin.IN)
  btn2 = Pin(27, Pin.IN)
  btn3 = Pin(13, Pin.IN)
  btn4 = Pin(4, Pin.IN)

def init_buttons():
  global btn1
  global btn2
  global btn3
  global btn4
  btn1.irq(trigger=Pin.IRQ_FALLING, handler=callback)
  btn2.irq(trigger=Pin.IRQ_FALLING, handler=callback)
  btn3.irq(trigger=Pin.IRQ_FALLING, handler=callback)
  btn4.irq(trigger=Pin.IRQ_FALLING, handler=callback)

########################################
####       temp                     ####
########################################

def fahrenheit(celsius):
  return round(celsius * 1.8 + 32)

def show_temp():
  stop_time()
  sensor = dht.DHT11(Pin(26))
  sensor.measure()
  temp = sensor.temperature()
  if fahrenheit:
    temp = fahrenheit(temp)
  time.sleep_ms(100)
  print("fetched temperature " + str(temp))
  set_tube_all(-1,temp//100,temp//10,temp%10)
  time.sleep_ms(default_temp_time)
  start_time()
  

  


########################################
####       init                     ####
########################################

def tubes_init():
  for tube in tubes:
    #set output 1
    i2c.writeto(tubes[tube],b'\x06\x00')
    #set output 2
    i2c.writeto(tubes[tube],b'\x07\x00')  
  # disable all
  set_off_all()

def start():
  tubes_init()
  check_cfg()
  init_buttons()
  start_time()

########################################
####       :)                       ####
########################################

def help():
  print("Welcome to your 2019 Hacker Jeopardy prize!")

def f42():
  cycle_to_all(4,2,4,2,100)

def inception():
  f = uio.open("nixie.py")
  x = f.read()
  print(x)
  f.close()
