Skip to content

Commit ffe88fe

Browse files
h2zeroh2zero
andauthored
[SYS] Add Blufi support (#1913)
* First build with IDF, tested with esp32dev-ble only. * Fix frameworks for non-esp32 boards * Add blufi support. * Adds an environment to use esp-idf and Arduino as a component to facilitate incorporating blufi for onboarding and configuration. --------- Co-authored-by: h2zero <[email protected]>
1 parent e55431a commit ffe88fe

14 files changed

+760
-9
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ jobs:
8181
- "esp32c3-m5stamp"
8282
- "thingpulse-espgateway"
8383
- "theengs-bridge"
84+
- "esp32dev-ble-idf"
8485
runs-on: ubuntu-latest
8586
name: Build with PlatformIO
8687
steps:
@@ -93,6 +94,7 @@ jobs:
9394
run: |
9495
python -m pip install --upgrade pip
9596
pip install platformio
97+
pip install setuptools
9698
- name: Extract ESP32 platform version from platformio.ini
9799
run: |
98100
ESP32_VERSION=$(grep 'esp32_platform\s*=' platformio.ini | cut -d'@' -f2 | tr -d '[:space:]')

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ node_modules
77
main/certs/private*
88
lib/*
99
!lib/esp32-bt-lib
10+
CMakeLists.txt
11+
dependencies.lock
12+
sdkconfig.*
13+
!sdkconfig.defaults

environments.ini

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,3 +1810,22 @@ build_flags =
18101810
; '-DsimplePublishing=true'
18111811
custom_description = BLE Gateway using ethernet or wifi with external antenna
18121812
custom_hardware = ThingPulse gateway single ESP32
1813+
1814+
[env:esp32dev-ble-idf]
1815+
platform = ${com.esp32_platform}
1816+
framework = arduino, espidf
1817+
board = esp32dev
1818+
extra_scripts = ${com-esp32.extra_scripts}
1819+
board_build.partitions = partitions/min_spiffs.csv
1820+
lib_deps =
1821+
${com-esp32.lib_deps}
1822+
${libraries.ble}
1823+
${libraries.decoder}
1824+
build_flags =
1825+
${com-esp32.build_flags}
1826+
'-DZgatewayBT="BT"'
1827+
'-DLED_SEND_RECEIVE=2'
1828+
'-DLED_SEND_RECEIVE_ON=0'
1829+
'-DGateway_Name="OMG_ESP32_BLE"'
1830+
'-DUSE_BLUFI=1'
1831+
custom_description = Regular BLE gateway with adaptive scanning activated, automatically adapts the scan parameters depending on your devices

main/Zblufi.ino

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
/*
2+
OpenMQTTGateway - ESP8266 or Arduino program for home automation
3+
4+
Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker
5+
Send and receiving command by MQTT
6+
7+
This program enables to:
8+
- receive MQTT data from a topic and send signal (RF, IR, BLE, GSM) corresponding to the received MQTT data
9+
- publish MQTT data to a different topic related to received signals (RF, IR, BLE, GSM)
10+
11+
Copyright: (c)Florian ROBERT
12+
13+
This file is part of OpenMQTTGateway.
14+
15+
OpenMQTTGateway is free software: you can redistribute it and/or modify
16+
it under the terms of the GNU General Public License as published by
17+
the Free Software Foundation, either version 3 of the License, or
18+
(at your option) any later version.
19+
20+
OpenMQTTGateway is distributed in the hope that it will be useful,
21+
but WITHOUT ANY WARRANTY; without even the implied warranty of
22+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+
GNU General Public License for more details.
24+
25+
You should have received a copy of the GNU General Public License
26+
along with this program. If not, see <http://www.gnu.org/licenses/>.
27+
*/
28+
#if defined(ESP32) && defined(USE_BLUFI)
29+
30+
# include "esp_blufi_api.h"
31+
32+
extern "C" {
33+
# include "esp_blufi.h"
34+
}
35+
36+
/* store the station info for send back to phone */
37+
//static bool gl_sta_connected = false;
38+
bool omg_blufi_ble_connected = false;
39+
static uint8_t gl_sta_bssid[6];
40+
static uint8_t gl_sta_ssid[32];
41+
static uint8_t gl_sta_passwd[64];
42+
static int gl_sta_ssid_len;
43+
static bool gl_sta_is_connecting = false;
44+
static esp_blufi_extra_info_t gl_sta_conn_info;
45+
46+
static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t* param);
47+
void wifi_event_handler(arduino_event_id_t event);
48+
esp_err_t blufi_security_init(void);
49+
void blufi_dh_negotiate_data_handler(uint8_t* data, int len, uint8_t** output_data, int* output_len, bool* need_free);
50+
int blufi_aes_encrypt(uint8_t iv8, uint8_t* crypt_data, int crypt_len);
51+
int blufi_aes_decrypt(uint8_t iv8, uint8_t* crypt_data, int crypt_len);
52+
uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t* data, int len);
53+
void blufi_security_deinit(void);
54+
55+
static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t* param) {
56+
/* actually, should post to blufi_task handle the procedure,
57+
* now, as a example, we do it more simply */
58+
switch (event) {
59+
case ESP_BLUFI_EVENT_INIT_FINISH:
60+
Log.notice(F("BLUFI init finish" CR));
61+
esp_blufi_adv_start();
62+
break;
63+
case ESP_BLUFI_EVENT_DEINIT_FINISH:
64+
Log.notice(F("BLUFI deinit finish" CR));
65+
NimBLEDevice::deinit(true);
66+
break;
67+
case ESP_BLUFI_EVENT_BLE_CONNECT:
68+
omg_blufi_ble_connected = true;
69+
esp_blufi_adv_stop();
70+
blufi_security_init();
71+
break;
72+
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
73+
omg_blufi_ble_connected = false;
74+
blufi_security_deinit();
75+
if (WiFi.isConnected()) {
76+
esp_blufi_deinit();
77+
} else {
78+
esp_blufi_adv_start();
79+
}
80+
break;
81+
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
82+
Log.notice(F("BLUFI requset wifi connect to AP" CR));
83+
WiFi.begin((char*)gl_sta_ssid, (char*)gl_sta_passwd);
84+
gl_sta_is_connecting = true;
85+
break;
86+
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
87+
Log.notice(F("BLUFI requset wifi disconnect from AP\n" CR));
88+
WiFi.disconnect();
89+
break;
90+
case ESP_BLUFI_EVENT_REPORT_ERROR:
91+
Log.notice(F("BLUFI report error, error code %d\n" CR), param->report_error.state);
92+
esp_blufi_send_error_info(param->report_error.state);
93+
break;
94+
case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {
95+
esp_blufi_extra_info_t info;
96+
if (WiFi.isConnected()) {
97+
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
98+
memcpy(info.sta_bssid, gl_sta_bssid, 6);
99+
info.sta_bssid_set = true;
100+
info.sta_ssid = gl_sta_ssid;
101+
info.sta_ssid_len = gl_sta_ssid_len;
102+
esp_blufi_send_wifi_conn_report(WIFI_MODE_STA, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
103+
} else if (gl_sta_is_connecting) {
104+
esp_blufi_send_wifi_conn_report(WIFI_MODE_STA, ESP_BLUFI_STA_CONNECTING, 0, &gl_sta_conn_info);
105+
} else {
106+
esp_blufi_send_wifi_conn_report(WIFI_MODE_STA, ESP_BLUFI_STA_CONN_FAIL, 0, &gl_sta_conn_info);
107+
}
108+
109+
break;
110+
}
111+
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
112+
esp_blufi_disconnect();
113+
break;
114+
case ESP_BLUFI_EVENT_RECV_STA_SSID:
115+
strncpy((char*)gl_sta_ssid, (char*)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
116+
gl_sta_ssid[param->sta_ssid.ssid_len] = '\0';
117+
Log.notice(F("Recv STA SSID %s" CR), gl_sta_ssid);
118+
break;
119+
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
120+
strncpy((char*)gl_sta_passwd, (char*)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
121+
gl_sta_passwd[param->sta_passwd.passwd_len] = '\0';
122+
Log.notice(F("Recv STA PASSWORD %s" CR), gl_sta_passwd);
123+
break;
124+
case ESP_BLUFI_EVENT_GET_WIFI_LIST: {
125+
WiFi.scanNetworks(true);
126+
break;
127+
}
128+
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA: {
129+
Log.notice(F("Recv Custom Data %" PRIu32 CR), param->custom_data.data_len);
130+
esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
131+
132+
DynamicJsonDocument json(1024);
133+
auto error = deserializeJson(json, param->custom_data.data);
134+
if (error) {
135+
Log.error(F("deserialize config failed: %s, buffer capacity: %u" CR), error.c_str(), json.capacity());
136+
break;
137+
}
138+
if (!json.isNull()) {
139+
Log.trace(F("\nparsed json, size: %u" CR), json.memoryUsage());
140+
if (json.containsKey("mqtt_server"))
141+
strcpy(mqtt_server, json["mqtt_server"]);
142+
if (json.containsKey("mqtt_port"))
143+
strcpy(mqtt_port, json["mqtt_port"]);
144+
if (json.containsKey("mqtt_user"))
145+
strcpy(mqtt_user, json["mqtt_user"]);
146+
if (json.containsKey("mqtt_pass"))
147+
strcpy(mqtt_pass, json["mqtt_pass"]);
148+
if (json.containsKey("mqtt_topic"))
149+
strcpy(mqtt_topic, json["mqtt_topic"]);
150+
if (json.containsKey("mqtt_broker_secure"))
151+
mqtt_secure = json["mqtt_broker_secure"].as<bool>();
152+
if (json.containsKey("gateway_name"))
153+
strcpy(gateway_name, json["gateway_name"]);
154+
saveConfig();
155+
}
156+
break;
157+
}
158+
case ESP_BLUFI_EVENT_RECV_USERNAME:
159+
break;
160+
case ESP_BLUFI_EVENT_RECV_CA_CERT:
161+
break;
162+
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
163+
break;
164+
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
165+
break;
166+
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
167+
break;
168+
;
169+
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
170+
break;
171+
default:
172+
break;
173+
}
174+
}
175+
176+
void wifi_event_handler(arduino_event_id_t event) {
177+
switch (event) {
178+
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
179+
case ARDUINO_EVENT_WIFI_STA_GOT_IP: {
180+
gl_sta_is_connecting = false;
181+
esp_blufi_extra_info_t info;
182+
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
183+
memcpy(info.sta_bssid, gl_sta_bssid, 6);
184+
info.sta_bssid_set = true;
185+
info.sta_ssid = gl_sta_ssid;
186+
info.sta_ssid_len = gl_sta_ssid_len;
187+
if (omg_blufi_ble_connected == true) {
188+
esp_blufi_send_wifi_conn_report(WIFI_MODE_STA, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
189+
}
190+
191+
break;
192+
}
193+
case ARDUINO_EVENT_WIFI_SCAN_DONE: {
194+
uint16_t apCount = WiFi.scanComplete();
195+
if (apCount == 0) {
196+
Log.notice(F("No AP found" CR));
197+
break;
198+
}
199+
wifi_ap_record_t* ap_list = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * apCount);
200+
if (!ap_list) {
201+
Log.error(F("malloc error, ap_list is NULL"));
202+
break;
203+
}
204+
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
205+
esp_blufi_ap_record_t* blufi_ap_list = (esp_blufi_ap_record_t*)malloc(apCount * sizeof(esp_blufi_ap_record_t));
206+
if (!blufi_ap_list) {
207+
if (ap_list) {
208+
free(ap_list);
209+
}
210+
Log.error(F("malloc error, blufi_ap_list is NULL" CR));
211+
break;
212+
}
213+
for (int i = 0; i < apCount; ++i) {
214+
blufi_ap_list[i].rssi = ap_list[i].rssi;
215+
memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
216+
}
217+
218+
if (omg_blufi_ble_connected == true) {
219+
esp_blufi_send_wifi_list(apCount, blufi_ap_list);
220+
}
221+
222+
free(ap_list);
223+
free(blufi_ap_list);
224+
break;
225+
}
226+
default:
227+
break;
228+
}
229+
return;
230+
}
231+
232+
static esp_blufi_callbacks_t example_callbacks = {
233+
.event_cb = example_event_callback,
234+
.negotiate_data_handler = blufi_dh_negotiate_data_handler,
235+
.encrypt_func = blufi_aes_encrypt,
236+
.decrypt_func = blufi_aes_decrypt,
237+
.checksum_func = blufi_crc_checksum,
238+
};
239+
240+
bool startBlufi() {
241+
esp_err_t ret = ESP_OK;
242+
WiFi.onEvent(wifi_event_handler);
243+
244+
ret = esp_blufi_register_callbacks(&example_callbacks);
245+
if (ret) {
246+
Log.error(F("%s blufi register failed, error code = %x" CR), __func__, ret);
247+
return false;
248+
}
249+
250+
if (NimBLEDevice::getInitialized()) {
251+
NimBLEDevice::deinit(true);
252+
delay(50);
253+
}
254+
esp_blufi_btc_init();
255+
uint8_t mac[6];
256+
esp_read_mac(mac, ESP_MAC_WIFI_STA);
257+
char advName[20] = {0};
258+
snprintf(advName, sizeof(advName), "OMGBFI_%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
259+
NimBLEDevice::init(advName);
260+
esp_blufi_gatt_svr_init();
261+
ble_gatts_start();
262+
return esp_blufi_profile_init() == ESP_OK;
263+
}
264+
265+
#endif // defined(ESP32) && defined(USE_BLUFI)

0 commit comments

Comments
 (0)