import smbus                      # Knihovna pro praci s I2C.
import time                       # Knihovna pro praci s casem.
import os                         # Knihovna pro pristup k systemovym prikazum (kvuli zjistovani teploty).
import sys                        # Knihovna pro pristup k argumentum prikazove radky pri spousteni programu


# ----------------  K O N S T A N T Y    P R O G R A M U ----------
# bus = smbus.SMBus(0)              # Starsi verze RasPi (256MB).
bus = smbus.SMBus(1)            # Novejsi verze RasPi (512MB).
addr = 0x60                     # I2C adresa ATtiny85.

# konstanty pro prepocet z teploty na PWM sirku signalu
pwm_min = 140  # minimalni vykon, pri kterem se dokaze ventilator jeste tocit (alespon trochu fouka)
tep_min = 33   # minimalni teplota, pri ktere se zacne ventilator tocit minimalnimi otackami (36 stupnu Celsia)
tep_max = 41   # teplota, od ktere uz ventilator bezi naplno (42 stupnu Celsia) 



# ------------------------ T E S T O V A C I   R E Z I M ------------------------------
#                              (rucne zadavane PWM)
#   Pri spusteni programu v prikazove radce:        sudo python /home/pi/ventilator.py -test
#
# Vyhodnoceni predavaneho parametru pri spousteni programu.
try:                          # Odchytavani chyby, ktera by vznikla pri chybejicim parametru.
  parametr = sys.argv[1]      # Parametr spousteneho programu do promenne.
except:                       # Kdyz parametr chybi, je nahrazen prazdnym retezcem.
  parametr=""

parametr = parametr.lower()   # Prevod parametru na mala pismena.

if (parametr == "-test" or parametr == "test"):       # kKyz je zadany parametr pri spusteni programu:
  print "Vyzkousej, jake PWM jeste dokaze bezpecne udrzet ventilator v chodu."
  while True:                         #  Nekonecna smycka. 
    pwm = input("Zadej PWM 0-255 (mimo cisel 1, 2, 3 nebo 4): ")
    if (pwm > 3 or pwm == 0):
      uspech = False                  # Znacka, jestli se podarilo odeslat prikaz ke zmene vykonu pres I2C.
      pokus = 0                       # Aktualni pocet chyb pri pokusech o komunikaci s ATtiny.
      while (pokus < 4 and uspech == False):  # Pokus o komunikaci se kvuli obcasnym chybam opakuje (max 4x)
    
        try:
          bus.write_byte(addr, pwm)   # Pak se posle do ventilatoru pozadovany vykon. 
          uspech = True               # Kdyz je komunikace v poradku, nastavi se znacka "uspech" a tim se ukonci 3 pokusy o komunikaci.
        except:
          pokus = pokus + 1           # Kdyz pri komunikaci dojde k chybe, zvetsi se pocitadlo chyb o 1. 
    
    
      if (pokus == 4):                # Kdyz pocitadlo chyb napocita do 4, znamena to nejakou zasadni chybu v komunikaci.
        print "Chyba v komunikaci s ATtiny."

# ---------------------     K O N E C  testovaciho rezimu  -----------------------






# -------------- P O D P R O G R A M Y    P R O    I2C    K O M U N I K A C I -------------------------------
def posli_i2c(adresa , bajt):
  # Pri vysoke PWM frekvenci v ATtiny (36kHz) obcas dochazi k problemum s komunikaci pres I2C,
  #     proto se v pripade problemu provadi pokus o komunikaci 4x.
  uspech = False                       # Znacka, jestli se podarilo odeslat prikaz ke zmene vykonu pres I2C.
  pokus = 0                            # Aktualni pocet chyb pri pokusech o komunikaci s ATtiny.
  while (pokus < 4 and uspech == False):

    try:
      bus.write_byte(adresa , bajt)    # Do ventilatoru posle pozadovany vykon. 
      uspech = True                    # Kdyz je komunikace v poradku, nastavi se znacka "uspech" a tim se ukonci 3 pokusy o komunikaci.

    except:
      pokus = pokus + 1                # Kdyz pri komunikaci dojde k chybe, zvetsi se pocitadlo chyb o 1. 


  if (pokus == 4):                     # Kdyz pocitadlo chyb napocita do 4, znamena to nejakou zasadni chybu v komunikaci.
    print "Chyba v komunikaci"


# ---------------------------------------------
def precti_i2c(adresa):
  # Pri vysoke PWM frekvenci v ATtiny (36kHz) obcas dochazi k problemum s komunikaci pres I2C,
  #     proto se v pripade problemu provadi pokus o komunikaci 4x.
  uspech = False                       # Znacka, jestli se podarilo odeslat prikaz ke zmene vykonu pres I2C.
  pokus = 0                            # Aktualni pocet chyb pri pokusech o komunikaci s ATtiny.
  while (pokus < 4 and uspech == False):

    try:
      navrat = bus.read_byte(adresa)   # zkusi precist hodnotu z I2C 
      uspech = True                    # Kdyz je komunikace v poradku, nastavi se znacka "uspech" a tim se ukonci 3 pokusy o komunikaci.

    except:
      pokus = pokus + 1                # Kdyz pri komunikaci dojde k chybe, zvetsi se pocitadlo chyb o 1. 


  if (pokus == 4):                     # Kdyz pocitadlo chyb napocita do 4, znamena to nejakou zasadni chybu v komunikaci.
    return 255                         # Dal do programu preda informaci, ze ventilator pravdepodobne stoji
  else:
    return navrat                      # Kdyz se podari nejakou hodnotu z I2C ziskat, tak ji preda dal do programu

# ---------------------------------------------





posli_i2c(addr,2)   # Prepne obvod ATtiny85 tak, aby na pozadani vracel stav LED (STOP ALARM).


while True:                       #  Nekonecna smycka. 

  # Zjisteni teploty procesoru (v tisicinach stupne Celsia) a uprava na stupne Celsia
  teplota = os.popen("cat /sys/class/thermal/thermal_zone0/temp").readline()  
  teplota = float(teplota) / 1000 

  if (teplota < tep_min): pwm = 0                   # Az do minimalni teploty ventilator stoji.
  if (teplota > tep_max): pwm = 255                 # Nad maximalni teplotou je ventilator spusteny naplno.

  if (teplota >= tep_min  and teplota <= tep_max):  # Mezi minimalni a maximalni teplotou probiha linearni vypocet PWM.
    pwm = int(((255 - pwm_min) * ((teplota - tep_min) / (tep_max - tep_min))) + pwm_min)


  print "teplota = " , teplota , "       PWM = " , pwm 


  posli_i2c(addr,pwm)             # Posle vypoctenou hodnotu PWM do ATtiny.

  time.sleep(5)                   # 10 sekund pauza pred zjistenim stavu LED (aby se ventilator stacil zastavit, nebo roztocit).
  print "     ... testuji stav ventilatoru ... "
  time.sleep(5) 

  led = precti_i2c(addr)          # Zjisti stav LED (ALARM STOP).

  # Vyhodnoceni LED
  if (led == 10):
    print "                 Ventilator se toci - vsechno OK."
  if (led == 20):
    print "                 Ventilator by se mel tocit, ale stoji - JE ZADRENY!"
  if (led == 30):
    print "                 Ventilator je zastaveny (vykon 0%) - OK"

  if (led != 10 and led != 20 and led != 30):
    print "Z ventilatoru byla prijata nejaka neocekavana data. (" + str(led) + ")" 
    print "Pokousim se resetovat komunikaci a nastavit vysilani stavu LED."
    posli_i2c(addr,2)   # Prepne obvod ATtiny85 tak, aby na pozadani vracel stav LED (STOP ALARM).

  print "----------------------------------------------------------------"

  time.sleep(10)                  # Dalsich 10 sekund pauza pred dalsim merenim teploty.

# Konec nekonecne smycky.

