lladam
July 2, 2025, 11:21pm
1
Hi all.
the APP and ESP32 connected but doesn't send the base64String, why?
thanks.
base64String:
/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAaABoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAdEAEAAgIDAQAAAAAAAAAAAAABAgMAEQQFITEy/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgT/xAAWEQEBAQAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhEDEQA/AL+AAD//Z
ABG
July 3, 2025, 1:57pm
2
Show us the responseContent.
I'll bet it's failing that if/then test.
1 Like
Thanks.
the attached shown all labels content.
ESP32 send 'take_picture' when pressed button.
ABG
July 3, 2025, 2:12pm
4
So responseContent was "idle", and the if/then test failed.
But what if it might have momentarily been different, and we missed it?
That calls for logging the incoming responseContent to a global list, and adding a List Picker to show that list on request.
1 Like
Thanks.
added List Picker got:
when button1 click:
ESP32 button pressed:
List Picker results:
new block:
ABG
July 3, 2025, 4:52pm
6
So that definitely established that the if/then was entered, and the POST was issued.
That changes the question to "What happened to the POST?"
I notice you are using Web1 Gets in a Clock Timer, and not stopping the Clock Timer from repeating when you do the POST.
Could the Clock Timer Gets be interfering with the Web1 POSTs?
Is there a completion event for Web1 POSts where you could catch the result, and turn the Timer back on?
1 Like
thanks for the good point.
I added Clock1.TimerEnabled = false before call web1.posttext, and true after received OK from ESP32.
still got :
[GET] /take_picture
Button Pressed → set takePictureFlag = true
[GET] /take_picture
[POST] /upload_picture
No plain arg received
[GET] /take_picture
why?
ABG
July 3, 2025, 9:22pm
8
If the esp is not responding (taking a picture?) it's time to read the esp code.
I don't see any in this thread.
P.S. Ever see a swim lane diagram?
They help explain back and forth communication.
1 Like
sure.
ESP32 code:
#include <WiFi.h>
#include <WebServer.h>
#include <TFT_eSPI.h>
#include <JPEGDecoder.h>
#include "mbedtls/base64.h"
TFT_eSPI tft = TFT_eSPI();
WebServer server(80);
const char* ssid = "ESP32_TEST";
const char* password = "12345678";
bool takePictureFlag = false;
void setup() {
SerialSettingS3();
delay(6000);
Serial.println("tttt");
// Button pin (BOOT on S3)
pinMode(0, INPUT_PULLUP);
WiFi.softAP(ssid, password);
IPAddress IP = WiFi.softAPIP();
Serial.println("AP IP: " + IP.toString());
tft.begin();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.drawString("📡 Waiting...", 10, 10, 2);
// Simple GET trigger
server.on("/take_picture", HTTP_GET, []() {
Serial.println("[GET] /take_picture");
if (takePictureFlag) {
server.send(200, "text/plain", "take_picture");
takePictureFlag = false;
} else {
server.send(200, "text/plain", "idle");
}
});
// Upload Base64 image
server.on("/upload_picture", HTTP_POST, []() {
Serial.println("[POST] /upload_picture");
if (server.hasArg("plain")) {
String body = server.arg("plain");
Serial.printf("📩 Received POST. Base64 length = %d\n", body.length());
displayBase64Image(body);
server.send(200, "text/plain", "OK");
} else {
Serial.println("❌ No plain arg received");
server.send(400, "text/plain", "Missing body");
}
});
server.begin();
Serial.println("✅ Web server started");
//SPIFFS.begin();
if (!SPIFFS.begin(true)) {
Serial.println("❌ SPIFFS Mount Failed"); tft.drawString("SPIFFS Fail!", 10, 50, 2);
return;
}
}
void loop() {
server.handleClient();
// Press BOOT button to trigger photo
if (digitalRead(0) == LOW) {
takePictureFlag = true;
Serial.println("📸 Button Pressed → set takePictureFlag = true");
delay(500);
}
}
void displayBase64Image(String base64Str) {
size_t input_len = base64Str.length();
size_t decoded_len;
unsigned char* jpeg_buf = (unsigned char*)malloc(input_len);
if (!jpeg_buf) {
Serial.println("❌ malloc failed");
return;
}
//........................
Serial.printf("📦 Incoming Base64 length: %d\n", input_len);
Serial.printf("📦 Free heap before decode: %d\n", ESP.getFreeHeap());
//........................
int res = mbedtls_base64_decode(jpeg_buf, input_len, &decoded_len,
(const unsigned char*)base64Str.c_str(), input_len);
//......................
Serial.printf("📦 Free heap after decode: %d\n", ESP.getFreeHeap());
//.................
if (res != 0) {
Serial.printf("❌ Base64 decode error: %d\n", res);
free(jpeg_buf);
return;
}
if (res == 0) {
Serial.printf("✅ Base64 decoded: %d bytes\n", decoded_len);
if (JpegDec.decodeArray(jpeg_buf, decoded_len)) {
tft.fillScreen(TFT_BLACK);
while (JpegDec.read()) {
int x = JpegDec.MCUx * JpegDec.MCUWidth;
int y = JpegDec.MCUy * JpegDec.MCUHeight;
tft.pushImage(x, y, JpegDec.MCUWidth, JpegDec.MCUHeight, JpegDec.pImage);
}
} else {
Serial.println("❌ JPEG decode failed");
}
} else {
Serial.printf("❌ Base64 decode error: %d\n", res);
}
free(jpeg_buf);
}
void SerialSettingS3() {
Serial.begin(115200);
delay(5000);
Serial.println("setup1");
delay(5000);
Serial.println("setup2");
Serial.print("File : "); Serial.println(FILE);
const char compile_date[] = DATE " " TIME;
Serial.print("Compile timestamp: ");
Serial.println(compile_date);
}
thanks.
ABG
July 3, 2025, 9:46pm
10
I'm a bit out of my depth here, in http traffic.
I looked at
https://ai2.appinventor.mit.edu/reference/components/connectivity.html#Web
to see what you need to set up to do a POST in AI2.
The doc mentions headers, which I did not see in your blocks.
There is also a flag to say if you want to send or receive a file instead of text.
I could not figure out from your code and blocks which side (ESP/AI2) is actually going to take the picture, or are they just saying
You take a picture
No, YOU take a picture.
A swim lane diagram would help.
1 Like
ABG
July 3, 2025, 11:12pm
12
See the Sending Data section at the bottom of
https://ai2.appinventor.mit.edu/reference/other/json-web-apis.html
You are not setting up Request Headers in your blocks.
Of course, you are not sending JSON, but there should probably be a Content-Type you should be specifying for your application.
Our Web Services collection:
1 Like
lladam
July 4, 2025, 1:02am
13
thanks.
added a RequestHeaders made it works.
ABG
July 4, 2025, 2:11am
14
I have no practical experience with base64 conversion.
I have seen Canvas features that might give you a path to do it in AI2, and have seen posts by more advanced Power Users with extensions and JavaScript for that
Start with the Canvas.
1 Like
lladam
July 4, 2025, 3:03am
15
Thanks.
I'll test more.
now I have problem is the display quality is really bad.