基于Lua框架下的合宙ESP32C3+1.5‘’Eink墨水屏天气时钟+OLED开源项目分享
基于Lua框架下的合宙ESP32C3+1.5‘’Eink墨水屏天气时钟+OLED项目分享
- 🎈相关篇《基于Lua框架下的合宙ESP32C3+1.5‘’Eink墨水屏天气时钟项目》
- ✨显示效果
- 📚OLED屏幕驱动采用的是U8g2库,理论上U8g2库支持的屏幕都可以支持,本篇只适配了
ssd1306
和sh1106
IIC
接口的屏幕。 - 🛠本项目使用的固件版本是:
LuatOS-SoC_V0004_ESP32C3.soc
固件和脚本烧写教程,请参考上面的相关篇,本篇只这对部分内容进行说明。
📖开源项目介绍
📑合宙ESP32C3 电子墨水屏 OLED+ATH10 网络天气时钟,整合了官方demo实现的.
合宙ESP32C3 墨水屏天气时钟
- 📌项目地址:
https://gitee.com/yingfumei96/ESP32C3
📢接线说明
0.96/1.3 ssd1306/sh1106 IIC OLED ----->ESP32C3
SDA ------>GPIO 4
SCL ------->GPIO 5
🌻字体修改
- 🌿资源包:https://gitee.com/openLuat/LuatOS
- 📗具体字体请参考:
LuatOS-master\components\luatfonts\luat_lib_fonts.c
{.name="unifont_t_symbols", .font=u8g2_font_unifont_t_symbols},
{.name="open_iconic_weather_6x_t", .font=u8g2_font_open_iconic_weather_6x_t},
{.name="opposansm8", .font=u8g2_font_opposansm8},
{.name="opposansm10", .font=u8g2_font_opposansm10},
{.name="opposansm12", .font=u8g2_font_opposansm12},
{.name="opposansm16", .font=u8g2_font_opposansm16},
{.name="opposansm20", .font=u8g2_font_opposansm20},
{.name="opposansm24", .font=u8g2_font_opposansm24},
{.name="opposansm32", .font=u8g2_font_opposansm32},
🌷需要修改的地方说明
local location = "101250303" --自己所在城市ID
- 📍国内城市编码表查询
链接: https://pan.baidu.com/s/16YqQBNhNfd-Lm1cFvVY1mQ?pwd=3pnj
提取码: 3pnj
- 📌需自己注册天气API
注册地址:
https://tianqiapi.com/
appid = "8979xx36"
appsecret = "OL8umxxP"
- 📋填写自己的WIFI信息
local wifiName,wifiPassword = "MERCURY_D268G","pba5ayzk"
🌼屏幕说明
-- 初始化硬件i2c的ssd1306/sh1106
-- ESP32C3 SDA:GPIO 4 ; SCL:GPIO 5
-- 如果使用的是 ssd1306 0.96寸OLED,下面改成ssd1306,sh1106 1.3寸屏幕
u8g2.begin({ic = "sh1106",direction = 0,mode="i2c_hw",i2c_id=0,i2c_speed = i2c.FAST}) -- direction 可选0 90 180 270
⛳固件和脚本烧录
📝main.lua内容代码
🔖本代码在原开源项目基础上做了修改,没有启用
ATH10
传感器,但是烧录脚本的时候需要添加进去。
PROJECT = "wifidemo"
VERSION = "1.0.0"
local sys = require "sys"
--添加硬狗防止程序卡死
if wdt then
wdt.init(15000)--初始化watchdog设置为15s
sys.timerLoopStart(wdt.feed, 10000)--10s喂一次狗
end
--需要自行填写的东西
--wifi信息
--定义是否使用I2C 的ATH10好 OLED,默认零打开,其余任何字符都是关闭,这里只要Oled_on 不为0 ,就关闭了后面的所有OLED的显示
local on = 0
local off = 1
--local ath10_on = on --加上ATH10 运存可能会不够,不需要就自己关了
local oled_on = on --I2C OLED屏幕,买的是ssd1306,不需要就自己关了
local eink_weather = on --水墨屏部分,不需要就自己关了,这里是按照合宙提供的方法解锁了IO11,没解锁的可以把水墨屏对应的针脚飞线插到别的地方,并且修改对应初始化代码即可
--水墨屏初始化调用函数
function elink_setup()
-- 水墨屏初始化API
--eink.setup(0, 2,11,10,6,7)
eink.setup(0, 2,11,10,6,7)
-- body
end
--地区id,请前往https://api.luatos.org/luatos-calendar/v1/check-city/查询自己所在位置的id
local location = "101250303" --城市ID
--天气接口信息,需要自己申请,具体参数请参考https://api.luatos.org/页面上的描述
local appid,appsecret = "",""
appid = "89795xx6"
appsecret = "OL8umxxP"
--定义WIFI的名称和密码
local wifiName,wifiPassword = "MERCURY_D268G","pba5ayzk"--填写自己的WIFI信息
local function connectWifi()
log.info("wlan", "wlan_init:", wlan.init())
wlan.setMode(wlan.STATION)
wlan.connect(wifiName,wifiPassword)
-- 等待连上路由,此时还没获取到ip
result, _ = sys.waitUntil("WLAN_STA_CONNECTED")
log.info("wlan", "WLAN_STA_CONNECTED", result)
-- 等到成功获取ip就代表连上局域网了
result, data = sys.waitUntil("IP_READY")
log.info("wlan", "IP_READY", result, data)
end
local function get_ntp_time()
ntp.settz("CST-8")
ntp.init("ntp.ntsc.ac.cn")
-- body
end
sys.subscribe(
"NTP_SYNC_DONE",
function()
log.info("ntp", "done")
log.info("date", os.date())
end
)
local function requestHttp()
local rd = {}
local httpc = esphttp.init(esphttp.GET, "http://apicn.luatos.org:23328/luatos-calendar/v1?mac=111&battery=10&location="..location.."&appid="..appid.."&appsecret="..appsecret)
if httpc then
local ok, err = esphttp.perform(httpc, true)
if ok then
while 1 do
local result, c, ret, data = sys.waitUntil("ESPHTTP_EVT", 20000)
--log.info("httpc", result, c, ret)
if c == httpc then
if esphttp.is_done(httpc, ret) then
break
end
if ret == esphttp.EVENT_ON_DATA and esphttp.status_code(httpc) == 200 then
table.insert(rd,data)
end
end
end
else
log.warn("esphttp", "bad perform", err)
end
esphttp.cleanup(httpc)
if ok then
return table.concat(rd)
end
end
end
local function refresh()
log.info("refresh","start!")
local data
for i=1,5 do
--重试最多五次
data = requestHttp()
if #data > 100 then
break
end
log.info("load fail","retry!")
end
if #data < 100 then
log.info("load fail","exit!")
return
end
eink.model(eink.MODEL_1in54)
-- log.info("eink.setup",eink.setup(0, 2,10,10,6,7))
-- log.info("eink.setup",eink.setup(0, 2,11,10,6,7))
log.info("eink.setup",elink_setup())
--elnk_start = elnk_start + 1
eink.setWin(200, 200, 2)--0代表不旋转,1,代表选择90度,2,代表选择180度
eink.clear(1)
log.info("eink", "end setup")
eink.drawXbm(0, 0, 200, 200, data)--Elink屏幕显示
-- 刷屏幕
eink.show()
eink.sleep()
log.info("refresh","done")
end
--这里用于后面I2C读值四舍五入,例如
--num1=(aht10_data.RH*100) --基于小米蓝牙温湿度计比对调的湿度原始数据+/-差异值或者直接修改传感器读取代码,确保串口和屏幕信息一致
--num2=(aht10_data.T) --基于小米蓝牙温湿度计比对调的温度原始数据+/-差异值或者直接修改传感器读取代码,确保串口和屏幕信息一致
--hum=keepDecimalTest(num1, 2)
--temp=keepDecimalTest(num2, 2)
local function keepDecimalTest(num, n)
if type(num) ~= "number" then
return num
end
-- n = n or 2
return string.format("%." .. n .. "f", num)
end
--[[sys.taskInit(function()
--先连wifi
connectWifi()
get_ntp_time()
while true do
refresh()
sys.wait(3600*1000)
--一小时刷新一次吧
end
end)
]]
if oled_on == 0 then
local TAG = "main"
-- 初始化显示屏
log.info(TAG, "init ssd1306/sh1106")
-- 初始化硬件i2c的ssd1306/sh1106
-- ESP32C3 SDA:GPIO 4 ; SCL:GPIO 5
-- 如果使用的是 ssd1306 0.96寸OLED,下面改成ssd1306,sh1106 1.3寸屏幕
u8g2.begin({ic = "sh1106",direction = 0,mode="i2c_hw",i2c_id=0,i2c_speed = i2c.FAST}) -- direction 可选0 90 180 270
-- 初始化软件i2c的ssd1306
-- u8g2.begin({ic = "ssd1306",direction = 0,mode="i2c_sw", i2c_scl=1, i2c_sda=4}) -- 通过PA1 SCL / PA4 SDA模拟
u8g2.SetFontMode(1)
u8g2.ClearBuffer()
u8g2.SetFont(u8g2.font_opposansm12)--字体大小:8,12,16,20,24,32
u8g2.DrawUTF8("Perseverance51", 3, 16)
--u8g2.SetFont(u8g2.font_opposansm12_chinese)
--u8g2.DrawUTF8("中文测试", 40, 38)
--u8g2.SetFont(u8g2.font_opposansm8_chinese)
u8g2.DrawUTF8("Hello World", 10, 42)
u8g2.SendBuffer()
end
--local aht10 = require "aht10"
if ath10_on == 0 then
aht10 = require "aht10"
i2cid = 0
i2c_speed = i2c.FAST
end
sys.taskInit(function()
--链接WIFI
rtc.set({year=2022,mon=10,day=16,hour=19,min=08,sec=43})
connectWifi()
--获取网络时间
get_ntp_time()
--加载天气图片到水墨屏
if eink_weather == 0 then
refresh()
end
local str_month1
local str_day
local str_month
local str_year
local str_time
local str_datetime2
local str_date
local str_week
local str_week1 = ""
local str_week2
local str_voidhour
local str_min
local num3 = 2
if ath10_on == 0 then
i2c.setup(i2cid,i2c_speed)
aht10.init(i2cid)
end -- sys.wait(2000)
while 1 do
sys.wait(50)
local str_datetime = os.date()
--log.info(str_datetime)--打印时间信息
str_week = string.sub(str_datetime,1,3)
str_month = string.sub(str_datetime,5,7)
str_day = string.sub(str_datetime,9,10)
if str_week == "Sun" then
str_week1 = "天"
str_week2 = 7
elseif str_week == "Mon" then
str_week1 = "一"
str_week2 = 1
elseif str_week == "Tue" then
str_week1 = "二"
str_week2 = 2
elseif str_week == "Wed" then
str_week1 = "三"
str_week2 = 3
elseif str_week == "Thu" then
str_week1 = "四"
str_week2 = 4
elseif str_week == "Fri" then
str_week1 = "五"
str_week2 = 5
elseif str_week == "Sat" then
str_week1 = "六"
str_week2 = 6
end
if(str_month=="Jan") then
str_month1 = "01"
elseif str_month == "Feb" then
str_month1 = "02"
elseif str_month == "Mar" then
str_month1 = "03"
elseif str_month == "Apr" then
str_month1 = "04"
elseif str_month == "May" then
str_month1 = "05"
elseif str_month == "Jun" then
str_month1 = "06"
elseif str_month == "Jul" then
str_month1 = "07"
elseif str_month == "Aug" then
str_month1 = "08"
elseif str_month == "Aep" then
str_month1 = "09"
elseif str_month == "Oct" then
str_month1 = "10"
elseif str_month == "Nov" then
str_month1 = "11"
elseif str_month == "Dec" then
str_month1 = "12"
end
str_year = string.sub(str_datetime,21,24)
str_time = string.sub(str_datetime,12,20)
-- log.info("输出:"..str_time)
str_voidhour = string.sub(str_datetime,15,19) --这里是截取时间数据里面的分和秒
str_min = string.sub(str_datetime,18,19) --截取秒
if ath10_on == 0 then
local aht10_data = aht10.get_data()
num1=(aht10_data.RH*100) --基于小米蓝牙温湿度计比对调的湿度原始数据+/-差异值或者直接修改传感器读取代码,确保串口和屏幕信息一致
num2=(aht10_data.T) --基于小米蓝牙温湿度计比对调的温度原始数据+/-差异值或者直接修改传感器读取代码,确保串口和屏幕信息一致
hum=keepDecimalTest(num1, 2)
temp=keepDecimalTest(num2, 2)
--u8g2.ClearBuffer() -- 清屏
--u8g2.SetFont(u8g2.font_opposansm12_chinese)
-- u8g2.SendBuffer()
end
-- 定义OLED刷新
if oled_on == 0 then
u8g2.ClearBuffer()
if ath10_on == 0 then
u8g2.SetFont(u8g2.font_opposansm8_chinese)
u8g2.DrawUTF8("温:"..temp.."C'", 0, 60)
u8g2.DrawUTF8("湿:"..hum.."%", 65,60)
--else
--u8g2.SetFont(u8g2.font_opposansm8)
--u8g2.DrawUTF8("U8g2+LuatOS", 30, 60)
end
sys.wait(50)
--u8g2.SetFont(u8g2.font_opposansm8_chinese)
u8g2.SetFont(u8g2.font_opposansm12)--字体大小:8,12,16,20,24,32
u8g2.DrawUTF8(str_year.."-"..str_month1.."-"..str_day.." "..str_week,2, 15)--OLED:2022-10-16 SUN显示位置
u8g2.SetFont(u8g2.font_opposansm16)--字体大小:8,12,16,20,24,32
-- u8g2.DrawUTF8("Week: "..str_week,5, 60)--星期显示位置
-- sys.wait(50)
u8g2.DrawUTF8(str_time,20, 52)
u8g2.SendBuffer()
end
--u8g2.SetFont(u8g2.font_opposansm12_chinese)
--u8g2.DrawUTF8("中文测试", 40, 38)
-- u8g2.SendBuffer()
-- 定义 水墨屏刷新的时间节点
if eink_weather == 0 then
-- if str_min == "59" then --可以每分钟刷新一次
if str_voidhour == "00:00" or str_voidhour == "30:00" then --每整点或者30分刷新一次
log.info("1小时准点刷新水墨屏天气")
log.info(str_year.." "..str_month1.." "..str_day..str_time..str_week1)
-- 后面的代码是为了限制水墨屏在一秒内刷新次数太多,造成RAM拥堵
num3 = num3 + 1
print("num3 = "..num3)
bbb = num3%3
if bbb == 0 then
num3 = 1
if oled_on == 0 then
u8g2.ClearBuffer()
u8g2.SetFont(u8g2.font_opposansm8_chinese)
u8g2.DrawUTF8(str_year.."-"..str_month1.."-"..str_day,30, 10)
sys.wait(50)
u8g2.DrawUTF8("天气更新中....",35, 35)
u8g2.DrawUTF8("星期"..str_week1,5, 60)
u8g2.SendBuffer()
end
collectgarbage("collect")
refresh()
end
end
end
-- lvgl.label_set_text(label_time,"#00CED1 "..str_year.."-"..str_month1.."-"..str_day.." ##00ff00 " ..str_time.."##90EE90 星期"..str_week1.."#")
sys.wait(50)
end
end)
sys.taskInit(function()
local LEDA = gpio.setup(12, 0, gpio.PULLUP) -- PE07输出模式,内部上拉
local LEDB = gpio.setup(13, 0, gpio.PULLUP) -- PE06输出模式,内部上拉
--local LEDC = gpio.setup(pin.PD15, 0, gpio.PULLUP) -- PB10输出模式,内部上拉
local count = 0
while 1 do
-- sys.wait(1000)
-- 一闪一闪亮晶晶
LEDA(0)
LEDB(1)
sys.wait(1000)
LEDA(1)
LEDB(0)
sys.wait(1000)
LEDA(1)
LEDB(1)
sys.wait(1000)
LEDA(0)
LEDB(0)
sys.wait(1000)
-- log.info("gpio", "Go Go Go", count, rtos.bsp())
-- count = count + 1
end
end)
-- 用户代码已结束-------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!