'''
oled温湿度报警,
可手动设定警戒值的报警装置,可以用于一些特定环境的温湿度控制
可以自己设定间隔时间
可以通过串口进行最高最低温度的设置等,省的设置一堆按钮显得乱
'''
from machine import Pin,PWM,I2C,Timer,UART
import time,machine,ssd1306,dht

uart1=UART(1,115200)    #调用串口uart1
uart1.init(115200,bits=8,parity=None,stop=1)   #初始化相关参数
Tim_S=Timer(0)   #定时器对象,很怪,有了这个定时器,下面的蜂鸣器没有了短促的鸣叫。。。。。
key=Pin(27, Pin.OUT)
Buzzer= PWM(key)   #定义蜂鸣器
Buzzer.duty(0)      #控制蜂鸣器初始关闭状态
global data
data = dht.DHT22(Pin(15))  #实例化15号管脚,21被占用了
i2c = I2C(0, scl=Pin(22), sda=Pin(21))   #对应管脚
oled_width = 128
oled_height = 64   #画幅大小
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)   #调用,设置像素大小
i=0
space=3000   #默认三秒,可修改但是要为整型
point=['','.','..','...']   #动态表示在工作
Warn_tem_Max=29.0
Warn_tem_Min=26.0   #可修改为浮点型
Warn_hum_Max=60.0
Warn_hum_Min=40.0
L_Blue=Pin(2,Pin.OUT)  #内置小灯,判断状态,命令设置成功闪亮

def Voice_On():   #开启调用
  Buzzer.duty(512)   #占空比
  Buzzer.freq(2000)    #频率
  time.sleep(0.5)
  Buzzer.duty(0)
  time.sleep(0.5)

def Voice_Off():     #关闭调用
  Buzzer.duty(0)   #蜂鸣器关闭

def Open_Test(t):
  data.measure()     #先调用测量函数,获取温湿度
  global temp
  temp=data.temperature()
  global humi
  humi=data.humidity()

def max_or_min():
  global tem_Max
  global tem_Min
  global hum_Max
  global hum_Min
  if int(temp)>tem_Max:
    tem_Max=int(temp)
  if int(temp)<tem_Min:
    tem_Min=int(temp)
  if int(humi)>hum_Max:
    hum_Max=int(humi)
  if int(humi)<tem_Max:
    hum_Min=int(humi)

def Print():
  global i
  oled.text('Temp:'+str(temp), 0, 12)
  oled.text('Max:'+str(tem_Max), 0, 26)    #空一段,最大最小
  oled.text('Min:'+str(tem_Min), 64, 26)
  oled.text('Humi:'+str(humi), 0,40)
  oled.text('Max:'+str(hum_Max), 0, 57)    
  oled.text('Min:'+str(hum_Min), 64, 57)
  oled.text('working'+point[i%4], 25, 0)
  oled.show()
  time.sleep(0.2)
  oled.fill(0)
  i=i+1

def Is_Int(Dir):   #异常处理。整型
  try:
    int(Dir)
    return True
  except ValueError:
    pass

def Is_Float(Dir):   #异常处理。浮点型
  try:
    float(Dir)
    return True
  except ValueError:
    pass

def twink():
  L_Blue.value(1)
  time.sleep(0.5)
  L_Blue.value(0)
  time.sleep(0.5)
  L_Blue.value(1)
  time.sleep(0.5)
  L_Blue.value(0)
  time.sleep(0.5)

oled.fill(0) #清屏
oled.text('Welcome!', 10, 10)   #欢迎界面   
oled.show()
time.sleep(0.5)
oled.fill(0) #清屏

Open_Test(0)  #先调用,才能全局改变下面的变量
Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
#效果是到定义的时间就调用函数收集一下数据,但是程序依然在运行,到主函数后会因为未到指定时间
#而不启用收集函数,导致主函数出错,所以需要在定时器之前先调用一下函数,
#还有种办法,可以通过延时来达到等待函数运行后再去显示数据,但是因为后续会有自定义收集间隔
#所以如果通过延时来处理还需要让延时时间变量与间隔相同
#time.sleep(n)

tem_Max=int(temp)  #控制空间,整数,大概
tem_Min=int(temp)
hum_Max=int(humi)
hum_Min=int(humi)

#主程序负责数据的对比,定时器外部中断优先,保障间隔的准确
while True:   #循环获取温湿度
  if Warn_tem_Min<temp<Warn_tem_Max and Warn_hum_Min<humi<Warn_hum_Max:
    Voice_Off()
  else:
    Voice_On()
  max_or_min()
  Print()
  #大概有几个口令:警报最大最小温度,湿度;采集时间间隔就这五个,
  #注意判断类型,命令或类型不正确的不予理会,设置成功有闪灯提醒
  if uart1.any()>0:   #考虑放在定时器中,因为循环内很难监测到
    Dir=uart1.read()
    Dir=str(Dir)     #转换为字符串型
#Dir=Dir.lower(),字符小写就涉及到回车的问题,无法转变,会异常,所以我可以提前切出来想要的部分
    Dir=Dir[2:-3]  #提前切掉b'...\n'这个东西,在让这个正常的字符串去变小写
    if Dir.find('space')>=0:
      Dir=Dir[5:]
      if Is_Int(Dir)==True:
        space=int(Dir)
        Tim_S.init(period=space,mode=Timer.PERIODIC,callback=Open_Test)
        twink()
    elif Dir.find('tmax')>=0:
      Dir=Dir[4:]
      if Is_Float(Dir)==True:
        Warn_tem_Max=float(Dir)
        twink()
    elif Dir.find('tmin')>=0:
      Dir=Dir[4:]
      if Is_Float(Dir)==True:
        Warn_tem_Min=float(Dir)
        twink()
    elif Dir.find('hmax')>=0:
      Dir=Dir[4:]
      if Is_Float(Dir)==True:
        Warn_hum_Max=float(Dir)
        twink()
    elif Dir.find('hmin')>=0:
      Dir=Dir[4:]
      if Is_Float(Dir)==True:
        Warn_hum_Min=float(Dir)
        twink()
#串口这部分也可以考虑写成函数,看起来能简洁些