--[[ @module espblufi @summary espblufi esp blufi 蓝牙配网(注意:初版暂不支持加密功能!!!!!!!!) @version 1.0 @date 2025.07.01 @author Dozingfiretruck @usage -- 此为Blufi 配网库 -- BluFi 配网指南:https://www.espressif.com/sites/default/files/documentation/esp32_bluetooth_networking_user_guide_cn.pdf -- 安卓测试APP下载地址:https://github.com/EspressifApp/EspBlufiForAndroid/releases -- 安卓APP源码下载地址:https://github.com/EspressifApp/EspBlufiForAndroid -- IOS测试APP下载地址:https://apps.apple.com/cn/app/espblufi/id1450614082 -- IOSAPP源码下载地址:https://github.com/EspressifApp/EspBlufiForiOS -- 小程序测试:微信搜索小程序:ESP Config -- 小程序源码下载地址:https://github.com/EspressifApps/ESP-Config-WeChat -- 注意:初版暂不支持加密功能!!!!!!!! -- 用法实例 local espblufi = require("espblufi") local function espblufi_callback(event,data) if event == espblufi.EVENT_STA_INFO then for i, v in pairs(data) do print(i,v) end elseif event == espblufi.EVENT_SOFTAP_INFO then for i, v in pairs(data) do print(i,v) end elseif event == espblufi.EVENT_CUSTOM_DATA then espblufi.send_custom_data(data) end end sys.taskInit(function() local bluetooth_device = bluetooth.init() espblufi.init(bluetooth_device, espblufi_callback) espblufi.start() while 1 do sys.wait(1000) end end) ]] local espblufi = {} local sys = require "sys" local BLUFI_TOPIC = "espblufi" local BTC_BLUFI_GREAT_VER = 0x01 --Version + Subversion local BTC_BLUFI_SUB_VER = 0x03 --Version + Subversion local BTC_BLUFI_VERSION = ((BTC_BLUFI_GREAT_VER<<8)|BTC_BLUFI_SUB_VER) --Version + Subversion -- packet type local BLUFI_TYPE_MASK = 0x03 local BLUFI_TYPE_SHIFT = 0 local BLUFI_SUBTYPE_MASK = 0xFC local BLUFI_SUBTYPE_SHIFT = 2 local function BLUFI_GET_TYPE(type) return ((type) & BLUFI_TYPE_MASK) end local function BLUFI_GET_SUBTYPE(type) return (((type) & BLUFI_SUBTYPE_MASK) >>BLUFI_SUBTYPE_SHIFT) end local function BLUFI_BUILD_TYPE(type,subtype) return (((type) & BLUFI_TYPE_MASK) | ((subtype)<0 then blufi_env.softap_conn_num = blufi_env.softap_conn_num-1 end end) local function blufi_crc_checksum(data) return crypto.crc16("IBM",data) end local function blufi_send_encap(blufi_hdr_send) local send_data = string.char(blufi_hdr_send.type,blufi_hdr_send.fc,blufi_hdr_send.seq,#blufi_hdr_send.data) .. blufi_hdr_send.data if BLUFI_TYPE_IS_CTRL(blufi_hdr_send.type) then blufi_hdr_send.fc = blufi_hdr_send.fc|BLUFI_FC_CHECK send_data = send_data .. blufi_crc_checksum(send_data) end blufi_env.send_seq = blufi_env.send_seq + 1 blufi_env.ble_device:write_notify({uuid_service=string.fromHex(espblufi_uuid_service),uuid_characteristic=string.fromHex(espblufi_uuid2mobile)},send_data) end local function btc_blufi_send_encap(type,data) if blufi_env.ble_state == BLUFI_BLE_STATE_DISCONN then return end local blufi_hdr_send = {type=type,fc=0,seq=blufi_env.send_seq,data=data} blufi_send_encap(blufi_hdr_send) end local function btc_blufi_wifi_conn_report(sta_conn_state) local data = string.char(blufi_env.opmode,blufi_env.wlan_state,blufi_env.softap_conn_num) local wlan_info = wlan.getInfo() if wlan_info then if wlan_info.bssid then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID,6) .. string.fromHex(wlan_info.bssid) end if wlan_info.rssi then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_RSSI,1,wlan_info.rssi%256) end end if blufi_env.sta_ssid then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_SSID,#blufi_env.sta_ssid) .. blufi_env.sta_ssid end if blufi_env.sta_passwd then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD,#blufi_env.sta_passwd) .. blufi_env.sta_passwd end if blufi_env.softap_ssid then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID,#blufi_env.softap_ssid) .. blufi_env.softap_ssid end if blufi_env.softap_passwd then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD,#blufi_env.softap_passwd) .. blufi_env.softap_passwd end if blufi_env.softap_authmode then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE,1) .. blufi_env.softap_authmode end if blufi_env.softap_max_conn_num then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM,1) .. blufi_env.softap_max_conn_num end if blufi_env.softap_channel then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL,1) .. blufi_env.softap_channel end if blufi_env.sta_max_conn_retry then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_MAX_CONN_RETRY,1) .. blufi_env.sta_max_conn_retry end if blufi_env.sta_conn_end_reason then data = data .. string.char(BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_END_REASON,1) .. blufi_env.sta_conn_end_reason end btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_WIFI_REP), data); end local function btc_blufi_send_wifi_list(results) local data = "" for k,v in pairs(results) do data = data .. string.char(#v["ssid"]+1,v["rssi"]%256) .. v["ssid"] end btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_WIFI_LIST),data) end local function btc_blufi_send_ack(seq) btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_CTRL, BLUFI_TYPE_CTRL_SUBTYPE_ACK),string.char(seq)) end local function btc_blufi_send_error_info(state) btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_ERROR_INFO),string.char(state)) end local function btc_blufi_send_custom_data(data) btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_CUSTOM_DATA),data) end local SEC_TYPE_DH_PARAM_LEN = 0x00 local SEC_TYPE_DH_PARAM_DATA = 0x01 local SEC_TYPE_DH_P = 0x02 local SEC_TYPE_DH_G = 0x03 local SEC_TYPE_DH_PUBLIC = 0x04 local blufi_sec = {dh_param_len=0} local function blufi_dh_negotiate_data_handler(data) if #data<3 then btc_blufi_send_error_info(BLUFI_DATA_FORMAT_ERROR) end local type = data:byte(1) if type == SEC_TYPE_DH_PARAM_LEN then blufi_sec.dh_param_len = ((data:byte(2)<<8)|data:byte(3)); -- print("dh_param_len",blufi_sec.dh_param_len) elseif type == SEC_TYPE_DH_PARAM_DATA then -- print("SEC_TYPE_DH_PARAM_DATA") if #data < (blufi_sec.dh_param_len + 1) then btc_blufi_send_error_info(BLUFI_DH_PARAM_ERROR); return; end -- 秘钥待实现,功能需要mbedtls引出c接口 btc_blufi_send_error_info(BLUFI_INIT_SECURITY_ERROR); elseif type == SEC_TYPE_DH_P then print("SEC_TYPE_DH_P") elseif type == SEC_TYPE_DH_G then print("SEC_TYPE_DH_G") elseif type == SEC_TYPE_DH_PUBLIC then print("SEC_TYPE_DH_PUBLIC") end end local function btc_blufi_protocol_handler(parse_data) local target_data_len = 0 local parse_data_len = #parse_data if parse_data_len<4 then return end blufi_hdr.type,blufi_hdr.fc,blufi_hdr.seq,blufi_hdr.data_len = string.unpack('0 then if blufi_env.isfrag then blufi_hdr.data = blufi_hdr.data .. parse_data:sub(5) else blufi_hdr.data = parse_data:sub(5) end end if BLUFI_FC_IS_FRAG(blufi_hdr.fc) then blufi_env.isfrag = true return else blufi_env.isfrag = false end -- print(blufi_hdr.type,blufi_hdr.fc,blufi_hdr.seq,blufi_hdr.data_len) -- print(blufi_hdr.data,blufi_hdr.data:toHex()) local blufi_type = BLUFI_GET_TYPE(blufi_hdr.type) local blufi_subtype = BLUFI_GET_SUBTYPE(blufi_hdr.type) if blufi_type == BLUFI_TYPE_CTRL then if blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_ACK then elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_SET_SEC_MODE then blufi_env.sec_mode = blufi_hdr.data; elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_SET_WIFI_OPMODE then blufi_env.opmode = blufi_hdr.data:byte(1) elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_CONN_TO_AP then blufi_env.callback(espblufi.EVENT_STA_INFO, {ssid=blufi_env.sta_ssid,password=blufi_env.sta_passwd}) wlan.connect(blufi_env.sta_ssid, blufi_env.sta_passwd) blufi_env.wlan_state = BLUFI_WLAN_STATE_CONNING local results = sys.waitUntil("IP_READY",3000) if results then blufi_env.wlan_state = BLUFI_WLAN_STATE_CONNED else blufi_env.wlan_state = BLUFI_WLAN_STATE_DISCONN end btc_blufi_wifi_conn_report() elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_DISCONN_FROM_AP then wlan.disconnect() elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_STATUS then btc_blufi_wifi_conn_report() elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_DEAUTHENTICATE_STA then -- print("BLUFI_TYPE_CTRL_SUBTYPE_DEAUTHENTICATE_STA") elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_GET_VERSION then btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_REPLY_VERSION), string.char(BTC_BLUFI_GREAT_VER,BTC_BLUFI_SUB_VER)) elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_DISCONNECT_BLE then blufi_env.ble_device:disconnect() elseif blufi_subtype == BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_LIST then wlan.scan() sys.waitUntil("WLAN_SCAN_DONE", 15000) local results = wlan.scanResult() if results and #results>0 then btc_blufi_send_wifi_list(results) else btc_blufi_send_error_info(BLUFI_WIFI_SCAN_FAIL) end end elseif blufi_type == BLUFI_TYPE_DATA then if blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_NEG then local data = blufi_dh_negotiate_data_handler(blufi_hdr.data) if data then btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_NEG),data) end elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID then blufi_env.sta_bssid = blufi_hdr.data elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_STA_SSID then blufi_env.sta_ssid = blufi_hdr.data elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD then blufi_env.sta_passwd = blufi_hdr.data elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID then blufi_env.softap_ssid = blufi_hdr.data elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD then blufi_env.softap_passwd = blufi_hdr.data elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM then blufi_env.softap_max_conn_num = blufi_hdr.data:byte(1) elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE then blufi_env.softap_auth_mode = blufi_hdr.data:byte(1) blufi_env.callback(espblufi.EVENT_SOFTAP_INFO, {ssid=blufi_env.softap_ssid,password=blufi_env.softap_passwd,}) wlan.createAP(blufi_env.softap_ssid, blufi_env.softap_passwd,nil,nil,blufi_env.softap_max_channel,{max_conn = blufi_env.softap_max_conn_num}) elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL then blufi_env.softap_max_channel = blufi_hdr.data:byte(1) elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_USERNAME then -- print("BLUFI_TYPE_DATA_SUBTYPE_USERNAME") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_CA then -- print("BLUFI_TYPE_DATA_SUBTYPE_CA") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_CLIENT_CERT then -- print("BLUFI_TYPE_DATA_SUBTYPE_CLIENT_CERT") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SERVER_CERT then -- print("BLUFI_TYPE_DATA_SUBTYPE_SERVER_CERT") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_CLIENT_PRIV_KEY then -- print("BLUFI_TYPE_DATA_SUBTYPE_CLIENT_PRIV_KEY") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_SERVER_PRIV_KEY then -- print("BLUFI_TYPE_DATA_SUBTYPE_SERVER_PRIV_KEY") elseif blufi_subtype == BLUFI_TYPE_DATA_SUBTYPE_CUSTOM_DATA then blufi_env.callback(espblufi.EVENT_CUSTOM_DATA,blufi_hdr.data) end else return end end local function espblufi_task() while true do local result, event, data = sys.waitUntil(BLUFI_TOPIC) if result then if event == BLUFI_PROTOCOL_DATA then btc_blufi_protocol_handler(data) elseif event == BLUFI_TASK_EXIT then break end end end end local function espblufi_ble_callback(ble_device, ble_event, ble_param) if ble_event == ble.EVENT_CONN then blufi_env.ble_state = BLUFI_BLE_STATE_CONNED elseif ble_event == ble.EVENT_DISCONN then blufi_env.ble_state = BLUFI_BLE_STATE_DISCONN elseif ble_event == ble.EVENT_WRITE then sys.publish(BLUFI_TOPIC,BLUFI_PROTOCOL_DATA,ble_param.data) end end --[[ 初始化espblufi @api espblufi.init(bluetooth_device,espblufi_callback,local_name) @userdata bluetooth_device 蓝牙设备对象 @function 事件回调函数 @number 蓝牙名,可选,默认为"BLUFI_xxx",xxx为设备型号(因为esp的配网测试app默认过滤蓝牙名称为BLUFI_开头的设备进行显示,可手动修改) @usage espblufi.init(espblufi_callback) ]] function espblufi.init(bluetooth_device,espblufi_callback,local_name) if not bluetooth or not ble or not wlan then log.error("need bluetooth ble and wlan") return end if bluetooth_device == nil or type(bluetooth_device) ~= "userdata" then log.error("bluetooth_device is nil") return end if not espblufi_callback then log.error("espblufi_callback is nil") return else blufi_env.callback = espblufi_callback end if not local_name then local_name = "BLUFI_"..rtos.bsp() end wlan.init() local ble_device = bluetooth_device:ble(espblufi_ble_callback) ble_device:gatt_create(espblufi_att_db) ble_device:adv_create({ adv_data = {{ble.FLAGS,string.char(0x06)},{ble.COMPLETE_LOCAL_NAME, local_name}}, }) blufi_env.ble_device = ble_device return end --[[ 开始配网 @api espblufi.start() @usage espblufi.start() ]] function espblufi.start() sys.taskInit(espblufi_task) blufi_env.ble_device:adv_start() end --[[ 停止配网 @api espblufi.stop() @usage espblufi.stop() ]] function espblufi.stop() blufi_env.ble_device:adv_stop() sys.publish(BLUFI_TOPIC,BLUFI_TASK_EXIT) end function espblufi.deinit() end --[[ 发送自定义数据,一般用于接收到客户端发送的自定义命令后进行回复 @api espblufi.send_custom_data(data) @string 回复的数据包内容 @usage espblufi.send_custom_data(data) ]] function espblufi.send_custom_data(data) btc_blufi_send_custom_data(data) end return espblufi