Skip to content

Commit 230487b

Browse files
author
Kinsey Moore
committed
Use dynamic buffer instead of static buffer
This removes the requirement to modify the aJson library to get a larger buffer. The default method allocates a buffer for rendering JSON dynamically based on output size. A new method has also been added for applications with less available SRAM (setBufferlessResponses). This requires no large fixed or dynamic buffer, but increases response rendering time by close to two orders of magnitude due to inefficiencies and overhead in the WiFiClient and aJson. With the following PR in place, this is reduced to an order of magnitude difference (50ms vs 400ms for /api): interactive-matter/aJson#91
1 parent ffe02d2 commit 230487b

File tree

4 files changed

+91
-14
lines changed

4 files changed

+91
-14
lines changed

ESP8266HueEmulator/ESP8266HueEmulator.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void setup() {
171171
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH
172172

173173
LightService.begin();
174+
//LightService.setBufferlessResponses(true);
174175

175176
// setup pixels as lights
176177
for (int i = 0; i < MAX_LIGHT_HANDLERS && i < pixelCount; i++) {

ESP8266HueEmulator/LightService.cpp

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@
99
#include <assert.h>
1010
#include <FS.h>
1111

12-
#if PRINT_BUFFER_LEN < 4096
13-
# error aJson print buffer length PRINT_BUFFER_LEN must be increased to at least 4096
14-
#endif
15-
1612
String macString;
1713
String bridgeIDString;
1814
String ipString;
@@ -966,15 +962,96 @@ void LightServiceClass::update() {
966962
HTTP->handleClient();
967963
}
968964

969-
void sendJson(aJsonObject *root) {
970-
// Take aJsonObject and print it to Serial and to WiFi
971-
// From https://github.com/pubnub/msp430f5529/blob/master/msp430f5529.ino
972-
char *msgStr = aJson.print(root);
973-
aJson.deleteItem(root);
965+
bool bufferlessResponses = false;
966+
void LightServiceClass::setBufferlessResponses(bool enabled) {
967+
bufferlessResponses = enabled;
968+
}
969+
970+
#include "Stream.h"
971+
class WebServerStream : public Stream {
972+
public:
973+
WebServerStream() {}
974+
~WebServerStream() {}
975+
size_t write(uint8_t ch) override {
976+
HTTP->client().write(&ch, 1);
977+
return 1;
978+
}
979+
size_t write(const uint8_t *str, size_t size) override {
980+
HTTP->client().write(str, size);
981+
return 1;
982+
}
983+
int available(void) override { return 1; }
984+
int peek(void) override { return 1; }
985+
int read(void) override { return 1; }
986+
int availableForWrite(void) { return 1; }
987+
void flush(void) override {}
988+
};
989+
990+
class StringStream : public Stream {
991+
public:
992+
StringStream(String& buf): buf(buf) {}
993+
~StringStream() {}
994+
size_t write(uint8_t ch) override {
995+
buf += (char)ch;
996+
return 1;
997+
}
998+
int available(void) override { return 1; }
999+
int peek(void) override { return 1; }
1000+
int read(void) override { return 1; }
1001+
int availableForWrite(void) { return 1; }
1002+
void flush(void) override {}
1003+
private:
1004+
String &buf;
1005+
};
1006+
1007+
class CountStream : public Stream {
1008+
public:
1009+
CountStream() {}
1010+
~CountStream() {}
1011+
size_t write(uint8_t ch) override {
1012+
count++;
1013+
return 1;
1014+
}
1015+
int available(void) override { return 1; }
1016+
int peek(void) override { return 1; }
1017+
int read(void) override { return 1; }
1018+
int availableForWrite(void) { return 1; }
1019+
void flush(void) override {}
1020+
long count = 0;
1021+
};
1022+
1023+
WebServerStream *WebStream = new WebServerStream();
1024+
CountStream *CStream = new CountStream();
1025+
aJsonStream serial_stream(&Serial);
1026+
aJsonStream web_stream(WebStream);
1027+
aJsonStream count_stream(CStream);
1028+
void sendJson(aJsonObject *root)
1029+
{
9741030
Serial.println(millis());
975-
Serial.println(msgStr);
976-
HTTP->send(200, "application/json", msgStr);
977-
free(msgStr);
1031+
1032+
if (bufferlessResponses) {
1033+
CStream->count = 0;
1034+
aJson.print(root, &count_stream);
1035+
HTTP->setContentLength(CStream->count+1);
1036+
HTTP->send(200, "application/json", "");
1037+
aJson.print(root, &web_stream);
1038+
HTTP->sendContent("\n");
1039+
} else {
1040+
CStream->count = 0;
1041+
aJson.print(root, &count_stream);
1042+
String outstr;
1043+
outstr.reserve(CStream->count+1);
1044+
StringStream *SStream = new StringStream(outstr);
1045+
aJsonStream string_stream(SStream);
1046+
aJson.print(root, &string_stream);
1047+
outstr += '\n';
1048+
HTTP->send(200, "application/json", outstr);
1049+
}
1050+
1051+
Serial.println(millis());
1052+
aJson.print(root, &serial_stream);
1053+
Serial.println();
1054+
aJson.deleteItem(root);
9781055
}
9791056

9801057
// ==============================================================================================================

ESP8266HueEmulator/LightService.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class LightServiceClass {
5959
bool setLightsAvailable(int numLights);
6060
int getLightsAvailable();
6161
bool setLightHandler(int index, LightHandler *handler);
62+
void setBufferlessResponses(bool enabled);
6263
void begin();
6364
void begin(ESP8266WebServer *svr);
6465
void update();

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Please note that currently only the bare minimum to advertise the emulated Hue b
1414
* I used [Arduino-1.6.11.hourly201608161225.esp497d19d-x86_64.AppImage](https://bintray.com/probono/AppImages/Arduino#files) which conveniently comes with both the Arduino IDE and esp8266/Arduino ready-to-use; otherwise use a recent version of the Arduino IDE and [esp8266/Arduino](https://github.com/esp8266/Arduino)
1515
* In the Arduino IDE, Open the Library Manager and search for "NeoPixelBus by Makuna" and install
1616
* Download https://github.com/interactive-matter/aJson/archive/master.zip and install the library via the Arduino IDE
17-
* Important: Change `#define PRINT_BUFFER_LEN 256` to `#define PRINT_BUFFER_LEN 4096` in `aJson/aJSON.h`
1817
* Edit the sketch to contain your WLAN credentials
1918
* Load the sketch onto your ESP-01 or other ESP8266 device
2019
* Optionally connect the DATA line of your WS2812b NeoPixels to pin GPIO2 (you do not really need this in order to test communication between the sketch and Hue client apps)
@@ -36,7 +35,6 @@ git clone --branch 2.1.4 https://github.com/Makuna/NeoPixelBus.git
3635
git clone https://github.com/interactive-matter/aJson.git
3736
git clone https://github.com/PaulStoffregen/Time.git
3837
git clone https://github.com/gmag11/NtpClient.git
39-
sed -i -e 's|#define PRINT_BUFFER_LEN 256|#define PRINT_BUFFER_LEN 4096|g' aJson/aJSON.h
4038
cd -
4139
git clone https://github.com/probonopd/ESP8266HueEmulator.git
4240
sed -i -e 's|#include "/secrets.h"|//#include "/secrets.h"|g' ESP8266HueEmulator/ESP8266HueEmulator/ESP8266HueEmulator.ino

0 commit comments

Comments
 (0)