Reputation: 455
Trying to send esp32 chip wifi credentials from android app (built with ionic). Using Ionic capacitor/bluetooth-le plug in to write to esp32, using the write function:
await BleClient.write(device.deviceId, GATT Service ID, Characteristic ID, textToDataView('wifi_ssid,wifi_password'));
Code for BleClient.write:
async write(deviceId: string, service: string, characteristic: string, value: DataView): Promise<void> {
service = validateUUID(service);
characteristic = validateUUID(characteristic);
return this.queue(async () => {
if (!value?.buffer) {
throw new Error('Invalid data.');
}
let writeValue: DataView | string = value;
if (Capacitor.getPlatform() !== 'web') {
// on native we can only write strings
writeValue = dataViewToHexString(value);
}
await BluetoothLe.write({
deviceId,
service,
characteristic,
value: writeValue,
});
});
}
How to pass wifi credentials as value
argument to the write
function so it's correctly received by ESP32?
On the ESP32 side, I'm using the wifi_prov_mgr example code, which in turn uses google protocol buffer (I'm very new to protobuf and don't really understand how it works). ESP uses wifi_config.c
(Espressif wifi_provisioning component). When I send wifi credentials from the app using BleClient.write, it shows up in wifi_config.c
as inbuf
with value wifi_ssid,wifi_password:��Z�?�Z�?
Here's the relevant code for wifi_config.c:
esp_err_t wifi_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data)
{
ESP_LOGI(TAG ,"Wifi config payload inbuf value: %s", inbuf);
WiFiConfigPayload *req;
WiFiConfigPayload resp;
esp_err_t ret;
req = wi_fi_config_payload__unpack(NULL, inlen, inbuf);
if (!req) {
ESP_LOGE(TAG, "Unable to unpack config data");
return ESP_ERR_INVALID_ARG;
}
I'm having a very hard time understanding how wi_fi_config_payload_unpack
processes the inbuf
argument. This is where the code gets into protobuf code generated by the proto files. The proto file for wifi config data looks like this:
message CmdSetConfig {
bytes ssid = 1;
bytes passphrase = 2;
bytes bssid = 3;
int32 channel = 4;
}
message WiFiConfigPayload {
WiFiConfigMsgType msg = 1;
oneof payload {
CmdGetStatus cmd_get_status = 10;
RespGetStatus resp_get_status = 11;
CmdSetConfig cmd_set_config = 12;
RespSetConfig resp_set_config = 13;
CmdApplyConfig cmd_apply_config = 14;
RespApplyConfig resp_apply_config = 15;
}
}
So my question is - how do I pass the wifi credentials in BleClient.write so it is correctly recognized by wifi_config.c on the ESP32 side?
I thought about using the Android app developed by Espressif to pass wifi credentials to the ESP32 chip, but then I don't know how to integrate native Android code with ionic code, since I need my app to do more than just credential the ESP32.
Upvotes: 1
Views: 759
Reputation: 455
Resolved this issue by using Google's protocol buffer code for javascript. Here's code that worked for me:
import * as goog from 'google-protobuf';
export class SetupPage implements OnInit {
messages = require('../../assets/proto-js/wifi_config_pb.js');
connectedDevice: BleDevice;
bleScan: any;
wifiSSID: Promise<any>;
scanResults: Promise<[]>;
wifiCredentials: string;
uint8String: Uint8Array;
buffer: Uint8Array;
ngOnInit() {
async getBLE(){
await BleClient.initialize();
var cmdSetMessage = new this.messages.CmdSetConfig();
var wifiConfigPayloadMessage = new this.messages.WiFiConfigPayload;
message.setSsid('wifiid');
message.setPassphrase('password');
wifiConfigPayloadMessage.setCmdSetConfig(cmdSetMessage);
wifiConfigPayloadMessage.setMsg(2); //this is ESP32 BLE specific
let bytesOfStuff = await wifiConfigPayloadMessage.serializeBinary();
this.connectedDevice = await BleClient.requestDevice();
await BleClient.connect(this.connectedDevice.deviceId);
BleClient.writeWithoutResponse(this.connectedDevice.deviceId, '021a9004-0382-
4aea-bff4-6b3f1c5adfb4', '021aff52-0382-4aea-bff4-6b3f1c5adfb4',
bytesOfStuff)
//After this, you need to send wifiConfigPayloadMessage.setMsg(4) to ESP32 to apply wifi credentials and connect to the selected wifi
}
}
Before this code can function, you need to install google-protobuf from npm or other package installer and protoc or another compiler for the proto files in order to generate pb.js files (since I'm working with javascript) for each proto file. In this example, the proto file is called wifi_config.proto, and the corresponding pb.js file (created by running protoc) is called wifi_config_pb.js.
Functions used to create the data to be transferred are defined in the pb.js files and correspond to objects defined in the proto files. The following references will help a lot if you don't have a good understanding of how this mechanism works:
https://developers.google.com/protocol-buffers/docs/proto3 (google protocol-buffer tutorial)
Protocol Buffers in Ionic (stack question)
Upvotes: 1