from machine import Pin, I2C, PWM, Timer
import ssd1306
import neopixel, time
import _thread
import random
import network
oled_iic = None
oled = None
np = None
SSID = '320_' # wifi名称
PWD = '00213922' # wifi密码
wlan = None
pwm_out = None
interruptCounter = None # 声明一个计数器
light_timer = Timer(0) # 创建一个定时器对象,用于定时开关灯
button_timer = Timer(1) # 用于定时扫描按键
colorful_thread = None
light_luminance = 0 # 灯的亮度
diy_number = 1
operating_buttons = ["up", "down", "enter(ok)", "exit"] # 进行手动修改时,只扫描这四个按键
global_buttons = ["mode_change", "enter(ok)"] # 其余时刻只扫描模式切换键
light_mode = ['Nor.', 'P.S.', 'BQ.', 'PT.'] # 灯光模式,从左到右依次为正常模式、节能模式、宴会模式和派对模式
buttons = {"up": None, "down": None, "mode_change": None, "enter(ok)": None, "exit": None, "blanket": None}
button_pin = {"up": 25, "down": 26, "mode_change": 32, "enter(ok)": 33, "exit": 18, "blanket": 19}
button_flag = {"up": False, "down": False, "mode_change": False, "enter(ok)": False, "exit": False, "blanket": False}
sys_flag = {"sys_mode": True, "light_mode": 0, "wifi": False, "upload": False, "person_detect": False,
"button_repeat": False, "light_status": False, "change_light_power": False, "change_light_mode": False,
"time_set": False, "diy_menu_change": False, "diy_refresh": False}
"""
!!!ATTENTION: sys_flag["light_status"]该标志位只能在light_or_shut_the_lights中更改,其他函数不许动
"""
timing_ = 0.0
# sys_mode为自动/手动模式切换,True表示自动,默认自动模式
# light_mode灯光模式的切换,见light_mode列表
"""
按键相关函数
"""
def button_init():
"""
初始化按键引脚
:return: None
"""
for i, j in zip(buttons, button_pin):
buttons[i] = Pin(button_pin[j], Pin.IN, Pin.PULL_UP)
def button_scan(scan_target):
"""
按下任一按键后,将sys_flag["button_repeat"]标识位转为True
等待另一线程refresh_button_repeat将该标识位转为False之后才继续扫描按键
按下按钮后,会将对应的按钮标识位置真,该标志位在发挥功能后被重新置假
:param scan_target: 扫描的目标,不同状态下会扫描不同的按钮,比如开机初始状态,只会扫描模式切换和确认两个按键。该参数传入列表对象
:return: None
"""
for i in scan_target:
# print(buttons[i])
if not buttons[i].value():
if not sys_flag["button_repeat"]:
if not buttons[i].value():
button_flag[i] = True
sys_flag["button_repeat"] = True
str_ = i + ": " + str(button_flag[i])
print(str_)
return str_
return ""
"""
oled内容显示组件(点、叉、指定范围清屏等)
"""
def change_main_point(i, j):
global oled
for x in range(2, 4): # 下点
for y in range(48, 50):
oled.pixel(x, y, i)
for x in range(2, 4): # 上点
for y in range(18, 20):
oled.pixel(x, y, j)
def change_child_point(which):
"""
手动模式子菜单中的菜单项前会有点,表示当前选中某一个项
本函数用于点亮某一个点
:param which: 传入0,1,2和3之中一个数字,表示点亮某一个点
:return: None
"""
num = {0: (0, 0, 0), 1: (1, 0, 0), 2: (0, 1, 0), 3: (0, 0, 1)}
if which not in num:
return "param error: the number must be in [1, 3]"
i, j, k = num[which]
for x in range(41, 43): # 第一个点
for y in range(13, 15):
oled.pixel(x, y, i)
for x in range(41, 43): # 第二个点
for y in range(33, 35):
oled.pixel(x, y, j)
for x in range(41, 43): # 第三个点
for y in range(53, 55):
oled.pixel(x, y, k)
oled.show()
def frame_clear(start_x=40, start_y=0, end_x=128, end_y=64):
"""
清除指定矩形区域内的屏幕,默认参数为清除竖线右侧的子菜单区域
"""
global oled
for x in range(start_x, end_x):
for y in range(start_y, end_y):
oled.pixel(x, y, 0)
oled.show()
def show_label(type, x, y):
global oled
if type: # 显示勾
x += 2
y += 3
for i in range(4):
oled.pixel(x + i, y + i, 1)
x += 4
y += 4
for i in range(7):
oled.pixel(x + i, y - i, 1)
else: # 显示叉
x += 3
for i in range(7):
oled.pixel(x + i, y + i, 1)
y += 6
for i in range(7):
oled.pixel(x + i, y - i, 1)
"""
界面构建和维持函数,会用到上方的oled内容显示组件
"""
def auto_frame():
print("auto frame")
"""
显示自动模式界面,在初始化和切换界面时只需调用一次
"""
global oled
frame_clear()
change_main_point(0, 1)
oled.text("set time", 40, 2)
# oled.text("-", 40, 12)
oled.show()
auto_refresh()
def auto_refresh():
"""
自动模式下,界面中需要刷新的四个选项,需要不断循环更新
需要改写:刷新前需要把原来的状态擦除
"""
# error
global oled
if sys_flag["time_set"]:
oled.text("%dm" % (timing_), 72, 12)
oled.text("wifi", 40, 25)
show_label(sys_flag["wifi"], 100, 25)
oled.text("upload", 40, 35)
show_label(sys_flag["upload"], 100, 35)
oled.text("person", 40, 45)
show_label(sys_flag["person_detect"], 100, 45)
oled.text("mode:", 40, 55)
oled.text(light_mode[sys_flag["light_mode"]], 95, 55)
oled.show()
def diy_frame():
print("diy frame")
global oled
frame_clear()
oled.text("Lumi: ", 45, 10)
oled.text("light: ", 45, 30)
oled.text("Mode: ", 45, 50)
oled.show()
change_main_point(1, 0)
oled.show()
def diy_refresh():
global light_luminance
switch_status = {"True": "ON", "False": "OFF"}
frame = {1: (95, 10, 128, 18), 2: (95, 30, 128, 38), 3: (95, 50, 128, 58)}
# frame_clear(95, 10, 110, 64)
# oled.text("Lumi", 50, 10)
if sys_flag["diy_refresh"]:
print("diy_number:" + str(diy_number))
if diy_number == 2 or diy_number == 1:
x1, y1, x2, y2 = frame[1]
frame_clear(x1, y1, x2, y2)
x1, y1, x2, y2 = frame[2]
frame_clear(x1, y1, x2, y2)
else:
x1, y1, x2, y2 = frame[3]
frame_clear(x1, y1, x2, y2)
sys_flag["diy_refresh"] = False
oled.text("%d" % (light_luminance), 95, 10)
# oled.text("light", 50, 30)
oled.text(switch_status[str(sys_flag["light_status"])], 95, 30)
# oled.text("Mode", 50, 50)
oled.text(light_mode[sys_flag["light_mode"]], 95, 50)
oled.show()
def refresh_screen():
if sys_flag["sys_mode"]:
auto_refresh()
else:
diy_refresh()
"""
逻辑函数
"""
def auto_diy_change():
sys_flag["sys_mode"] = bool(1 - sys_flag["sys_mode"])
if sys_flag["sys_mode"]:
auto_frame()
else:
diy_frame()
button_flag["mode_change"] = False # 功能完成后去除按键标志位状态
print("sys_flag[\"sys_mode\"]: " + str(sys_flag["sys_mode"]))
def time_setting():
"""
自动模式下进入子菜单选择,仅有一个菜单项即设定时间
:return: None
"""
global oled
global timing_
change_main_point(0, 0)
oled.text("-> 0m", 40, 12)
oled.show()
while button_flag["enter(ok)"]:
# print(timing_)
frame_clear(40, 12, 110, 22)
oled.text("-> %dm" % (timing_), 40, 12)
oled.show()
if button_flag["up"]:
timing_ += 1
if timing_ > 60:
timing_ = 60
button_flag["up"] = False
elif button_flag["down"]:
timing_ -= 1
if timing_ < 0:
timing_ = 0
button_flag["down"] = False
elif (not button_flag["enter(ok)"]) or button_scan(operating_buttons).find(
"enter(ok)") == 0: # 如果此处发现该标志位为False,只有一种可能,即按下了确认键
if timing_ > 0:
delay_to_do()
sys_flag["time_set"] = True
frame_clear(40, 12, 55, 22)
break
else:
frame_clear(40, 12, 110, 22)
elif button_flag["exit"]:
button_flag["exit"] = False
frame_clear(40, 12, 110, 22)
break
change_main_point(0, 1)
button_flag["enter(ok)"] = False
def lumi_adjust():
print("lumi_adjust")
global light_luminance
global oled
change_child_point(diy_number)
for i in range(30):
oled.pixel(93 + i, 20, 1)
while True:
refresh_screen()
if button_scan(operating_buttons).find("enter") == 0 or button_scan(operating_buttons).find(
"exit") == 0: # 如果确认键或退出键被按下,则退出本层循环
for i in range(30):
oled.pixel(93 + i, 20, 0)
break
if button_flag["up"]:
if light_luminance < 100:
sys_flag["diy_refresh"] = True
light_luminance += 1
button_flag["up"] = False
elif button_flag["down"]:
if light_luminance > 0:
sys_flag["diy_refresh"] = True
light_luminance -= 1
button_flag["down"] = False
light_or_shut_the_lights()
print("lumi_adjust quit")
def light_power_adjust():
print("light_power_adjust")
global oled
for i in range(30): # 画灯开关的下划线
oled.pixel(93 + i, 40, 1)
change_child_point(diy_number)
while True:
if button_scan(operating_buttons).find("enter") == 0 or button_scan(operating_buttons).find(
"exit") == 0: # 如果确认键或退出键被按下,则退出本层循环
for i in range(30):
oled.pixel(93 + i, 40, 0)
break
if button_flag["up"] or button_flag["down"]:
sys_flag["change_light_power"] = bool(1 - sys_flag["change_light_power"])
button_flag["up"] = False
button_flag["down"] = False
light_or_shut_the_lights()
sys_flag["diy_refresh"] = True
refresh_screen()
def light_mode_adjust():
print("light_mode_adjust")
global oled
for i in range(30):
oled.pixel(93 + i, 60, 1)
change_child_point(diy_number)
while True:
if button_scan(operating_buttons).find("enter") == 0 or button_scan(operating_buttons).find(
"exit") == 0: # 如果确认键或退出键被按下,则退出本层循环
for i in range(30):
oled.pixel(93 + i, 60, 0)
break
if button_flag["up"] or button_flag["down"]:
sys_flag["light_mode"] += 1
sys_flag["change_light_mode"] = True
if sys_flag["light_mode"] == 4:
sys_flag["light_mode"] = 0
button_flag["up"] = False
button_flag["down"] = False
light_or_shut_the_lights()
sys_flag["diy_refresh"] = True
refresh_screen()
def diy_menu_operating():
"""
手动模式下进行操作
:return: None
"""
print("diy_menu_operating")
global oled
global diy_number
diy_number = 1
change_main_point(0, 0)
change_child_point(diy_number)
button_flag["enter(ok)"] = False
while True: # 本层while循环,在手动模式中的一级菜单中上下选择,可随时退出
button_scan(operating_buttons)
change_child_point(diy_number)
refresh_screen()
if button_flag["up"]:
diy_number -= 1
button_flag["up"] = False
if button_flag["down"]:
diy_number += 1
button_flag["down"] = False
if diy_number < 1:
diy_number = 1
elif diy_number > 3:
diy_number = 3
if button_scan(operating_buttons).find("enter(ok)") == 0 and button_flag[
"enter(ok)"] is True: # 如果此时确认键被按下,表示要进入某一项菜单项进行手动调节
sys_flag["diy_refresh"] = True
triple_adjust[diy_number - 1]()
if button_flag["exit"]:
change_child_point(0)
change_main_point(1, 0)
button_flag["exit"] = False
button_flag["enter(ok)"] = False
break
def delay_to_do():
print("task set")
light_timer.init(period=60*1000, mode=Timer.PERIODIC, callback=timer_callback) # 周期性模式 开启定时器,定时半小时
def timer_callback(handle):
"""
定时设定后,每分钟执行一次,每次更新timing_的值,并同步更新oled屏幕的内容
当定时结束后,更新sys_flag["change_light_power"]的值,告诉系统需要改变灯的状态,并同步更新oled的内容
:return: None
"""
global timing_
global oled
timing_ -= 1
print("timing_: " + str(timing_))
if timing_ == 0:
sys_flag["change_light_power"] = True # 告诉系统灯的状态需要变化即可
sys_flag["time_set"] = False # 计时结束
frame_clear(40, 12, 110, 22)
oled.text("time out", 40, 12)
oled.show()
light_timer.deinit() # 定时结束,关掉定时器
elif timing_ > 0:
frame_clear(55, 12, 120, 22)
oled.text("%dm" % (timing_), 72, 12)
oled.show()
"""
灯光操作函数
"""
def action_shut_down_light():
"""
逐渐使灯变暗直到熄灭
:return: None
"""
global np
global light_luminance
for i in range(100, 0, -2): # 熄灭
light_luminance = i
np.write()
light_luminance = 0
for i in range(16):
np[i] = (0, 0, 0)
np.write()
def action_light_light(r, g, b):
"""
开灯的动作,会逐渐变亮
:param r: 红色值
:param g: 绿色值
:param b: 蓝色值
:return: None
"""
global np
global light_luminance
for i in range(16):
np[i] = (r, g, b)
np.write()
for i in range(0, 102, 2): # 点亮
light_luminance = i
np.write()
def colorful_lights():
"""
线程专用,RGB跑马灯
:return: None
"""
global np
while True:
if sys_flag["light_mode"] == 3:
for j in range(16):
temp = random.randint(1, 50)
for i in range(16):
np[i] = (255 - temp, j * 5, j * 10)
np.write()
#time.sleep(0.1)
#time.sleep(0.3)
def light_or_shut_the_lights():
"""
改变灯的开关状态或者改变灯的模式
:return:None
"""
global np
global colorful_thread
global light_luminance
if ((not sys_flag["light_status"]) and sys_flag["change_light_power"]) or ((not sys_flag["light_status"]) and light_luminance > 0): # 没开灯,并且灯的状态需要变化
# print(thread_ctl(False))
light_luminance = 0
np.write()
if sys_flag["light_mode"] == 0: # 正常模式,打开灯,缓慢变到最亮
action_light_light(255, 255, 255)
elif sys_flag["light_mode"] == 1: # 节能模式,根据环境光亮度调节
pass
elif sys_flag["light_mode"] == 2: # 宴会模式,开黄灯
action_light_light(234, 255, 0)
elif sys_flag["light_mode"] == 3: # 派对模式,开彩灯
pass
# print(thread_ctl())
sys_flag["change_light_power"] = False
sys_flag["light_status"] = True
elif (sys_flag["light_status"] and sys_flag["change_light_power"]) or (sys_flag["light_status"] and light_luminance == 0): # 开灯了并且灯的状态需要变化,则关灯
# print(thread_ctl(False))
action_shut_down_light()
sys_flag["change_light_power"] = False
sys_flag["light_status"] = False
elif sys_flag["light_status"] and sys_flag["change_light_mode"]: # 开了灯,但需要改变其模式
print("changing mode")
if sys_flag["light_mode"] == 0: # Nor. 先关灯,然后设定白色光最亮
action_shut_down_light()
# print(thread_ctl(False))
action_light_light(255, 255, 255)
time.sleep(0.5)
action_light_light(255, 255, 255)
elif sys_flag["light_mode"] == 1: # 节能模式,根据环境光亮度调节
pass
elif sys_flag["light_mode"] == 2: # BQ. 先关灯,然后设定黄光最亮
action_shut_down_light()
# print(thread_ctl(False))
action_light_light(234, 255, 0)
elif sys_flag["light_mode"] == 3: # PT. 先关灯,然后开启一个彩灯线程
pass
#action_shut_down_light()
# print(thread_ctl())
sys_flag["change_light_mode"] = False
sys_flag["light_status"] = True
def set_the_lum(): # 调节亮度
while True:
pwm_out.duty(light_luminance)
time.sleep(0.1)
"""
系统初始化函数
"""
def sys_init(oled_scl_pin=22, oled_sda_pin=21, ws2812_pin=15, pwm_pin=5):
global oled
global oled_iic
global np
global pwm_out
# 初始化oled
oled_iic = I2C(0, scl=Pin(oled_scl_pin), sda=Pin(oled_sda_pin), freq=400000)
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, oled_iic) # 得到oled对象
oled.fill(0) # 清除屏幕
oled.text("Aut", 9, 15) # 显示基本信息
oled.text("DIY", 9, 45)
for i in range(64): # 显示竖线
oled.pixel(35, i, 1)
oled.pixel(36, i, 1)
# oled.pixel(35, i, 1)
oled.show()
button_init() # 初始化按键引脚
pin = Pin(ws2812_pin, Pin.OUT)
# 以下参数不可更改:1、传递引脚;2、灯珠数量;3、设备几种颜色,3种或者4种;4、频率,0=400K,1=800KHz
np = neopixel.NeoPixel(pin, n=16, bpp=3, timing=1) # 得到灯珠列表
# PWM初始化
pwm_out = PWM(Pin(pwm_pin))
pwm_out.freq(1000)
auto_frame() # 默认自动模式
# wifi_connect()
if __name__ == "__main__":
sys_init()
sys_flag["change_light_power"] = True
light_luminance = 0
timing_ = 0
triple_adjust = [lumi_adjust, light_power_adjust, light_mode_adjust]
# time_fresh = _thread.start_new_thread(show_time, ())
# refresh_button = _thread.start_new_thread(refresh_button_repeat, ()) # 启动刷新扫描
button_timer.init(period=500, mode=Timer.PERIODIC,
callback=lambda t: sys_flag.__setitem__("button_repeat", False)) # 周期性模式 开启定时器
refresh_luminance_light = _thread.start_new_thread(set_the_lum, ()) # 启动灯光亮度刷新
colorful_thread = _thread.start_new_thread(colorful_lights, ())
while True: # 主线程死循环进行扫描
button_scan(global_buttons) # 只扫描模式切换键和确认键
if button_flag["up"]:
pass
elif button_flag["down"]:
pass
elif button_flag["mode_change"]:
auto_diy_change()
elif button_flag["enter(ok)"]:
if sys_flag["sys_mode"]: # 如果在自动模式下按确认键,则进入设置定时功能
time_setting()
else: # 否则进入手动模式下的功能设置
diy_menu_operating()
elif button_flag["exit"]:
pass
elif button_flag["blanket"]:
pass
refresh_screen()
light_or_shut_the_lights()