Skip to content

Commit

Permalink
Use dynamic buffer instead of static buffer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Kinsey Moore committed Apr 30, 2018
1 parent ffe02d2 commit 230487b
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 14 deletions.
1 change: 1 addition & 0 deletions ESP8266HueEmulator/ESP8266HueEmulator.ino
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ void setup() {
digitalWrite(LED_BUILTIN, HIGH); // Turn the LED off by making the voltage HIGH

LightService.begin();
//LightService.setBufferlessResponses(true);

// setup pixels as lights
for (int i = 0; i < MAX_LIGHT_HANDLERS && i < pixelCount; i++) {
Expand Down
101 changes: 89 additions & 12 deletions ESP8266HueEmulator/LightService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
#include <assert.h>
#include <FS.h>

#if PRINT_BUFFER_LEN < 4096
# error aJson print buffer length PRINT_BUFFER_LEN must be increased to at least 4096
#endif

String macString;
String bridgeIDString;
String ipString;
Expand Down Expand Up @@ -966,15 +962,96 @@ void LightServiceClass::update() {
HTTP->handleClient();
}

void sendJson(aJsonObject *root) {
// Take aJsonObject and print it to Serial and to WiFi
// From https://github.com/pubnub/msp430f5529/blob/master/msp430f5529.ino
char *msgStr = aJson.print(root);
aJson.deleteItem(root);
bool bufferlessResponses = false;
void LightServiceClass::setBufferlessResponses(bool enabled) {
bufferlessResponses = enabled;
}

#include "Stream.h"
class WebServerStream : public Stream {
public:
WebServerStream() {}
~WebServerStream() {}
size_t write(uint8_t ch) override {
HTTP->client().write(&ch, 1);
return 1;
}
size_t write(const uint8_t *str, size_t size) override {
HTTP->client().write(str, size);
return 1;
}
int available(void) override { return 1; }
int peek(void) override { return 1; }
int read(void) override { return 1; }
int availableForWrite(void) { return 1; }
void flush(void) override {}
};

class StringStream : public Stream {
public:
StringStream(String& buf): buf(buf) {}
~StringStream() {}
size_t write(uint8_t ch) override {
buf += (char)ch;
return 1;
}
int available(void) override { return 1; }
int peek(void) override { return 1; }
int read(void) override { return 1; }
int availableForWrite(void) { return 1; }
void flush(void) override {}
private:
String &buf;
};

class CountStream : public Stream {
public:
CountStream() {}
~CountStream() {}
size_t write(uint8_t ch) override {
count++;
return 1;
}
int available(void) override { return 1; }
int peek(void) override { return 1; }
int read(void) override { return 1; }
int availableForWrite(void) { return 1; }
void flush(void) override {}
long count = 0;
};

WebServerStream *WebStream = new WebServerStream();
CountStream *CStream = new CountStream();
aJsonStream serial_stream(&Serial);
aJsonStream web_stream(WebStream);
aJsonStream count_stream(CStream);
void sendJson(aJsonObject *root)
{
Serial.println(millis());
Serial.println(msgStr);
HTTP->send(200, "application/json", msgStr);
free(msgStr);

if (bufferlessResponses) {
CStream->count = 0;
aJson.print(root, &count_stream);
HTTP->setContentLength(CStream->count+1);
HTTP->send(200, "application/json", "");
aJson.print(root, &web_stream);
HTTP->sendContent("\n");
} else {
CStream->count = 0;
aJson.print(root, &count_stream);
String outstr;
outstr.reserve(CStream->count+1);
StringStream *SStream = new StringStream(outstr);
aJsonStream string_stream(SStream);
aJson.print(root, &string_stream);
outstr += '\n';
HTTP->send(200, "application/json", outstr);
}

Serial.println(millis());
aJson.print(root, &serial_stream);
Serial.println();
aJson.deleteItem(root);
}

// ==============================================================================================================
Expand Down
1 change: 1 addition & 0 deletions ESP8266HueEmulator/LightService.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class LightServiceClass {
bool setLightsAvailable(int numLights);
int getLightsAvailable();
bool setLightHandler(int index, LightHandler *handler);
void setBufferlessResponses(bool enabled);
void begin();
void begin(ESP8266WebServer *svr);
void update();
Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Please note that currently only the bare minimum to advertise the emulated Hue b
* 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)
* In the Arduino IDE, Open the Library Manager and search for "NeoPixelBus by Makuna" and install
* Download https://github.com/interactive-matter/aJson/archive/master.zip and install the library via the Arduino IDE
* Important: Change `#define PRINT_BUFFER_LEN 256` to `#define PRINT_BUFFER_LEN 4096` in `aJson/aJSON.h`
* Edit the sketch to contain your WLAN credentials
* Load the sketch onto your ESP-01 or other ESP8266 device
* 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)
Expand All @@ -36,7 +35,6 @@ git clone --branch 2.1.4 https://github.com/Makuna/NeoPixelBus.git
git clone https://github.com/interactive-matter/aJson.git
git clone https://github.com/PaulStoffregen/Time.git
git clone https://github.com/gmag11/NtpClient.git
sed -i -e 's|#define PRINT_BUFFER_LEN 256|#define PRINT_BUFFER_LEN 4096|g' aJson/aJSON.h
cd -
git clone https://github.com/probonopd/ESP8266HueEmulator.git
sed -i -e 's|#include "/secrets.h"|//#include "/secrets.h"|g' ESP8266HueEmulator/ESP8266HueEmulator/ESP8266HueEmulator.ino
Expand Down

0 comments on commit 230487b

Please sign in to comment.