From 4f6253aa9fec99260b8bb7b9b2e9003f5259b600 Mon Sep 17 00:00:00 2001
From: Daniel Friesel <derf@finalrewind.org>
Date: Mon, 17 Sep 2018 10:02:07 +0200
Subject: [PATCH] Import arduinojson and ubjson. Only partially working at the
 moment

---
 include/lib/ArduinoJson.h                     |  19 +
 include/lib/ArduinoJson/Configuration.hpp     | 151 +++++
 include/lib/ArduinoJson/Data/Encoding.hpp     |  37 ++
 .../ArduinoJson/Data/JsonBufferAllocated.hpp  |  22 +
 include/lib/ArduinoJson/Data/JsonFloat.hpp    |  18 +
 include/lib/ArduinoJson/Data/JsonInteger.hpp  |  23 +
 .../lib/ArduinoJson/Data/JsonVariantAs.hpp    |  42 ++
 .../ArduinoJson/Data/JsonVariantContent.hpp   |  27 +
 .../ArduinoJson/Data/JsonVariantDefault.hpp   |  23 +
 .../lib/ArduinoJson/Data/JsonVariantType.hpp  |  27 +
 include/lib/ArduinoJson/Data/List.hpp         |  94 +++
 .../ArduinoJson/Data/ListConstIterator.hpp    |  50 ++
 include/lib/ArduinoJson/Data/ListIterator.hpp |  60 ++
 include/lib/ArduinoJson/Data/ListNode.hpp     |  24 +
 include/lib/ArduinoJson/Data/NonCopyable.hpp  |  23 +
 .../lib/ArduinoJson/Data/ReferenceType.hpp    |  24 +
 include/lib/ArduinoJson/Data/ValueSaver.hpp   |  52 ++
 .../ArduinoJson/Deserialization/Comments.hpp  |  61 ++
 .../Deserialization/JsonParser.hpp            | 102 +++
 .../Deserialization/JsonParserImpl.hpp        | 189 ++++++
 .../Deserialization/StringWriter.hpp          |  41 ++
 include/lib/ArduinoJson/DynamicJsonBuffer.hpp | 170 +++++
 include/lib/ArduinoJson/JsonArray.hpp         | 227 +++++++
 include/lib/ArduinoJson/JsonArrayImpl.hpp     |  26 +
 .../lib/ArduinoJson/JsonArraySubscript.hpp    | 122 ++++
 include/lib/ArduinoJson/JsonBuffer.hpp        |  78 +++
 include/lib/ArduinoJson/JsonBufferBase.hpp    | 127 ++++
 include/lib/ArduinoJson/JsonBufferImpl.hpp    |  17 +
 include/lib/ArduinoJson/JsonObject.hpp        | 328 ++++++++++
 include/lib/ArduinoJson/JsonObjectImpl.hpp    |  28 +
 .../lib/ArduinoJson/JsonObjectSubscript.hpp   | 110 ++++
 include/lib/ArduinoJson/JsonPair.hpp          |  16 +
 include/lib/ArduinoJson/JsonVariant.hpp       | 355 ++++++++++
 include/lib/ArduinoJson/JsonVariantBase.hpp   |  24 +
 include/lib/ArduinoJson/JsonVariantCasts.hpp  |  59 ++
 .../ArduinoJson/JsonVariantComparisons.hpp    | 139 ++++
 include/lib/ArduinoJson/JsonVariantImpl.hpp   | 126 ++++
 include/lib/ArduinoJson/JsonVariantOr.hpp     |  52 ++
 .../lib/ArduinoJson/JsonVariantSubscripts.hpp |  86 +++
 .../lib/ArduinoJson/Polyfills/attributes.hpp  |  29 +
 include/lib/ArduinoJson/Polyfills/ctype.hpp   |  18 +
 include/lib/ArduinoJson/Polyfills/isFloat.hpp |  38 ++
 .../lib/ArduinoJson/Polyfills/isInteger.hpp   |  19 +
 include/lib/ArduinoJson/Polyfills/math.hpp    |  19 +
 .../lib/ArduinoJson/Polyfills/parseFloat.hpp  |  90 +++
 .../ArduinoJson/Polyfills/parseInteger.hpp    |  41 ++
 include/lib/ArduinoJson/RawJson.hpp           |  46 ++
 .../ArduinoJson/Serialization/DummyPrint.hpp  |  22 +
 .../Serialization/DynamicStringBuilder.hpp    |  35 +
 .../ArduinoJson/Serialization/FloatParts.hpp  |  89 +++
 .../Serialization/IndentedPrint.hpp           |  68 ++
 .../Serialization/JsonPrintable.hpp           | 117 ++++
 .../Serialization/JsonSerializer.hpp          |  32 +
 .../Serialization/JsonSerializerImpl.hpp      | 103 +++
 .../ArduinoJson/Serialization/JsonWriter.hpp  | 155 +++++
 .../ArduinoJson/Serialization/Prettyfier.hpp  | 133 ++++
 .../Serialization/StaticStringBuilder.hpp     |  36 +
 .../Serialization/StreamPrintAdapter.hpp      |  39 ++
 include/lib/ArduinoJson/StaticJsonBuffer.hpp  | 126 ++++
 .../StringTraits/ArduinoStream.hpp            |  61 ++
 .../ArduinoJson/StringTraits/CharPointer.hpp  |  64 ++
 .../ArduinoJson/StringTraits/FlashString.hpp  |  61 ++
 .../ArduinoJson/StringTraits/StdStream.hpp    |  60 ++
 .../ArduinoJson/StringTraits/StdString.hpp    |  77 +++
 .../ArduinoJson/StringTraits/StringTraits.hpp |  36 +
 .../lib/ArduinoJson/TypeTraits/EnableIf.hpp   |  19 +
 .../ArduinoJson/TypeTraits/FloatTraits.hpp    | 171 +++++
 .../lib/ArduinoJson/TypeTraits/IsArray.hpp    |  24 +
 .../lib/ArduinoJson/TypeTraits/IsBaseOf.hpp   |  27 +
 include/lib/ArduinoJson/TypeTraits/IsChar.hpp |  23 +
 .../lib/ArduinoJson/TypeTraits/IsConst.hpp    |  21 +
 .../TypeTraits/IsFloatingPoint.hpp            |  18 +
 .../lib/ArduinoJson/TypeTraits/IsIntegral.hpp |  26 +
 include/lib/ArduinoJson/TypeTraits/IsSame.hpp |  21 +
 .../TypeTraits/IsSignedIntegral.hpp           |  28 +
 .../TypeTraits/IsUnsignedIntegral.hpp         |  28 +
 .../lib/ArduinoJson/TypeTraits/IsVariant.hpp  |  17 +
 .../ArduinoJson/TypeTraits/RemoveConst.hpp    |  20 +
 .../TypeTraits/RemoveReference.hpp            |  20 +
 include/lib/ArduinoJson/version.hpp           |  10 +
 include/lib/ubjson/ubj.h                      | 230 +++++++
 include/lib/ubjson/ubj_internal.h             | 163 +++++
 src/app/prototest/Makefile.inc                |   3 +
 src/app/prototest/main.cc                     |  30 +
 src/lib/ubjson/ubjr.c                         | 516 +++++++++++++++
 src/lib/ubjson/ubjrw.c                        | 169 +++++
 src/lib/ubjson/ubjw.c                         | 618 ++++++++++++++++++
 87 files changed, 7015 insertions(+)
 create mode 100644 include/lib/ArduinoJson.h
 create mode 100644 include/lib/ArduinoJson/Configuration.hpp
 create mode 100644 include/lib/ArduinoJson/Data/Encoding.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonFloat.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonInteger.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonVariantAs.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonVariantContent.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonVariantDefault.hpp
 create mode 100644 include/lib/ArduinoJson/Data/JsonVariantType.hpp
 create mode 100644 include/lib/ArduinoJson/Data/List.hpp
 create mode 100644 include/lib/ArduinoJson/Data/ListConstIterator.hpp
 create mode 100644 include/lib/ArduinoJson/Data/ListIterator.hpp
 create mode 100644 include/lib/ArduinoJson/Data/ListNode.hpp
 create mode 100644 include/lib/ArduinoJson/Data/NonCopyable.hpp
 create mode 100644 include/lib/ArduinoJson/Data/ReferenceType.hpp
 create mode 100644 include/lib/ArduinoJson/Data/ValueSaver.hpp
 create mode 100644 include/lib/ArduinoJson/Deserialization/Comments.hpp
 create mode 100644 include/lib/ArduinoJson/Deserialization/JsonParser.hpp
 create mode 100644 include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp
 create mode 100644 include/lib/ArduinoJson/Deserialization/StringWriter.hpp
 create mode 100644 include/lib/ArduinoJson/DynamicJsonBuffer.hpp
 create mode 100644 include/lib/ArduinoJson/JsonArray.hpp
 create mode 100644 include/lib/ArduinoJson/JsonArrayImpl.hpp
 create mode 100644 include/lib/ArduinoJson/JsonArraySubscript.hpp
 create mode 100644 include/lib/ArduinoJson/JsonBuffer.hpp
 create mode 100644 include/lib/ArduinoJson/JsonBufferBase.hpp
 create mode 100644 include/lib/ArduinoJson/JsonBufferImpl.hpp
 create mode 100644 include/lib/ArduinoJson/JsonObject.hpp
 create mode 100644 include/lib/ArduinoJson/JsonObjectImpl.hpp
 create mode 100644 include/lib/ArduinoJson/JsonObjectSubscript.hpp
 create mode 100644 include/lib/ArduinoJson/JsonPair.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariant.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantBase.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantCasts.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantComparisons.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantImpl.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantOr.hpp
 create mode 100644 include/lib/ArduinoJson/JsonVariantSubscripts.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/attributes.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/ctype.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/isFloat.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/isInteger.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/math.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/parseFloat.hpp
 create mode 100644 include/lib/ArduinoJson/Polyfills/parseInteger.hpp
 create mode 100644 include/lib/ArduinoJson/RawJson.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/DummyPrint.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/FloatParts.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/IndentedPrint.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/JsonPrintable.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/JsonSerializer.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/JsonWriter.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/Prettyfier.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp
 create mode 100644 include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp
 create mode 100644 include/lib/ArduinoJson/StaticJsonBuffer.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/CharPointer.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/FlashString.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/StdStream.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/StdString.hpp
 create mode 100644 include/lib/ArduinoJson/StringTraits/StringTraits.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/EnableIf.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsArray.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsChar.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsConst.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsSame.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/IsVariant.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp
 create mode 100644 include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp
 create mode 100644 include/lib/ArduinoJson/version.hpp
 create mode 100644 include/lib/ubjson/ubj.h
 create mode 100644 include/lib/ubjson/ubj_internal.h
 create mode 100644 src/app/prototest/Makefile.inc
 create mode 100644 src/app/prototest/main.cc
 create mode 100644 src/lib/ubjson/ubjr.c
 create mode 100644 src/lib/ubjson/ubjrw.c
 create mode 100644 src/lib/ubjson/ubjw.c

diff --git a/include/lib/ArduinoJson.h b/include/lib/ArduinoJson.h
new file mode 100644
index 0000000..c493c06
--- /dev/null
+++ b/include/lib/ArduinoJson.h
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ArduinoJson/version.hpp"
+
+#include "ArduinoJson/DynamicJsonBuffer.hpp"
+#include "ArduinoJson/JsonArray.hpp"
+#include "ArduinoJson/JsonObject.hpp"
+#include "ArduinoJson/StaticJsonBuffer.hpp"
+
+#include "ArduinoJson/Deserialization/JsonParserImpl.hpp"
+#include "ArduinoJson/JsonArrayImpl.hpp"
+#include "ArduinoJson/JsonBufferImpl.hpp"
+#include "ArduinoJson/JsonObjectImpl.hpp"
+#include "ArduinoJson/JsonVariantImpl.hpp"
+#include "ArduinoJson/Serialization/JsonSerializerImpl.hpp"
diff --git a/include/lib/ArduinoJson/Configuration.hpp b/include/lib/ArduinoJson/Configuration.hpp
new file mode 100644
index 0000000..82483ad
--- /dev/null
+++ b/include/lib/ArduinoJson/Configuration.hpp
@@ -0,0 +1,151 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+// Small or big machine?
+#ifndef ARDUINOJSON_EMBEDDED_MODE
+#if defined(ARDUINO) || defined(__IAR_SYSTEMS_ICC__) || defined(__XC) || \
+    defined(__ARMCC_VERSION)
+#define ARDUINOJSON_EMBEDDED_MODE 1
+#else
+#define ARDUINOJSON_EMBEDDED_MODE 0
+#endif
+#endif
+
+#if ARDUINOJSON_EMBEDDED_MODE
+
+// Store floats by default to reduce the memory usage (issue #134)
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 0
+#endif
+
+// Store longs by default, because they usually match the size of a float.
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#ifndef ARDUINOJSON_USE_INT64
+#define ARDUINOJSON_USE_INT64 0
+#endif
+
+// Embedded systems usually don't have std::string
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 0
+#endif
+
+// Embedded systems usually don't have std::stream
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 0
+#endif
+
+// Limit nesting as the stack is likely to be small
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 10
+#endif
+
+#else  // ARDUINOJSON_EMBEDDED_MODE
+
+// On a computer we have plenty of memory so we can use doubles
+#ifndef ARDUINOJSON_USE_DOUBLE
+#define ARDUINOJSON_USE_DOUBLE 1
+#endif
+
+// Use long long when available
+#ifndef ARDUINOJSON_USE_LONG_LONG
+#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
+#define ARDUINOJSON_USE_LONG_LONG 1
+#else
+#define ARDUINOJSON_USE_LONG_LONG 0
+#endif
+#endif
+
+// Use _int64 on old versions of Visual Studio
+#ifndef ARDUINOJSON_USE_INT64
+#if defined(_MSC_VER) && _MSC_VER <= 1700
+#define ARDUINOJSON_USE_INT64 1
+#else
+#define ARDUINOJSON_USE_INT64 0
+#endif
+#endif
+
+// On a computer, we can use std::string
+#ifndef ARDUINOJSON_ENABLE_STD_STRING
+#define ARDUINOJSON_ENABLE_STD_STRING 1
+#endif
+
+// On a computer, we can assume std::stream
+#ifndef ARDUINOJSON_ENABLE_STD_STREAM
+#define ARDUINOJSON_ENABLE_STD_STREAM 1
+#endif
+
+// On a computer, the stack is large so we can increase nesting limit
+#ifndef ARDUINOJSON_DEFAULT_NESTING_LIMIT
+#define ARDUINOJSON_DEFAULT_NESTING_LIMIT 50
+#endif
+
+#endif  // ARDUINOJSON_EMBEDDED_MODE
+
+#ifdef ARDUINO
+
+// Enable support for Arduino String
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
+#endif
+
+// Enable support for Arduino Stream
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 1
+#endif
+
+#else  // ARDUINO
+
+// Disable support for Arduino String
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STRING
+#define ARDUINOJSON_ENABLE_ARDUINO_STRING 0
+#endif
+
+// Disable support for Arduino Stream
+#ifndef ARDUINOJSON_ENABLE_ARDUINO_STREAM
+#define ARDUINOJSON_ENABLE_ARDUINO_STREAM 0
+#endif
+
+#endif  // ARDUINO
+
+#ifndef ARDUINOJSON_ENABLE_PROGMEM
+#ifdef PROGMEM
+#define ARDUINOJSON_ENABLE_PROGMEM 1
+#else
+#define ARDUINOJSON_ENABLE_PROGMEM 0
+#endif
+#endif
+
+#ifndef ARDUINOJSON_ENABLE_ALIGNMENT
+#ifdef ARDUINO_ARCH_AVR
+// alignment isn't needed for 8-bit AVR
+#define ARDUINOJSON_ENABLE_ALIGNMENT 0
+#else
+// but most processors need pointers to be align on word size
+#define ARDUINOJSON_ENABLE_ALIGNMENT 1
+#endif
+#endif
+
+// Enable deprecated functions by default
+#ifndef ARDUINOJSON_ENABLE_DEPRECATED
+#define ARDUINOJSON_ENABLE_DEPRECATED 1
+#endif
+
+// Control the exponentiation threshold for big numbers
+// CAUTION: cannot be more that 1e9 !!!!
+#ifndef ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD 1e7
+#endif
+
+// Control the exponentiation threshold for small numbers
+#ifndef ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD
+#define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5
+#endif
+
+#if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64
+#error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together
+#endif
diff --git a/include/lib/ArduinoJson/Data/Encoding.hpp b/include/lib/ArduinoJson/Data/Encoding.hpp
new file mode 100644
index 0000000..a0efa2c
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/Encoding.hpp
@@ -0,0 +1,37 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+class Encoding {
+ public:
+  // Optimized for code size on a 8-bit AVR
+  static char escapeChar(char c) {
+    const char *p = escapeTable(false);
+    while (p[0] && p[1] != c) {
+      p += 2;
+    }
+    return p[0];
+  }
+
+  // Optimized for code size on a 8-bit AVR
+  static char unescapeChar(char c) {
+    const char *p = escapeTable(true);
+    for (;;) {
+      if (p[0] == '\0') return c;
+      if (p[0] == c) return p[1];
+      p += 2;
+    }
+  }
+
+ private:
+  static const char *escapeTable(bool excludeIdenticals) {
+    return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0];
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp b/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp
new file mode 100644
index 0000000..443aae4
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonBufferAllocated.hpp
@@ -0,0 +1,22 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+class JsonBufferAllocated {
+ public:
+  void *operator new(size_t n, JsonBuffer *jsonBuffer) throw() {
+    if (!jsonBuffer) return NULL;
+    return jsonBuffer->alloc(n);
+  }
+
+  void operator delete(void *, JsonBuffer *)throw();
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonFloat.hpp b/include/lib/ArduinoJson/Data/JsonFloat.hpp
new file mode 100644
index 0000000..0ed4214
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonFloat.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+#if ARDUINOJSON_USE_DOUBLE
+typedef double JsonFloat;
+#else
+typedef float JsonFloat;
+#endif
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonInteger.hpp b/include/lib/ArduinoJson/Data/JsonInteger.hpp
new file mode 100644
index 0000000..c8ddd00
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonInteger.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+#if ARDUINOJSON_USE_LONG_LONG
+typedef long long JsonInteger;
+typedef unsigned long long JsonUInt;
+#elif ARDUINOJSON_USE_INT64
+typedef __int64 JsonInteger;
+typedef unsigned _int64 JsonUInt;
+#else
+typedef long JsonInteger;
+typedef unsigned long JsonUInt;
+#endif
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantAs.hpp b/include/lib/ArduinoJson/Data/JsonVariantAs.hpp
new file mode 100644
index 0000000..8f202c5
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantAs.hpp
@@ -0,0 +1,42 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A metafunction that returns the type of the value returned by
+// JsonVariant::as<T>()
+template <typename T>
+struct JsonVariantAs {
+  typedef T type;
+};
+
+template <>
+struct JsonVariantAs<char*> {
+  typedef const char* type;
+};
+
+template <>
+struct JsonVariantAs<JsonArray> {
+  typedef JsonArray& type;
+};
+
+template <>
+struct JsonVariantAs<const JsonArray> {
+  typedef const JsonArray& type;
+};
+
+template <>
+struct JsonVariantAs<JsonObject> {
+  typedef JsonObject& type;
+};
+
+template <>
+struct JsonVariantAs<const JsonObject> {
+  typedef const JsonObject& type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantContent.hpp b/include/lib/ArduinoJson/Data/JsonVariantContent.hpp
new file mode 100644
index 0000000..c525a60
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantContent.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonFloat.hpp"
+#include "JsonInteger.hpp"
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonArray;
+class JsonObject;
+
+namespace Internals {
+// A union that defines the actual content of a JsonVariant.
+// The enum JsonVariantType determines which member is in use.
+union JsonVariantContent {
+  JsonFloat asFloat;     // used for double and float
+  JsonUInt asInteger;    // used for bool, char, short, int and longs
+  const char* asString;  // asString can be null
+  JsonArray* asArray;    // asArray cannot be null
+  JsonObject* asObject;  // asObject cannot be null
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp b/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp
new file mode 100644
index 0000000..57ecc83
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantDefault.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+struct JsonVariantDefault {
+  static T get() {
+    return T();
+  }
+};
+
+template <typename T>
+struct JsonVariantDefault<const T> : JsonVariantDefault<T> {};
+
+template <typename T>
+struct JsonVariantDefault<T&> : JsonVariantDefault<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/JsonVariantType.hpp b/include/lib/ArduinoJson/Data/JsonVariantType.hpp
new file mode 100644
index 0000000..21f890e
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/JsonVariantType.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+
+namespace Internals {
+
+// Enumerated type to know the current type of a JsonVariant.
+// The value determines which member of JsonVariantContent is used.
+enum JsonVariantType {
+  JSON_UNDEFINED,         // JsonVariant has not been initialized
+  JSON_UNPARSED,          // JsonVariant contains an unparsed string
+  JSON_STRING,            // JsonVariant stores a const char*
+  JSON_BOOLEAN,           // JsonVariant stores a bool
+  JSON_POSITIVE_INTEGER,  // JsonVariant stores an JsonUInt
+  JSON_NEGATIVE_INTEGER,  // JsonVariant stores an JsonUInt that must be negated
+  JSON_ARRAY,             // JsonVariant stores a pointer to a JsonArray
+  JSON_OBJECT,            // JsonVariant stores a pointer to a JsonObject
+  JSON_FLOAT              // JsonVariant stores a JsonFloat
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/List.hpp b/include/lib/ArduinoJson/Data/List.hpp
new file mode 100644
index 0000000..506308c
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/List.hpp
@@ -0,0 +1,94 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "ListConstIterator.hpp"
+#include "ListIterator.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A singly linked list of T.
+// The linked list is composed of ListNode<T>.
+// It is derived by JsonArray and JsonObject
+template <typename T>
+class List {
+ public:
+  typedef T value_type;
+  typedef ListNode<T> node_type;
+  typedef ListIterator<T> iterator;
+  typedef ListConstIterator<T> const_iterator;
+
+  // Creates an empty List<T> attached to a JsonBuffer.
+  // The JsonBuffer allows to allocate new nodes.
+  // When buffer is NULL, the List is not able to grow and success() returns
+  // false. This is used to identify bad memory allocations and parsing
+  // failures.
+  explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {}
+
+  // Returns true if the object is valid
+  // Would return false in the following situation:
+  // - the memory allocation failed (StaticJsonBuffer was too small)
+  // - the JSON parsing failed
+  bool success() const {
+    return _buffer != NULL;
+  }
+
+  // Returns the numbers of elements in the list.
+  // For a JsonObject, it would return the number of key-value pairs
+  size_t size() const {
+    size_t nodeCount = 0;
+    for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
+    return nodeCount;
+  }
+
+  iterator add() {
+    node_type *newNode = new (_buffer) node_type();
+
+    if (_firstNode) {
+      node_type *lastNode = _firstNode;
+      while (lastNode->next) lastNode = lastNode->next;
+      lastNode->next = newNode;
+    } else {
+      _firstNode = newNode;
+    }
+
+    return iterator(newNode);
+  }
+
+  iterator begin() {
+    return iterator(_firstNode);
+  }
+  iterator end() {
+    return iterator(NULL);
+  }
+
+  const_iterator begin() const {
+    return const_iterator(_firstNode);
+  }
+  const_iterator end() const {
+    return const_iterator(NULL);
+  }
+
+  void remove(iterator it) {
+    node_type *nodeToRemove = it._node;
+    if (!nodeToRemove) return;
+    if (nodeToRemove == _firstNode) {
+      _firstNode = nodeToRemove->next;
+    } else {
+      for (node_type *node = _firstNode; node; node = node->next)
+        if (node->next == nodeToRemove) node->next = nodeToRemove->next;
+    }
+  }
+
+ protected:
+  JsonBuffer *_buffer;
+
+ private:
+  node_type *_firstNode;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListConstIterator.hpp b/include/lib/ArduinoJson/Data/ListConstIterator.hpp
new file mode 100644
index 0000000..a6af685
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListConstIterator.hpp
@@ -0,0 +1,50 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ListNode.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A read-only forward itertor for List<T>
+template <typename T>
+class ListConstIterator {
+ public:
+  explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
+
+  const T &operator*() const {
+    return _node->content;
+  }
+  const T *operator->() {
+    return &_node->content;
+  }
+
+  bool operator==(const ListConstIterator<T> &other) const {
+    return _node == other._node;
+  }
+
+  bool operator!=(const ListConstIterator<T> &other) const {
+    return _node != other._node;
+  }
+
+  ListConstIterator<T> &operator++() {
+    if (_node) _node = _node->next;
+    return *this;
+  }
+
+  ListConstIterator<T> &operator+=(size_t distance) {
+    while (_node && distance) {
+      _node = _node->next;
+      --distance;
+    }
+    return *this;
+  }
+
+ private:
+  const ListNode<T> *_node;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListIterator.hpp b/include/lib/ArduinoJson/Data/ListIterator.hpp
new file mode 100644
index 0000000..01fa287
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListIterator.hpp
@@ -0,0 +1,60 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "ListConstIterator.hpp"
+#include "ListNode.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+class List;
+
+// A read-write forward iterator for List<T>
+template <typename T>
+class ListIterator {
+  friend class List<T>;
+
+ public:
+  explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
+
+  T &operator*() const {
+    return _node->content;
+  }
+  T *operator->() {
+    return &_node->content;
+  }
+
+  bool operator==(const ListIterator<T> &other) const {
+    return _node == other._node;
+  }
+
+  bool operator!=(const ListIterator<T> &other) const {
+    return _node != other._node;
+  }
+
+  ListIterator<T> &operator++() {
+    if (_node) _node = _node->next;
+    return *this;
+  }
+
+  ListIterator<T> &operator+=(size_t distance) {
+    while (_node && distance) {
+      _node = _node->next;
+      --distance;
+    }
+    return *this;
+  }
+
+  operator ListConstIterator<T>() const {
+    return ListConstIterator<T>(_node);
+  }
+
+ private:
+  ListNode<T> *_node;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ListNode.hpp b/include/lib/ArduinoJson/Data/ListNode.hpp
new file mode 100644
index 0000000..c090712
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ListNode.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h>  // for NULL
+
+#include "JsonBufferAllocated.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A node for a singly-linked list.
+// Used by List<T> and its iterators.
+template <typename T>
+struct ListNode : public Internals::JsonBufferAllocated {
+  ListNode() throw() : next(NULL) {}
+
+  ListNode<T> *next;
+  T content;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/NonCopyable.hpp b/include/lib/ArduinoJson/Data/NonCopyable.hpp
new file mode 100644
index 0000000..73f3d8e
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/NonCopyable.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A type that cannot be copied
+class NonCopyable {
+ protected:
+  NonCopyable() {}
+
+ private:
+  // copy constructor is private
+  NonCopyable(const NonCopyable&);
+
+  // copy operator is private
+  NonCopyable& operator=(const NonCopyable&);
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ReferenceType.hpp b/include/lib/ArduinoJson/Data/ReferenceType.hpp
new file mode 100644
index 0000000..1e49117
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ReferenceType.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A type that is meant to be used by reference only (JsonArray and JsonObject)
+class ReferenceType {
+ public:
+  bool operator==(const ReferenceType& other) const {
+    // two JsonArray are equal if they are the same instance
+    // (we don't compare the content)
+    return this == &other;
+  }
+
+  bool operator!=(const ReferenceType& other) const {
+    return this != &other;
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Data/ValueSaver.hpp b/include/lib/ArduinoJson/Data/ValueSaver.hpp
new file mode 100644
index 0000000..9750f1a
--- /dev/null
+++ b/include/lib/ArduinoJson/Data/ValueSaver.hpp
@@ -0,0 +1,52 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "../JsonVariant.hpp"
+#include "../StringTraits/StringTraits.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename Source, typename Enable = void>
+struct ValueSaver {
+  template <typename Destination>
+  static bool save(JsonBuffer*, Destination& destination, Source source) {
+    destination = source;
+    return true;
+  }
+};
+
+template <typename Source>
+struct ValueSaver<
+    Source, typename EnableIf<StringTraits<Source>::should_duplicate>::type> {
+  template <typename Destination>
+  static bool save(JsonBuffer* buffer, Destination& dest, Source source) {
+    if (!StringTraits<Source>::is_null(source)) {
+      typename StringTraits<Source>::duplicate_t dup =
+          StringTraits<Source>::duplicate(source, buffer);
+      if (!dup) return false;
+      dest = dup;
+    } else {
+      dest = reinterpret_cast<const char*>(0);
+    }
+    return true;
+  }
+};
+
+// const char*, const signed char*, const unsigned char*
+template <typename Char>
+struct ValueSaver<
+    Char*, typename EnableIf<!StringTraits<Char*>::should_duplicate>::type> {
+  template <typename Destination>
+  static bool save(JsonBuffer*, Destination& dest, Char* source) {
+    dest = reinterpret_cast<const char*>(source);
+    return true;
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Deserialization/Comments.hpp b/include/lib/ArduinoJson/Deserialization/Comments.hpp
new file mode 100644
index 0000000..c2c48eb
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/Comments.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename TInput>
+void skipSpacesAndComments(TInput& input) {
+  for (;;) {
+    switch (input.current()) {
+      // spaces
+      case ' ':
+      case '\t':
+      case '\r':
+      case '\n':
+        input.move();
+        continue;
+
+      // comments
+      case '/':
+        switch (input.next()) {
+          // C-style block comment
+          case '*':
+            input.move();  // skip '/'
+            // no need to skip '*'
+            for (;;) {
+              input.move();
+              if (input.current() == '\0') return;
+              if (input.current() == '*' && input.next() == '/') {
+                input.move();  // skip '*'
+                input.move();  // skip '/'
+                break;
+              }
+            }
+            break;
+
+          // C++-style line comment
+          case '/':
+            // not need to skip "//"
+            for (;;) {
+              input.move();
+              if (input.current() == '\0') return;
+              if (input.current() == '\n') break;
+            }
+            break;
+
+          // not a comment, just a '/'
+          default:
+            return;
+        }
+        break;
+
+      default:
+        return;
+    }
+  }
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Deserialization/JsonParser.hpp b/include/lib/ArduinoJson/Deserialization/JsonParser.hpp
new file mode 100644
index 0000000..4cbaf45
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/JsonParser.hpp
@@ -0,0 +1,102 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonBuffer.hpp"
+#include "../JsonVariant.hpp"
+#include "../TypeTraits/IsConst.hpp"
+#include "StringWriter.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Parse JSON string to create JsonArrays and JsonObjects
+// This internal class is not indended to be used directly.
+// Instead, use JsonBuffer.parseArray() or .parseObject()
+template <typename TReader, typename TWriter>
+class JsonParser {
+ public:
+  JsonParser(JsonBuffer *buffer, TReader reader, TWriter writer,
+             uint8_t nestingLimit)
+      : _buffer(buffer),
+        _reader(reader),
+        _writer(writer),
+        _nestingLimit(nestingLimit) {}
+
+  JsonArray &parseArray();
+  JsonObject &parseObject();
+
+  JsonVariant parseVariant() {
+    JsonVariant result;
+    parseAnythingTo(&result);
+    return result;
+  }
+
+ private:
+  JsonParser &operator=(const JsonParser &);  // non-copiable
+
+  static bool eat(TReader &, char charToSkip);
+  FORCE_INLINE bool eat(char charToSkip) {
+    return eat(_reader, charToSkip);
+  }
+
+  const char *parseString();
+  bool parseAnythingTo(JsonVariant *destination);
+
+  inline bool parseArrayTo(JsonVariant *destination);
+  inline bool parseObjectTo(JsonVariant *destination);
+  inline bool parseStringTo(JsonVariant *destination);
+
+  static inline bool isBetween(char c, char min, char max) {
+    return min <= c && c <= max;
+  }
+
+  static inline bool canBeInNonQuotedString(char c) {
+    return isBetween(c, '0', '9') || isBetween(c, '_', 'z') ||
+           isBetween(c, 'A', 'Z') || c == '+' || c == '-' || c == '.';
+  }
+
+  static inline bool isQuote(char c) {
+    return c == '\'' || c == '\"';
+  }
+
+  JsonBuffer *_buffer;
+  TReader _reader;
+  TWriter _writer;
+  uint8_t _nestingLimit;
+};
+
+template <typename TJsonBuffer, typename TString, typename Enable = void>
+struct JsonParserBuilder {
+  typedef typename StringTraits<TString>::Reader InputReader;
+  typedef JsonParser<InputReader, TJsonBuffer &> TParser;
+
+  static TParser makeParser(TJsonBuffer *buffer, TString &json,
+                            uint8_t nestingLimit) {
+    return TParser(buffer, InputReader(json), *buffer, nestingLimit);
+  }
+};
+
+template <typename TJsonBuffer, typename TChar>
+struct JsonParserBuilder<TJsonBuffer, TChar *,
+                         typename EnableIf<!IsConst<TChar>::value>::type> {
+  typedef typename StringTraits<TChar *>::Reader TReader;
+  typedef StringWriter<TChar> TWriter;
+  typedef JsonParser<TReader, TWriter> TParser;
+
+  static TParser makeParser(TJsonBuffer *buffer, TChar *json,
+                            uint8_t nestingLimit) {
+    return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
+  }
+};
+
+template <typename TJsonBuffer, typename TString>
+inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
+    TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {
+  return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json,
+                                                             nestingLimit);
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp b/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp
new file mode 100644
index 0000000..5042673
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/JsonParserImpl.hpp
@@ -0,0 +1,189 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Comments.hpp"
+#include "JsonParser.hpp"
+
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::eat(
+    TReader &reader, char charToSkip) {
+  skipSpacesAndComments(reader);
+  if (reader.current() != charToSkip) return false;
+  reader.move();
+  return true;
+}
+
+template <typename TReader, typename TWriter>
+inline bool
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseAnythingTo(
+    JsonVariant *destination) {
+  skipSpacesAndComments(_reader);
+
+  switch (_reader.current()) {
+    case '[':
+      return parseArrayTo(destination);
+
+    case '{':
+      return parseObjectTo(destination);
+
+    default:
+      return parseStringTo(destination);
+  }
+}
+
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonArray &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArray() {
+  if (_nestingLimit == 0) return JsonArray::invalid();
+  _nestingLimit--;
+
+  // Create an empty array
+  JsonArray &array = _buffer->createArray();
+
+  // Check opening braket
+  if (!eat('[')) goto ERROR_MISSING_BRACKET;
+  if (eat(']')) goto SUCCESS_EMPTY_ARRAY;
+
+  // Read each value
+  for (;;) {
+    // 1 - Parse value
+    JsonVariant value;
+    if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+    if (!array.add(value)) goto ERROR_NO_MEMORY;
+
+    // 2 - More values?
+    if (eat(']')) goto SUCCES_NON_EMPTY_ARRAY;
+    if (!eat(',')) goto ERROR_MISSING_COMMA;
+  }
+
+SUCCESS_EMPTY_ARRAY:
+SUCCES_NON_EMPTY_ARRAY:
+  _nestingLimit++;
+  return array;
+
+ERROR_INVALID_VALUE:
+ERROR_MISSING_BRACKET:
+ERROR_MISSING_COMMA:
+ERROR_NO_MEMORY:
+  return JsonArray::invalid();
+}
+
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseArrayTo(
+    JsonVariant *destination) {
+  JsonArray &array = parseArray();
+  if (!array.success()) return false;
+
+  *destination = array;
+  return true;
+}
+
+template <typename TReader, typename TWriter>
+inline ArduinoJson::JsonObject &
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObject() {
+  if (_nestingLimit == 0) return JsonObject::invalid();
+  _nestingLimit--;
+
+  // Create an empty object
+  JsonObject &object = _buffer->createObject();
+
+  // Check opening brace
+  if (!eat('{')) goto ERROR_MISSING_BRACE;
+  if (eat('}')) goto SUCCESS_EMPTY_OBJECT;
+
+  // Read each key value pair
+  for (;;) {
+    // 1 - Parse key
+    const char *key = parseString();
+    if (!key) goto ERROR_INVALID_KEY;
+    if (!eat(':')) goto ERROR_MISSING_COLON;
+
+    // 2 - Parse value
+    JsonVariant value;
+    if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
+    if (!object.set(key, value)) goto ERROR_NO_MEMORY;
+
+    // 3 - More keys/values?
+    if (eat('}')) goto SUCCESS_NON_EMPTY_OBJECT;
+    if (!eat(',')) goto ERROR_MISSING_COMMA;
+  }
+
+SUCCESS_EMPTY_OBJECT:
+SUCCESS_NON_EMPTY_OBJECT:
+  _nestingLimit++;
+  return object;
+
+ERROR_INVALID_KEY:
+ERROR_INVALID_VALUE:
+ERROR_MISSING_BRACE:
+ERROR_MISSING_COLON:
+ERROR_MISSING_COMMA:
+ERROR_NO_MEMORY:
+  return JsonObject::invalid();
+}
+
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseObjectTo(
+    JsonVariant *destination) {
+  JsonObject &object = parseObject();
+  if (!object.success()) return false;
+
+  *destination = object;
+  return true;
+}
+
+template <typename TReader, typename TWriter>
+inline const char *
+ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseString() {
+  typename RemoveReference<TWriter>::type::String str = _writer.startString();
+
+  skipSpacesAndComments(_reader);
+  char c = _reader.current();
+
+  if (isQuote(c)) {  // quotes
+    _reader.move();
+    char stopChar = c;
+    for (;;) {
+      c = _reader.current();
+      if (c == '\0') break;
+      _reader.move();
+
+      if (c == stopChar) break;
+
+      if (c == '\\') {
+        // replace char
+        c = Encoding::unescapeChar(_reader.current());
+        if (c == '\0') break;
+        _reader.move();
+      }
+
+      str.append(c);
+    }
+  } else {  // no quotes
+    for (;;) {
+      if (!canBeInNonQuotedString(c)) break;
+      _reader.move();
+      str.append(c);
+      c = _reader.current();
+    }
+  }
+
+  return str.c_str();
+}
+
+template <typename TReader, typename TWriter>
+inline bool ArduinoJson::Internals::JsonParser<TReader, TWriter>::parseStringTo(
+    JsonVariant *destination) {
+  bool hasQuotes = isQuote(_reader.current());
+  const char *value = parseString();
+  if (value == NULL) return false;
+  if (hasQuotes) {
+    *destination = value;
+  } else {
+    *destination = RawJson(value);
+  }
+  return true;
+}
diff --git a/include/lib/ArduinoJson/Deserialization/StringWriter.hpp b/include/lib/ArduinoJson/Deserialization/StringWriter.hpp
new file mode 100644
index 0000000..fd5507e
--- /dev/null
+++ b/include/lib/ArduinoJson/Deserialization/StringWriter.hpp
@@ -0,0 +1,41 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TChar>
+class StringWriter {
+ public:
+  class String {
+   public:
+    String(TChar** ptr) : _writePtr(ptr), _startPtr(*ptr) {}
+
+    void append(char c) {
+      *(*_writePtr)++ = TChar(c);
+    }
+
+    const char* c_str() const {
+      *(*_writePtr)++ = 0;
+      return reinterpret_cast<const char*>(_startPtr);
+    }
+
+   private:
+    TChar** _writePtr;
+    TChar* _startPtr;
+  };
+
+  StringWriter(TChar* buffer) : _ptr(buffer) {}
+
+  String startString() {
+    return String(&_ptr);
+  }
+
+ private:
+  TChar* _ptr;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/DynamicJsonBuffer.hpp b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp
new file mode 100644
index 0000000..bdbd5dd
--- /dev/null
+++ b/include/lib/ArduinoJson/DynamicJsonBuffer.hpp
@@ -0,0 +1,170 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonBufferBase.hpp"
+
+#include <stdlib.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+class DefaultAllocator {
+ public:
+  void* allocate(size_t size) {
+    return malloc(size);
+  }
+  void deallocate(void* pointer) {
+    free(pointer);
+  }
+};
+
+template <typename TAllocator>
+class DynamicJsonBufferBase
+    : public JsonBufferBase<DynamicJsonBufferBase<TAllocator> > {
+  struct Block;
+  struct EmptyBlock {
+    Block* next;
+    size_t capacity;
+    size_t size;
+  };
+  struct Block : EmptyBlock {
+    uint8_t data[1];
+  };
+
+ public:
+  enum { EmptyBlockSize = sizeof(EmptyBlock) };
+
+  DynamicJsonBufferBase(size_t initialSize = 256)
+      : _head(NULL), _nextBlockCapacity(initialSize) {}
+
+  ~DynamicJsonBufferBase() {
+    clear();
+  }
+
+  // Gets the number of bytes occupied in the buffer
+  size_t size() const {
+    size_t total = 0;
+    for (const Block* b = _head; b; b = b->next) total += b->size;
+    return total;
+  }
+
+  // Allocates the specified amount of bytes in the buffer
+  virtual void* alloc(size_t bytes) {
+    alignNextAlloc();
+    return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
+  }
+
+  // Resets the buffer.
+  // USE WITH CAUTION: this invalidates all previously allocated data
+  void clear() {
+    Block* currentBlock = _head;
+    while (currentBlock != NULL) {
+      _nextBlockCapacity = currentBlock->capacity;
+      Block* nextBlock = currentBlock->next;
+      _allocator.deallocate(currentBlock);
+      currentBlock = nextBlock;
+    }
+    _head = 0;
+  }
+
+  class String {
+   public:
+    String(DynamicJsonBufferBase* parent)
+        : _parent(parent), _start(NULL), _length(0) {}
+
+    void append(char c) {
+      if (_parent->canAllocInHead(1)) {
+        char* end = static_cast<char*>(_parent->allocInHead(1));
+        *end = c;
+        if (_length == 0) _start = end;
+      } else {
+        char* newStart =
+            static_cast<char*>(_parent->allocInNewBlock(_length + 1));
+        if (_start && newStart) memcpy(newStart, _start, _length);
+        if (newStart) newStart[_length] = c;
+        _start = newStart;
+      }
+      _length++;
+    }
+
+    const char* c_str() {
+      append(0);
+      return _start;
+    }
+
+   private:
+    DynamicJsonBufferBase* _parent;
+    char* _start;
+    size_t _length;
+  };
+
+  String startString() {
+    return String(this);
+  }
+
+ private:
+  void alignNextAlloc() {
+    if (_head) _head->size = this->round_size_up(_head->size);
+  }
+
+  bool canAllocInHead(size_t bytes) const {
+    return _head != NULL && _head->size + bytes <= _head->capacity;
+  }
+
+  void* allocInHead(size_t bytes) {
+    void* p = _head->data + _head->size;
+    _head->size += bytes;
+    return p;
+  }
+
+  void* allocInNewBlock(size_t bytes) {
+    size_t capacity = _nextBlockCapacity;
+    if (bytes > capacity) capacity = bytes;
+    if (!addNewBlock(capacity)) return NULL;
+    _nextBlockCapacity *= 2;
+    return allocInHead(bytes);
+  }
+
+  bool addNewBlock(size_t capacity) {
+    size_t bytes = EmptyBlockSize + capacity;
+    Block* block = static_cast<Block*>(_allocator.allocate(bytes));
+    if (block == NULL) return false;
+    block->capacity = capacity;
+    block->size = 0;
+    block->next = _head;
+    _head = block;
+    return true;
+  }
+
+  TAllocator _allocator;
+  Block* _head;
+  size_t _nextBlockCapacity;
+};
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+// Implements a JsonBuffer with dynamic memory allocation.
+// You are strongly encouraged to consider using StaticJsonBuffer which is much
+// more suitable for embedded systems.
+typedef Internals::DynamicJsonBufferBase<Internals::DefaultAllocator>
+    DynamicJsonBuffer;
+}
diff --git a/include/lib/ArduinoJson/JsonArray.hpp b/include/lib/ArduinoJson/JsonArray.hpp
new file mode 100644
index 0000000..2acd2a1
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArray.hpp
@@ -0,0 +1,227 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonBufferAllocated.hpp"
+#include "Data/List.hpp"
+#include "Data/ReferenceType.hpp"
+#include "Data/ValueSaver.hpp"
+#include "JsonVariant.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsSame.hpp"
+
+// Returns the size (in bytes) of an array with n elements.
+// Can be very handy to determine the size of a StaticJsonBuffer.
+#define JSON_ARRAY_SIZE(NUMBER_OF_ELEMENTS) \
+  (sizeof(JsonArray) + (NUMBER_OF_ELEMENTS) * sizeof(JsonArray::node_type))
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonObject;
+class JsonBuffer;
+namespace Internals {
+class JsonArraySubscript;
+}
+
+// An array of JsonVariant.
+//
+// The constructor is private, instances must be created via
+// JsonBuffer::createArray() or JsonBuffer::parseArray().
+// A JsonArray can be serialized to a JSON string via JsonArray::printTo().
+// It can also be deserialized from a JSON string via JsonBuffer::parseArray().
+class JsonArray : public Internals::JsonPrintable<JsonArray>,
+                  public Internals::ReferenceType,
+                  public Internals::NonCopyable,
+                  public Internals::List<JsonVariant>,
+                  public Internals::JsonBufferAllocated {
+ public:
+  // Create an empty JsonArray attached to the specified JsonBuffer.
+  // You should not call this constructor directly.
+  // Instead, use JsonBuffer::createArray() or JsonBuffer::parseArray().
+  explicit JsonArray(JsonBuffer *buffer) throw()
+      : Internals::List<JsonVariant>(buffer) {}
+
+  // Gets the value at the specified index
+  const Internals::JsonArraySubscript operator[](size_t index) const;
+
+  // Gets or sets the value at specified index
+  Internals::JsonArraySubscript operator[](size_t index);
+
+  // Adds the specified value at the end of the array.
+  //
+  // bool add(TValue);
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename T>
+  bool add(const T &value) {
+    return add_impl<const T &>(value);
+  }
+  //
+  // bool add(TValue);
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename T>
+  bool add(T *value) {
+    return add_impl<T *>(value);
+  }
+  //
+  // bool add(TValue value, uint8_t decimals);
+  // TValue = float, double
+  template <typename T>
+  DEPRECATED("Second argument is not supported anymore")
+  bool add(T value, uint8_t) {
+    return add_impl<const JsonVariant &>(JsonVariant(value));
+  }
+
+  // Sets the value at specified index.
+  //
+  // bool add(size_t index, const TValue&);
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename T>
+  bool set(size_t index, const T &value) {
+    return set_impl<const T &>(index, value);
+  }
+  //
+  // bool add(size_t index, TValue);
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename T>
+  bool set(size_t index, T *value) {
+    return set_impl<T *>(index, value);
+  }
+  //
+  // bool set(size_t index, TValue value, uint8_t decimals);
+  // TValue = float, double
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+  set(size_t index, T value, uint8_t decimals) {
+    return set_impl<const JsonVariant &>(index, JsonVariant(value, decimals));
+  }
+
+  // Gets the value at the specified index.
+  template <typename T>
+  typename Internals::JsonVariantAs<T>::type get(size_t index) const {
+    const_iterator it = begin() += index;
+    return it != end() ? it->as<T>() : Internals::JsonVariantDefault<T>::get();
+  }
+
+  // Check the type of the value at specified index.
+  template <typename T>
+  bool is(size_t index) const {
+    const_iterator it = begin() += index;
+    return it != end() ? it->is<T>() : false;
+  }
+
+  // Creates a JsonArray and adds a reference at the end of the array.
+  // It's a shortcut for JsonBuffer::createArray() and JsonArray::add()
+  JsonArray &createNestedArray();
+
+  // Creates a JsonObject and adds a reference at the end of the array.
+  // It's a shortcut for JsonBuffer::createObject() and JsonArray::add()
+  JsonObject &createNestedObject();
+
+  // Removes element at specified index.
+  void remove(size_t index) {
+    remove(begin() += index);
+  }
+  using Internals::List<JsonVariant>::remove;
+
+  // Returns a reference an invalid JsonArray.
+  // This object is meant to replace a NULL pointer.
+  // This is used when memory allocation or JSON parsing fail.
+  static JsonArray &invalid() {
+    static JsonArray instance(NULL);
+    return instance;
+  }
+
+  // Imports a 1D array
+  template <typename T, size_t N>
+  bool copyFrom(T (&array)[N]) {
+    return copyFrom(array, N);
+  }
+
+  // Imports a 1D array
+  template <typename T>
+  bool copyFrom(T *array, size_t len) {
+    bool ok = true;
+    for (size_t i = 0; i < len; i++) {
+      ok &= add(array[i]);
+    }
+    return ok;
+  }
+
+  // Imports a 2D array
+  template <typename T, size_t N1, size_t N2>
+  bool copyFrom(T (&array)[N1][N2]) {
+    bool ok = true;
+    for (size_t i = 0; i < N1; i++) {
+      JsonArray &nestedArray = createNestedArray();
+      for (size_t j = 0; j < N2; j++) {
+        ok &= nestedArray.add(array[i][j]);
+      }
+    }
+    return ok;
+  }
+
+  // Exports a 1D array
+  template <typename T, size_t N>
+  size_t copyTo(T (&array)[N]) const {
+    return copyTo(array, N);
+  }
+
+  // Exports a 1D array
+  template <typename T>
+  size_t copyTo(T *array, size_t len) const {
+    size_t i = 0;
+    for (const_iterator it = begin(); it != end() && i < len; ++it)
+      array[i++] = *it;
+    return i;
+  }
+
+  // Exports a 2D array
+  template <typename T, size_t N1, size_t N2>
+  void copyTo(T (&array)[N1][N2]) const {
+    size_t i = 0;
+    for (const_iterator it = begin(); it != end() && i < N1; ++it) {
+      it->as<JsonArray>().copyTo(array[i++]);
+    }
+  }
+
+#if ARDUINOJSON_ENABLE_DEPRECATED
+  DEPRECATED("use remove() instead")
+  FORCE_INLINE void removeAt(size_t index) {
+    return remove(index);
+  }
+#endif
+
+ private:
+  template <typename TValueRef>
+  bool set_impl(size_t index, TValueRef value) {
+    iterator it = begin() += index;
+    if (it == end()) return false;
+    return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+  }
+
+  template <typename TValueRef>
+  bool add_impl(TValueRef value) {
+    iterator it = Internals::List<JsonVariant>::add();
+    if (it == end()) return false;
+    return Internals::ValueSaver<TValueRef>::save(_buffer, *it, value);
+  }
+};
+
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonArray> {
+  static JsonArray &get() {
+    return JsonArray::invalid();
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonArrayImpl.hpp b/include/lib/ArduinoJson/JsonArrayImpl.hpp
new file mode 100644
index 0000000..924b7ea
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArrayImpl.hpp
@@ -0,0 +1,26 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonArray.hpp"
+#include "JsonArraySubscript.hpp"
+#include "JsonObject.hpp"
+
+namespace ArduinoJson {
+
+inline JsonArray &JsonArray::createNestedArray() {
+  if (!_buffer) return JsonArray::invalid();
+  JsonArray &array = _buffer->createArray();
+  add(array);
+  return array;
+}
+
+inline JsonObject &JsonArray::createNestedObject() {
+  if (!_buffer) return JsonObject::invalid();
+  JsonObject &object = _buffer->createObject();
+  add(object);
+  return object;
+}
+}
diff --git a/include/lib/ArduinoJson/JsonArraySubscript.hpp b/include/lib/ArduinoJson/JsonArraySubscript.hpp
new file mode 100644
index 0000000..afb4dc1
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonArraySubscript.hpp
@@ -0,0 +1,122 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonVariantBase.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
+ public:
+  FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
+      : _array(array), _index(index) {}
+
+  FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& src) {
+    _array.set(_index, src);
+    return *this;
+  }
+
+  // Replaces the value
+  //
+  // operator=(const TValue&)
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename T>
+  FORCE_INLINE JsonArraySubscript& operator=(const T& src) {
+    _array.set(_index, src);
+    return *this;
+  }
+  //
+  // operator=(TValue)
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename T>
+  FORCE_INLINE JsonArraySubscript& operator=(T* src) {
+    _array.set(_index, src);
+    return *this;
+  }
+
+  FORCE_INLINE bool success() const {
+    return _index < _array.size();
+  }
+
+  template <typename T>
+  FORCE_INLINE typename JsonVariantAs<T>::type as() const {
+    return _array.get<T>(_index);
+  }
+
+  template <typename T>
+  FORCE_INLINE bool is() const {
+    return _array.is<T>(_index);
+  }
+
+  // Replaces the value
+  //
+  // bool set(const TValue&)
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue>
+  FORCE_INLINE bool set(const TValue& value) {
+    return _array.set(_index, value);
+  }
+  //
+  // bool set(TValue)
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename TValue>
+  FORCE_INLINE bool set(TValue* value) {
+    return _array.set(_index, value);
+  }
+  //
+  // bool set(TValue, uint8_t decimals);
+  // TValue = float, double
+  template <typename TValue>
+  DEPRECATED("Second argument is not supported anymore")
+  FORCE_INLINE bool set(const TValue& value, uint8_t) {
+    return _array.set(_index, value);
+  }
+
+ private:
+  JsonArray& _array;
+  const size_t _index;
+};
+
+template <typename TImpl>
+inline JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+    size_t index) {
+  return impl()->template as<JsonArray>()[index];
+}
+
+template <typename TImpl>
+inline const JsonArraySubscript JsonVariantSubscripts<TImpl>::operator[](
+    size_t index) const {
+  return impl()->template as<JsonArray>()[index];
+}
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream& operator<<(std::ostream& os,
+                                const JsonArraySubscript& source) {
+  return source.printTo(os);
+}
+#endif
+}
+
+inline Internals::JsonArraySubscript JsonArray::operator[](size_t index) {
+  return Internals::JsonArraySubscript(*this, index);
+}
+
+inline const Internals::JsonArraySubscript JsonArray::operator[](
+    size_t index) const {
+  return Internals::JsonArraySubscript(*const_cast<JsonArray*>(this), index);
+}
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/include/lib/ArduinoJson/JsonBuffer.hpp b/include/lib/ArduinoJson/JsonBuffer.hpp
new file mode 100644
index 0000000..26101e0
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBuffer.hpp
@@ -0,0 +1,78 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h>  // for size_t
+#include <stdint.h>  // for uint8_t
+#include <string.h>
+
+#include "Data/NonCopyable.hpp"
+#include "JsonVariant.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+
+namespace ArduinoJson {
+class JsonArray;
+class JsonObject;
+
+// Entry point for using the library.
+//
+// Handle the memory management (done in derived classes) and calls the parser.
+// This abstract class is implemented by StaticJsonBuffer which implements a
+// fixed memory allocation.
+class JsonBuffer : Internals::NonCopyable {
+ public:
+  // Allocates an empty JsonArray.
+  //
+  // Returns a reference to the new JsonArray or JsonArray::invalid() if the
+  // allocation fails.
+  JsonArray &createArray();
+
+  // Allocates an empty JsonObject.
+  //
+  // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+  // allocation fails.
+  JsonObject &createObject();
+
+  // Duplicates a string
+  //
+  // const char* strdup(TValue);
+  // TValue = const std::string&, const String&,
+  template <typename TString>
+  DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               const char *>::type strdup(const TString &src) {
+    return Internals::StringTraits<TString>::duplicate(src, this);
+  }
+  //
+  // const char* strdup(TValue);
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename TString>
+  DEPRECATED("char* are duplicated, you don't need strdup() anymore")
+  const char *strdup(TString *src) {
+    return Internals::StringTraits<TString *>::duplicate(src, this);
+  }
+
+  // Allocates n bytes in the JsonBuffer.
+  // Return a pointer to the allocated memory or NULL if allocation fails.
+  virtual void *alloc(size_t size) = 0;
+
+ protected:
+  // CAUTION: NO VIRTUAL DESTRUCTOR!
+  // If we add a virtual constructor the Arduino compiler will add malloc()
+  // and free() to the binary, adding 706 useless bytes.
+  ~JsonBuffer() {}
+
+  // Preserve aligment if necessary
+  static FORCE_INLINE size_t round_size_up(size_t bytes) {
+#if ARDUINOJSON_ENABLE_ALIGNMENT
+    const size_t x = sizeof(void *) - 1;
+    return (bytes + x) & ~x;
+#else
+    return bytes;
+#endif
+  }
+};
+}
diff --git a/include/lib/ArduinoJson/JsonBufferBase.hpp b/include/lib/ArduinoJson/JsonBufferBase.hpp
new file mode 100644
index 0000000..1e771bf
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBufferBase.hpp
@@ -0,0 +1,127 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Deserialization/JsonParser.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename TDerived>
+class JsonBufferBase : public JsonBuffer {
+ public:
+  // Allocates and populate a JsonArray from a JSON string.
+  //
+  // The First argument is a pointer to the JSON string, the memory must be
+  // writable
+  // because the parser will insert null-terminators and replace escaped chars.
+  //
+  // The second argument set the nesting limit
+  //
+  // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+  // allocation fails.
+  // With this overload, the JsonBuffer will make a copy of the string
+  //
+  // JsonArray& parseArray(TString);
+  // TString = const std::string&, const String&
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonArray &>::type
+  parseArray(const TString &json,
+             uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+  //
+  // JsonArray& parseArray(TString);
+  // TString = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  JsonArray &parseArray(
+      TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+  //
+  // JsonArray& parseArray(TString);
+  // TString = std::istream&, Stream&
+  template <typename TString>
+  JsonArray &parseArray(
+      TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseArray();
+  }
+
+  // Allocates and populate a JsonObject from a JSON string.
+  //
+  // The First argument is a pointer to the JSON string, the memory must be
+  // writable
+  // because the parser will insert null-terminators and replace escaped chars.
+  //
+  // The second argument set the nesting limit
+  //
+  // Returns a reference to the new JsonObject or JsonObject::invalid() if the
+  // allocation fails.
+  //
+  // JsonObject& parseObject(TString);
+  // TString = const std::string&, const String&
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonObject &>::type
+  parseObject(const TString &json,
+              uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+  //
+  // JsonObject& parseObject(TString);
+  // TString = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  JsonObject &parseObject(
+      TString *json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+  //
+  // JsonObject& parseObject(TString);
+  // TString = std::istream&, Stream&
+  template <typename TString>
+  JsonObject &parseObject(
+      TString &json, uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseObject();
+  }
+
+  // Generalized version of parseArray() and parseObject(), also works for
+  // integral types.
+  //
+  // JsonVariant parse(TString);
+  // TString = const std::string&, const String&
+  template <typename TString>
+  typename Internals::EnableIf<!Internals::IsArray<TString>::value,
+                               JsonVariant>::type
+  parse(const TString &json,
+        uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+  //
+  // JsonVariant parse(TString);
+  // TString = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  JsonVariant parse(TString *json,
+                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+  //
+  // JsonVariant parse(TString);
+  // TString = std::istream&, Stream&
+  template <typename TString>
+  JsonVariant parse(TString &json,
+                    uint8_t nestingLimit = ARDUINOJSON_DEFAULT_NESTING_LIMIT) {
+    return Internals::makeParser(that(), json, nestingLimit).parseVariant();
+  }
+
+ protected:
+  ~JsonBufferBase() {}
+
+ private:
+  TDerived *that() {
+    return static_cast<TDerived *>(this);
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonBufferImpl.hpp b/include/lib/ArduinoJson/JsonBufferImpl.hpp
new file mode 100644
index 0000000..cdea374
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonBufferImpl.hpp
@@ -0,0 +1,17 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Deserialization/JsonParser.hpp"
+
+inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
+  JsonArray *ptr = new (this) JsonArray(this);
+  return ptr ? *ptr : JsonArray::invalid();
+}
+
+inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() {
+  JsonObject *ptr = new (this) JsonObject(this);
+  return ptr ? *ptr : JsonObject::invalid();
+}
diff --git a/include/lib/ArduinoJson/JsonObject.hpp b/include/lib/ArduinoJson/JsonObject.hpp
new file mode 100644
index 0000000..caf698a
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObject.hpp
@@ -0,0 +1,328 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonBufferAllocated.hpp"
+#include "Data/List.hpp"
+#include "Data/ReferenceType.hpp"
+#include "Data/ValueSaver.hpp"
+#include "JsonPair.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsArray.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsSame.hpp"
+
+// Returns the size (in bytes) of an object with n elements.
+// Can be very handy to determine the size of a StaticJsonBuffer.
+#define JSON_OBJECT_SIZE(NUMBER_OF_ELEMENTS) \
+  (sizeof(JsonObject) + (NUMBER_OF_ELEMENTS) * sizeof(JsonObject::node_type))
+
+namespace ArduinoJson {
+
+// Forward declarations
+class JsonArray;
+class JsonBuffer;
+namespace Internals {
+template <typename>
+class JsonObjectSubscript;
+}
+
+// A dictionary of JsonVariant indexed by string (char*)
+//
+// The constructor is private, instances must be created via
+// JsonBuffer::createObject() or JsonBuffer::parseObject().
+// A JsonObject can be serialized to a JSON string via JsonObject::printTo().
+// It can also be deserialized from a JSON string via JsonBuffer::parseObject().
+class JsonObject : public Internals::JsonPrintable<JsonObject>,
+                   public Internals::ReferenceType,
+                   public Internals::NonCopyable,
+                   public Internals::List<JsonPair>,
+                   public Internals::JsonBufferAllocated {
+ public:
+  // Create an empty JsonArray attached to the specified JsonBuffer.
+  // You should not use this constructor directly.
+  // Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
+  explicit JsonObject(JsonBuffer* buffer) throw()
+      : Internals::List<JsonPair>(buffer) {}
+
+  // Gets or sets the value associated with the specified key.
+  //
+  // JsonObjectSubscript operator[](TKey)
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  Internals::JsonObjectSubscript<const TString&> operator[](
+      const TString& key) {
+    return Internals::JsonObjectSubscript<const TString&>(*this, key);
+  }
+  //
+  // JsonObjectSubscript operator[](TKey)
+  // TKey = char*, const char*, char[], const char[N], const FlashStringHelper*
+  template <typename TString>
+  Internals::JsonObjectSubscript<TString*> operator[](TString* key) {
+    return Internals::JsonObjectSubscript<TString*>(*this, key);
+  }
+
+  // Gets the value associated with the specified key.
+  //
+  // const JsonObjectSubscript operator[](TKey) const;
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  const Internals::JsonObjectSubscript<const TString&> operator[](
+      const TString& key) const {
+    return Internals::JsonObjectSubscript<const TString&>(
+        *const_cast<JsonObject*>(this), key);
+  }
+  //
+  // const JsonObjectSubscript operator[](TKey) const;
+  // TKey = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  const Internals::JsonObjectSubscript<TString*> operator[](
+      TString* key) const {
+    return Internals::JsonObjectSubscript<TString*>(
+        *const_cast<JsonObject*>(this), key);
+  }
+
+  // Sets the specified key with the specified value.
+  //
+  // bool set(TKey, TValue);
+  // TKey = const std::string&, const String&
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  bool set(const TString& key, const TValue& value) {
+    return set_impl<const TString&, const TValue&>(key, value);
+  }
+  //
+  // bool set(TKey, TValue);
+  // TKey = const std::string&, const String&
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename TValue, typename TString>
+  bool set(const TString& key, TValue* value) {
+    return set_impl<const TString&, TValue*>(key, value);
+  }
+  //
+  // bool set(TKey, const TValue&);
+  // TKey = char*, const char*, const FlashStringHelper*
+  // TValue = bool, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  bool set(TString* key, const TValue& value) {
+    return set_impl<TString*, const TValue&>(key, value);
+  }
+  //
+  // bool set(TKey, TValue);
+  // TKey = char*, const char*, const FlashStringHelper*
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename TValue, typename TString>
+  bool set(TString* key, TValue* value) {
+    return set_impl<TString*, TValue*>(key, value);
+  }
+  //
+  // bool set(TKey, TValue, uint8_t decimals);
+  // TKey = const std::string&, const String&
+  // TValue = float, double
+  template <typename TValue, typename TString>
+  DEPRECATED("Second argument is not supported anymore")
+  typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+                               bool>::type
+      set(const TString& key, TValue value, uint8_t) {
+    return set_impl<const TString&, const JsonVariant&>(key,
+                                                        JsonVariant(value));
+  }
+  //
+  // bool set(TKey, TValue, uint8_t decimals);
+  // TKey = char*, const char*, const FlashStringHelper*
+  // TValue = float, double
+  template <typename TValue, typename TString>
+  DEPRECATED("Second argument is not supported anymore")
+  typename Internals::EnableIf<Internals::IsFloatingPoint<TValue>::value,
+                               bool>::type
+      set(TString* key, TValue value, uint8_t) {
+    return set_impl<TString*, const JsonVariant&>(key, JsonVariant(value));
+  }
+
+  // Gets the value associated with the specified key.
+  //
+  // TValue get<TValue>(TKey) const;
+  // TKey = const std::string&, const String&
+  // TValue = bool, char, long, int, short, float, double,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  typename Internals::JsonVariantAs<TValue>::type get(
+      const TString& key) const {
+    return get_impl<const TString&, TValue>(key);
+  }
+  //
+  // TValue get<TValue>(TKey) const;
+  // TKey = char*, const char*, const FlashStringHelper*
+  // TValue = bool, char, long, int, short, float, double,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  typename Internals::JsonVariantAs<TValue>::type get(TString* key) const {
+    return get_impl<TString*, TValue>(key);
+  }
+
+  // Checks the type of the value associated with the specified key.
+  //
+  //
+  // bool is<TValue>(TKey) const;
+  // TKey = const std::string&, const String&
+  // TValue = bool, char, long, int, short, float, double,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  bool is(const TString& key) const {
+    return is_impl<const TString&, TValue>(key);
+  }
+  //
+  // bool is<TValue>(TKey) const;
+  // TKey = char*, const char*, const FlashStringHelper*
+  // TValue = bool, char, long, int, short, float, double,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue, typename TString>
+  bool is(TString* key) const {
+    return is_impl<TString*, TValue>(key);
+  }
+
+  // Creates and adds a JsonArray.
+  //
+  // JsonArray& createNestedArray(TKey);
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  JsonArray& createNestedArray(const TString& key) {
+    return createNestedArray_impl<const TString&>(key);
+  }
+  // JsonArray& createNestedArray(TKey);
+  // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+  template <typename TString>
+  JsonArray& createNestedArray(TString* key) {
+    return createNestedArray_impl<TString*>(key);
+  }
+
+  // Creates and adds a JsonObject.
+  //
+  // JsonObject& createNestedObject(TKey);
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  JsonObject& createNestedObject(const TString& key) {
+    return createNestedObject_impl<const TString&>(key);
+  }
+  //
+  // JsonObject& createNestedObject(TKey);
+  // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+  template <typename TString>
+  JsonObject& createNestedObject(TString* key) {
+    return createNestedObject_impl<TString*>(key);
+  }
+
+  // Tells weither the specified key is present and associated with a value.
+  //
+  // bool containsKey(TKey);
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  bool containsKey(const TString& key) const {
+    return findKey<const TString&>(key) != end();
+  }
+  //
+  // bool containsKey(TKey);
+  // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+  template <typename TString>
+  bool containsKey(TString* key) const {
+    return findKey<TString*>(key) != end();
+  }
+
+  // Removes the specified key and the associated value.
+  //
+  // void remove(TKey);
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  void remove(const TString& key) {
+    remove(findKey<const TString&>(key));
+  }
+  //
+  // void remove(TKey);
+  // TKey = char*, const char*, char[], const char[], const FlashStringHelper*
+  template <typename TString>
+  void remove(TString* key) {
+    remove(findKey<TString*>(key));
+  }
+  //
+  // void remove(iterator)
+  using Internals::List<JsonPair>::remove;
+
+  // Returns a reference an invalid JsonObject.
+  // This object is meant to replace a NULL pointer.
+  // This is used when memory allocation or JSON parsing fail.
+  static JsonObject& invalid() {
+    static JsonObject instance(NULL);
+    return instance;
+  }
+
+ private:
+  // Returns the list node that matches the specified key.
+  template <typename TStringRef>
+  iterator findKey(TStringRef key) {
+    iterator it;
+    for (it = begin(); it != end(); ++it) {
+      if (Internals::StringTraits<TStringRef>::equals(key, it->key)) break;
+    }
+    return it;
+  }
+  template <typename TStringRef>
+  const_iterator findKey(TStringRef key) const {
+    return const_cast<JsonObject*>(this)->findKey<TStringRef>(key);
+  }
+
+  template <typename TStringRef, typename TValue>
+  typename Internals::JsonVariantAs<TValue>::type get_impl(
+      TStringRef key) const {
+    const_iterator it = findKey<TStringRef>(key);
+    return it != end() ? it->value.as<TValue>()
+                       : Internals::JsonVariantDefault<TValue>::get();
+  }
+
+  template <typename TStringRef, typename TValueRef>
+  bool set_impl(TStringRef key, TValueRef value) {
+    // ignore null key
+    if (Internals::StringTraits<TStringRef>::is_null(key)) return false;
+
+    // search a matching key
+    iterator it = findKey<TStringRef>(key);
+    if (it == end()) {
+      // add the key
+      it = Internals::List<JsonPair>::add();
+      if (it == end()) return false;
+      bool key_ok =
+          Internals::ValueSaver<TStringRef>::save(_buffer, it->key, key);
+      if (!key_ok) return false;
+    }
+
+    // save the value
+    return Internals::ValueSaver<TValueRef>::save(_buffer, it->value, value);
+  }
+
+  template <typename TStringRef, typename TValue>
+  bool is_impl(TStringRef key) const {
+    const_iterator it = findKey<TStringRef>(key);
+    return it != end() ? it->value.is<TValue>() : false;
+  }
+
+  template <typename TStringRef>
+  JsonArray& createNestedArray_impl(TStringRef key);
+
+  template <typename TStringRef>
+  JsonObject& createNestedObject_impl(TStringRef key);
+};
+
+namespace Internals {
+template <>
+struct JsonVariantDefault<JsonObject> {
+  static JsonObject& get() {
+    return JsonObject::invalid();
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonObjectImpl.hpp b/include/lib/ArduinoJson/JsonObjectImpl.hpp
new file mode 100644
index 0000000..e7689b5
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObjectImpl.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonArray.hpp"
+#include "JsonObject.hpp"
+#include "JsonObjectSubscript.hpp"
+
+namespace ArduinoJson {
+
+template <typename TStringRef>
+inline JsonArray &JsonObject::createNestedArray_impl(TStringRef key) {
+  if (!_buffer) return JsonArray::invalid();
+  JsonArray &array = _buffer->createArray();
+  set(key, array);
+  return array;
+}
+
+template <typename TStringRef>
+inline JsonObject &JsonObject::createNestedObject_impl(TStringRef key) {
+  if (!_buffer) return JsonObject::invalid();
+  JsonObject &object = _buffer->createObject();
+  set(key, object);
+  return object;
+}
+}
diff --git a/include/lib/ArduinoJson/JsonObjectSubscript.hpp b/include/lib/ArduinoJson/JsonObjectSubscript.hpp
new file mode 100644
index 0000000..6ac4763
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonObjectSubscript.hpp
@@ -0,0 +1,110 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonVariantBase.hpp"
+#include "TypeTraits/EnableIf.hpp"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4522)
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TStringRef>
+class JsonObjectSubscript
+    : public JsonVariantBase<JsonObjectSubscript<TStringRef> > {
+  typedef JsonObjectSubscript<TStringRef> this_type;
+
+ public:
+  FORCE_INLINE JsonObjectSubscript(JsonObject& object, TStringRef key)
+      : _object(object), _key(key) {}
+
+  FORCE_INLINE this_type& operator=(const this_type& src) {
+    _object.set(_key, src);
+    return *this;
+  }
+
+  // Set the specified value
+  //
+  // operator=(const TValue&);
+  // TValue = bool, char, long, int, short, float, double,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue>
+  FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, this_type&>::type
+  operator=(const TValue& src) {
+    _object.set(_key, src);
+    return *this;
+  }
+  //
+  // operator=(TValue);
+  // TValue = char*, const char*, const FlashStringHelper*
+  template <typename TValue>
+  FORCE_INLINE this_type& operator=(TValue* src) {
+    _object.set(_key, src);
+    return *this;
+  }
+
+  FORCE_INLINE bool success() const {
+    return _object.containsKey(_key);
+  }
+
+  template <typename TValue>
+  FORCE_INLINE typename JsonVariantAs<TValue>::type as() const {
+    return _object.get<TValue>(_key);
+  }
+
+  template <typename TValue>
+  FORCE_INLINE bool is() const {
+    return _object.is<TValue>(_key);
+  }
+
+  // Sets the specified value.
+  //
+  // bool set(const TValue&);
+  // TValue = bool, char, long, int, short, float, double, RawJson, JsonVariant,
+  //          std::string, String, JsonArray, JsonObject
+  template <typename TValue>
+  FORCE_INLINE typename EnableIf<!IsArray<TValue>::value, bool>::type set(
+      const TValue& value) {
+    return _object.set(_key, value);
+  }
+  //
+  // bool set(TValue);
+  // TValue = char*, const char, const FlashStringHelper*
+  template <typename TValue>
+  FORCE_INLINE bool set(const TValue* value) {
+    return _object.set(_key, value);
+  }
+  //
+  // bool set(TValue, uint8_t decimals);
+  // TValue = float, double
+  template <typename TValue>
+  DEPRECATED("Second argument is not supported anymore")
+  FORCE_INLINE bool set(const TValue& value, uint8_t) {
+    return _object.set(_key, value);
+  }
+
+ private:
+  JsonObject& _object;
+  TStringRef _key;
+};
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename TStringRef>
+inline std::ostream& operator<<(std::ostream& os,
+                                const JsonObjectSubscript<TStringRef>& source) {
+  return source.printTo(os);
+}
+#endif
+}
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/include/lib/ArduinoJson/JsonPair.hpp b/include/lib/ArduinoJson/JsonPair.hpp
new file mode 100644
index 0000000..4172430
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonPair.hpp
@@ -0,0 +1,16 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonVariant.hpp"
+
+namespace ArduinoJson {
+
+// A key value pair for JsonObject.
+struct JsonPair {
+  const char* key;
+  JsonVariant value;
+};
+}
diff --git a/include/lib/ArduinoJson/JsonVariant.hpp b/include/lib/ArduinoJson/JsonVariant.hpp
new file mode 100644
index 0000000..8326cbe
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariant.hpp
@@ -0,0 +1,355 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>  // for uint8_t
+
+#include "Data/JsonVariantContent.hpp"
+#include "Data/JsonVariantDefault.hpp"
+#include "Data/JsonVariantType.hpp"
+#include "JsonVariantBase.hpp"
+#include "RawJson.hpp"
+#include "Serialization/JsonPrintable.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsChar.hpp"
+#include "TypeTraits/IsFloatingPoint.hpp"
+#include "TypeTraits/IsIntegral.hpp"
+#include "TypeTraits/IsSame.hpp"
+#include "TypeTraits/IsSignedIntegral.hpp"
+#include "TypeTraits/IsUnsignedIntegral.hpp"
+#include "TypeTraits/RemoveConst.hpp"
+#include "TypeTraits/RemoveReference.hpp"
+
+namespace ArduinoJson {
+
+// Forward declarations.
+class JsonArray;
+class JsonObject;
+
+// A variant that can be a any value serializable to a JSON value.
+//
+// It can be set to:
+// - a boolean
+// - a char, short, int or a long (signed or unsigned)
+// - a string (const char*)
+// - a reference to a JsonArray or JsonObject
+class JsonVariant : public Internals::JsonVariantBase<JsonVariant> {
+  template <typename Print>
+  friend class Internals::JsonSerializer;
+
+ public:
+  // Creates an uninitialized JsonVariant
+  JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
+
+  // Create a JsonVariant containing a boolean value.
+  // It will be serialized as "true" or "false" in JSON.
+  JsonVariant(bool value) {
+    using namespace Internals;
+    _type = JSON_BOOLEAN;
+    _content.asInteger = static_cast<JsonUInt>(value);
+  }
+
+  // Create a JsonVariant containing a floating point value.
+  // JsonVariant(double value);
+  // JsonVariant(float value);
+  template <typename T>
+  JsonVariant(T value, typename Internals::EnableIf<
+                           Internals::IsFloatingPoint<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_FLOAT;
+    _content.asFloat = static_cast<JsonFloat>(value);
+  }
+  template <typename T>
+  DEPRECATED("Second argument is not supported anymore")
+  JsonVariant(T value, uint8_t,
+              typename Internals::EnableIf<
+                  Internals::IsFloatingPoint<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_FLOAT;
+    _content.asFloat = static_cast<JsonFloat>(value);
+  }
+
+  // Create a JsonVariant containing an integer value.
+  // JsonVariant(char)
+  // JsonVariant(signed short)
+  // JsonVariant(signed int)
+  // JsonVariant(signed long)
+  // JsonVariant(signed char)
+  template <typename T>
+  JsonVariant(
+      T value,
+      typename Internals::EnableIf<Internals::IsSignedIntegral<T>::value ||
+                                   Internals::IsSame<T, char>::value>::type * =
+          0) {
+    using namespace Internals;
+    if (value >= 0) {
+      _type = JSON_POSITIVE_INTEGER;
+      _content.asInteger = static_cast<JsonUInt>(value);
+    } else {
+      _type = JSON_NEGATIVE_INTEGER;
+      _content.asInteger = static_cast<JsonUInt>(-value);
+    }
+  }
+  // JsonVariant(unsigned short)
+  // JsonVariant(unsigned int)
+  // JsonVariant(unsigned long)
+  template <typename T>
+  JsonVariant(T value,
+              typename Internals::EnableIf<
+                  Internals::IsUnsignedIntegral<T>::value>::type * = 0) {
+    using namespace Internals;
+    _type = JSON_POSITIVE_INTEGER;
+    _content.asInteger = static_cast<JsonUInt>(value);
+  }
+
+  // Create a JsonVariant containing a string.
+  // JsonVariant(const char*);
+  // JsonVariant(const signed char*);
+  // JsonVariant(const unsigned char*);
+  template <typename TChar>
+  JsonVariant(
+      const TChar *value,
+      typename Internals::EnableIf<Internals::IsChar<TChar>::value>::type * =
+          0) {
+    _type = Internals::JSON_STRING;
+    _content.asString = reinterpret_cast<const char *>(value);
+  }
+
+  // Create a JsonVariant containing an unparsed string
+  JsonVariant(Internals::RawJsonString<const char *> value) {
+    _type = Internals::JSON_UNPARSED;
+    _content.asString = value;
+  }
+
+  // Create a JsonVariant containing a reference to an array.
+  // CAUTION: we are lying about constness, because the array can be modified if
+  // the variant is converted back to a JsonArray&
+  JsonVariant(const JsonArray &array);
+
+  // Create a JsonVariant containing a reference to an object.
+  // CAUTION: we are lying about constness, because the object can be modified
+  // if the variant is converted back to a JsonObject&
+  JsonVariant(const JsonObject &object);
+
+  // Get the variant as the specified type.
+  //
+  // char as<char>() const;
+  // signed char as<signed char>() const;
+  // signed short as<signed short>() const;
+  // signed int as<signed int>() const;
+  // signed long as<signed long>() const;
+  // unsigned char as<unsigned char>() const;
+  // unsigned short as<unsigned short>() const;
+  // unsigned int as<unsigned int>() const;
+  // unsigned long as<unsigned long>() const;
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsIntegral<T>::value, T>::type
+  as() const {
+    return variantAsInteger<T>();
+  }
+  // bool as<bool>() const
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsSame<T, bool>::value, T>::type
+  as() const {
+    return variantAsInteger<int>() != 0;
+  }
+  //
+  // double as<double>() const;
+  // float as<float>() const;
+  template <typename T>
+  const typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value,
+                                     T>::type
+  as() const {
+    return variantAsFloat<T>();
+  }
+  //
+  // const char* as<const char*>() const;
+  // const char* as<char*>() const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+                                   Internals::IsSame<T, char *>::value,
+                               const char *>::type
+  as() const {
+    return variantAsString();
+  }
+  //
+  // std::string as<std::string>() const;
+  // String as<String>() const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::StringTraits<T>::has_append, T>::type
+  as() const {
+    const char *cstr = variantAsString();
+    if (cstr) return T(cstr);
+    T s;
+    printTo(s);
+    return s;
+  }
+  //
+  // JsonArray& as<JsonArray> const;
+  // JsonArray& as<JsonArray&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        JsonArray>::value,
+      JsonArray &>::type
+  as() const {
+    return variantAsArray();
+  }
+  //
+  // const JsonArray& as<const JsonArray&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        const JsonArray>::value,
+      const JsonArray &>::type
+  as() const {
+    return variantAsArray();
+  }
+  //
+  // JsonObject& as<JsonObject> const;
+  // JsonObject& as<JsonObject&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        JsonObject>::value,
+      JsonObject &>::type
+  as() const {
+    return variantAsObject();
+  }
+  //
+  // JsonObject& as<const JsonObject> const;
+  // JsonObject& as<const JsonObject&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveReference<T>::type,
+                        const JsonObject>::value,
+      const JsonObject &>::type
+  as() const {
+    return variantAsObject();
+  }
+  //
+  // JsonVariant as<JsonVariant> const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, JsonVariant>::value,
+                               T>::type
+  as() const {
+    return *this;
+  }
+
+  // Tells weither the variant has the specified type.
+  // Returns true if the variant has type type T, false otherwise.
+  //
+  // bool is<char>() const;
+  // bool is<signed char>() const;
+  // bool is<signed short>() const;
+  // bool is<signed int>() const;
+  // bool is<signed long>() const;
+  // bool is<unsigned char>() const;
+  // bool is<unsigned short>() const;
+  // bool is<unsigned int>() const;
+  // bool is<unsigned long>() const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsIntegral<T>::value, bool>::type is()
+      const {
+    return variantIsInteger();
+  }
+  //
+  // bool is<double>() const;
+  // bool is<float>() const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsFloatingPoint<T>::value, bool>::type
+  is() const {
+    return variantIsFloat();
+  }
+  //
+  // bool is<bool>() const
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, bool>::value, bool>::type
+  is() const {
+    return variantIsBoolean();
+  }
+  //
+  // bool is<const char*>() const;
+  // bool is<char*>() const;
+  template <typename T>
+  typename Internals::EnableIf<Internals::IsSame<T, const char *>::value ||
+                                   Internals::IsSame<T, char *>::value,
+                               bool>::type
+  is() const {
+    return variantIsString();
+  }
+  //
+  // bool is<JsonArray> const;
+  // bool is<JsonArray&> const;
+  // bool is<const JsonArray&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveConst<
+                            typename Internals::RemoveReference<T>::type>::type,
+                        JsonArray>::value,
+      bool>::type
+  is() const {
+    return variantIsArray();
+  }
+  //
+  // bool is<JsonObject> const;
+  // bool is<JsonObject&> const;
+  // bool is<const JsonObject&> const;
+  template <typename T>
+  typename Internals::EnableIf<
+      Internals::IsSame<typename Internals::RemoveConst<
+                            typename Internals::RemoveReference<T>::type>::type,
+                        JsonObject>::value,
+      bool>::type
+  is() const {
+    return variantIsObject();
+  }
+
+  // Returns true if the variant has a value
+  bool success() const {
+    return _type != Internals::JSON_UNDEFINED;
+  }
+
+ private:
+  JsonArray &variantAsArray() const;
+  JsonObject &variantAsObject() const;
+  const char *variantAsString() const;
+  template <typename T>
+  T variantAsFloat() const;
+  template <typename T>
+  T variantAsInteger() const;
+  bool variantIsBoolean() const;
+  bool variantIsFloat() const;
+  bool variantIsInteger() const;
+  bool variantIsArray() const {
+    return _type == Internals::JSON_ARRAY;
+  }
+  bool variantIsObject() const {
+    return _type == Internals::JSON_OBJECT;
+  }
+  bool variantIsString() const {
+    return _type == Internals::JSON_STRING ||
+           (_type == Internals::JSON_UNPARSED && _content.asString &&
+            !strcmp("null", _content.asString));
+  }
+
+  // The current type of the variant
+  Internals::JsonVariantType _type;
+
+  // The various alternatives for the value of the variant.
+  Internals::JsonVariantContent _content;
+};
+
+DEPRECATED("Decimal places are ignored, use the float value instead")
+inline JsonVariant float_with_n_digits(float value, uint8_t) {
+  return JsonVariant(value);
+}
+
+DEPRECATED("Decimal places are ignored, use the double value instead")
+inline JsonVariant double_with_n_digits(double value, uint8_t) {
+  return JsonVariant(value);
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantBase.hpp b/include/lib/ArduinoJson/JsonVariantBase.hpp
new file mode 100644
index 0000000..44acf2e
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantBase.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonVariantCasts.hpp"
+#include "JsonVariantComparisons.hpp"
+#include "JsonVariantOr.hpp"
+#include "JsonVariantSubscripts.hpp"
+#include "Serialization/JsonPrintable.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantBase : public JsonPrintable<TImpl>,
+                        public JsonVariantCasts<TImpl>,
+                        public JsonVariantComparisons<TImpl>,
+                        public JsonVariantOr<TImpl>,
+                        public JsonVariantSubscripts<TImpl>,
+                        public JsonVariantTag {};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantCasts.hpp b/include/lib/ArduinoJson/JsonVariantCasts.hpp
new file mode 100644
index 0000000..68f5bd7
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantCasts.hpp
@@ -0,0 +1,59 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantCasts {
+ public:
+#if ARDUINOJSON_ENABLE_DEPRECATED
+  DEPRECATED("use as<JsonArray>() instead")
+  FORCE_INLINE JsonArray &asArray() const {
+    return impl()->template as<JsonArray>();
+  }
+
+  DEPRECATED("use as<JsonObject>() instead")
+  FORCE_INLINE JsonObject &asObject() const {
+    return impl()->template as<JsonObject>();
+  }
+
+  DEPRECATED("use as<char*>() instead")
+  FORCE_INLINE const char *asString() const {
+    return impl()->template as<const char *>();
+  }
+#endif
+
+  // Gets the variant as an array.
+  // Returns a reference to the JsonArray or JsonArray::invalid() if the
+  // variant
+  // is not an array.
+  FORCE_INLINE operator JsonArray &() const {
+    return impl()->template as<JsonArray &>();
+  }
+
+  // Gets the variant as an object.
+  // Returns a reference to the JsonObject or JsonObject::invalid() if the
+  // variant is not an object.
+  FORCE_INLINE operator JsonObject &() const {
+    return impl()->template as<JsonObject &>();
+  }
+
+  template <typename T>
+  FORCE_INLINE operator T() const {
+    return impl()->template as<T>();
+  }
+
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/JsonVariantComparisons.hpp b/include/lib/ArduinoJson/JsonVariantComparisons.hpp
new file mode 100644
index 0000000..47f9d63
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantComparisons.hpp
@@ -0,0 +1,139 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsVariant.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantComparisons {
+ public:
+  template <typename TComparand>
+  friend bool operator==(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return variant.equals(comparand);
+  }
+
+  template <typename TComparand>
+  friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+  operator==(TComparand comparand, const JsonVariantComparisons &variant) {
+    return variant.equals(comparand);
+  }
+
+  template <typename TComparand>
+  friend bool operator!=(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return !variant.equals(comparand);
+  }
+
+  template <typename TComparand>
+  friend typename EnableIf<!IsVariant<TComparand>::value, bool>::type
+  operator!=(TComparand comparand, const JsonVariantComparisons &variant) {
+    return !variant.equals(comparand);
+  }
+
+  template <typename TComparand>
+  friend bool operator<=(const JsonVariantComparisons &left, TComparand right) {
+    return left.as<TComparand>() <= right;
+  }
+
+  template <typename TComparand>
+  friend bool operator<=(TComparand comparand,
+                         const JsonVariantComparisons &variant) {
+    return comparand <= variant.as<TComparand>();
+  }
+
+  template <typename TComparand>
+  friend bool operator>=(const JsonVariantComparisons &variant,
+                         TComparand comparand) {
+    return variant.as<TComparand>() >= comparand;
+  }
+
+  template <typename TComparand>
+  friend bool operator>=(TComparand comparand,
+                         const JsonVariantComparisons &variant) {
+    return comparand >= variant.as<TComparand>();
+  }
+
+  template <typename TComparand>
+  friend bool operator<(const JsonVariantComparisons &varian,
+                        TComparand comparand) {
+    return varian.as<TComparand>() < comparand;
+  }
+
+  template <typename TComparand>
+  friend bool operator<(TComparand comparand,
+                        const JsonVariantComparisons &variant) {
+    return comparand < variant.as<TComparand>();
+  }
+
+  template <typename TComparand>
+  friend bool operator>(const JsonVariantComparisons &variant,
+                        TComparand comparand) {
+    return variant.as<TComparand>() > comparand;
+  }
+
+  template <typename TComparand>
+  friend bool operator>(TComparand comparand,
+                        const JsonVariantComparisons &variant) {
+    return comparand > variant.as<TComparand>();
+  }
+
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+
+  template <typename T>
+  const typename JsonVariantAs<T>::type as() const {
+    return impl()->template as<T>();
+  }
+
+  template <typename T>
+  bool is() const {
+    return impl()->template is<T>();
+  }
+
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_equals, bool>::type equals(
+      const TString &comparand) const {
+    const char *value = as<const char *>();
+    return StringTraits<TString>::equals(comparand, value);
+  }
+
+  template <typename TComparand>
+  typename EnableIf<!IsVariant<TComparand>::value &&
+                        !StringTraits<TComparand>::has_equals,
+                    bool>::type
+  equals(const TComparand &comparand) const {
+    return as<TComparand>() == comparand;
+  }
+
+  template <typename TVariant2>
+  bool equals(const JsonVariantComparisons<TVariant2> &right) const {
+    using namespace Internals;
+    if (is<bool>() && right.template is<bool>())
+      return as<bool>() == right.template as<bool>();
+    if (is<JsonInteger>() && right.template is<JsonInteger>())
+      return as<JsonInteger>() == right.template as<JsonInteger>();
+    if (is<JsonFloat>() && right.template is<JsonFloat>())
+      return as<JsonFloat>() == right.template as<JsonFloat>();
+    if (is<JsonArray>() && right.template is<JsonArray>())
+      return as<JsonArray>() == right.template as<JsonArray>();
+    if (is<JsonObject>() && right.template is<JsonObject>())
+      return as<JsonObject>() == right.template as<JsonObject>();
+    if (is<char *>() && right.template is<char *>())
+      return StringTraits<const char *>::equals(as<char *>(),
+                                                right.template as<char *>());
+
+    return false;
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonVariantImpl.hpp b/include/lib/ArduinoJson/JsonVariantImpl.hpp
new file mode 100644
index 0000000..31f96ce
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantImpl.hpp
@@ -0,0 +1,126 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Configuration.hpp"
+#include "JsonArray.hpp"
+#include "JsonObject.hpp"
+#include "JsonVariant.hpp"
+#include "Polyfills/isFloat.hpp"
+#include "Polyfills/isInteger.hpp"
+#include "Polyfills/parseFloat.hpp"
+#include "Polyfills/parseInteger.hpp"
+
+#include <string.h>  // for strcmp
+
+namespace ArduinoJson {
+
+inline JsonVariant::JsonVariant(const JsonArray &array) {
+  if (array.success()) {
+    _type = Internals::JSON_ARRAY;
+    _content.asArray = const_cast<JsonArray *>(&array);
+  } else {
+    _type = Internals::JSON_UNDEFINED;
+  }
+}
+
+inline JsonVariant::JsonVariant(const JsonObject &object) {
+  if (object.success()) {
+    _type = Internals::JSON_OBJECT;
+    _content.asObject = const_cast<JsonObject *>(&object);
+  } else {
+    _type = Internals::JSON_UNDEFINED;
+  }
+}
+
+inline JsonArray &JsonVariant::variantAsArray() const {
+  if (_type == Internals::JSON_ARRAY) return *_content.asArray;
+  return JsonArray::invalid();
+}
+
+inline JsonObject &JsonVariant::variantAsObject() const {
+  if (_type == Internals::JSON_OBJECT) return *_content.asObject;
+  return JsonObject::invalid();
+}
+
+template <typename T>
+inline T JsonVariant::variantAsInteger() const {
+  using namespace Internals;
+  switch (_type) {
+    case JSON_UNDEFINED:
+      return 0;
+    case JSON_POSITIVE_INTEGER:
+    case JSON_BOOLEAN:
+      return T(_content.asInteger);
+    case JSON_NEGATIVE_INTEGER:
+      return T(~_content.asInteger + 1);
+    case JSON_STRING:
+    case JSON_UNPARSED:
+      return parseInteger<T>(_content.asString);
+    default:
+      return T(_content.asFloat);
+  }
+}
+
+inline const char *JsonVariant::variantAsString() const {
+  using namespace Internals;
+  if (_type == JSON_UNPARSED && _content.asString &&
+      !strcmp("null", _content.asString))
+    return NULL;
+  if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
+  return NULL;
+}
+
+template <typename T>
+inline T JsonVariant::variantAsFloat() const {
+  using namespace Internals;
+  switch (_type) {
+    case JSON_UNDEFINED:
+      return 0;
+    case JSON_POSITIVE_INTEGER:
+    case JSON_BOOLEAN:
+      return static_cast<T>(_content.asInteger);
+    case JSON_NEGATIVE_INTEGER:
+      return -static_cast<T>(_content.asInteger);
+    case JSON_STRING:
+    case JSON_UNPARSED:
+      return parseFloat<T>(_content.asString);
+    default:
+      return static_cast<T>(_content.asFloat);
+  }
+}
+
+inline bool JsonVariant::variantIsBoolean() const {
+  using namespace Internals;
+  if (_type == JSON_BOOLEAN) return true;
+
+  if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
+
+  return !strcmp(_content.asString, "true") ||
+         !strcmp(_content.asString, "false");
+}
+
+inline bool JsonVariant::variantIsInteger() const {
+  using namespace Internals;
+
+  return _type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER ||
+         (_type == JSON_UNPARSED && isInteger(_content.asString));
+}
+
+inline bool JsonVariant::variantIsFloat() const {
+  using namespace Internals;
+
+  return _type == JSON_FLOAT || _type == JSON_POSITIVE_INTEGER ||
+         _type == JSON_NEGATIVE_INTEGER ||
+         (_type == JSON_UNPARSED && isFloat(_content.asString));
+}
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
+  return source.printTo(os);
+}
+#endif
+
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonVariantOr.hpp b/include/lib/ArduinoJson/JsonVariantOr.hpp
new file mode 100644
index 0000000..d8022fc
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantOr.hpp
@@ -0,0 +1,52 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+#include "TypeTraits/EnableIf.hpp"
+#include "TypeTraits/IsIntegral.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TImpl>
+class JsonVariantOr {
+ public:
+  // Returns the default value if the JsonVariant is undefined of incompatible
+  template <typename T>
+  typename EnableIf<!IsIntegral<T>::value, T>::type operator|(
+      const T &defaultValue) const {
+    if (impl()->template is<T>())
+      return impl()->template as<T>();
+    else
+      return defaultValue;
+  }
+
+  // Returns the default value if the JsonVariant is undefined of incompatible
+  // Special case for string: null is treated as undefined
+  const char *operator|(const char *defaultValue) const {
+    const char *value = impl()->template as<const char *>();
+    return value ? value : defaultValue;
+  }
+
+  // Returns the default value if the JsonVariant is undefined of incompatible
+  // Special case for integers: we also accept double
+  template <typename Integer>
+  typename EnableIf<IsIntegral<Integer>::value, Integer>::type operator|(
+      const Integer &defaultValue) const {
+    if (impl()->template is<double>())
+      return impl()->template as<Integer>();
+    else
+      return defaultValue;
+  }
+
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/JsonVariantSubscripts.hpp b/include/lib/ArduinoJson/JsonVariantSubscripts.hpp
new file mode 100644
index 0000000..279ee01
--- /dev/null
+++ b/include/lib/ArduinoJson/JsonVariantSubscripts.hpp
@@ -0,0 +1,86 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "Data/JsonVariantAs.hpp"
+#include "Polyfills/attributes.hpp"
+#include "StringTraits/StringTraits.hpp"
+#include "TypeTraits/EnableIf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Forward declarations.
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+
+template <typename TImpl>
+class JsonVariantSubscripts {
+ public:
+  // Mimics an array or an object.
+  // Returns the size of the array or object if the variant has that type.
+  // Returns 0 if the variant is neither an array nor an object
+  size_t size() const {
+    return impl()->template as<JsonArray>().size() +
+           impl()->template as<JsonObject>().size();
+  }
+
+  // Mimics an array.
+  // Returns the element at specified index if the variant is an array.
+  // Returns JsonVariant::invalid() if the variant is not an array.
+  FORCE_INLINE const JsonArraySubscript operator[](size_t index) const;
+  FORCE_INLINE JsonArraySubscript operator[](size_t index);
+
+  // Mimics an object.
+  // Returns the value associated with the specified key if the variant is
+  // an object.
+  // Return JsonVariant::invalid() if the variant is not an object.
+  //
+  // const JsonObjectSubscript operator[](TKey) const;
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  FORCE_INLINE
+      typename EnableIf<StringTraits<TString>::has_equals,
+                        const JsonObjectSubscript<const TString &> >::type
+      operator[](const TString &key) const {
+    return impl()->template as<JsonObject>()[key];
+  }
+  //
+  // const JsonObjectSubscript operator[](TKey) const;
+  // TKey = const std::string&, const String&
+  template <typename TString>
+  FORCE_INLINE typename EnableIf<StringTraits<TString>::has_equals,
+                                 JsonObjectSubscript<const TString &> >::type
+  operator[](const TString &key) {
+    return impl()->template as<JsonObject>()[key];
+  }
+  //
+  // JsonObjectSubscript operator[](TKey);
+  // TKey = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  FORCE_INLINE typename EnableIf<StringTraits<const TString *>::has_equals,
+                                 JsonObjectSubscript<const TString *> >::type
+  operator[](const TString *key) {
+    return impl()->template as<JsonObject>()[key];
+  }
+  //
+  // JsonObjectSubscript operator[](TKey);
+  // TKey = const char*, const char[N], const FlashStringHelper*
+  template <typename TString>
+  FORCE_INLINE
+      typename EnableIf<StringTraits<TString *>::has_equals,
+                        const JsonObjectSubscript<const TString *> >::type
+      operator[](const TString *key) const {
+    return impl()->template as<JsonObject>()[key];
+  }
+
+ private:
+  const TImpl *impl() const {
+    return static_cast<const TImpl *>(this);
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/attributes.hpp b/include/lib/ArduinoJson/Polyfills/attributes.hpp
new file mode 100644
index 0000000..b49091d
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/attributes.hpp
@@ -0,0 +1,29 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#ifdef _MSC_VER  // Visual Studio
+
+#define FORCE_INLINE  // __forceinline causes C4714 when returning std::string
+#define NO_INLINE __declspec(noinline)
+#define DEPRECATED(msg) __declspec(deprecated(msg))
+
+#elif defined(__GNUC__)  // GCC or Clang
+
+#define FORCE_INLINE __attribute__((always_inline))
+#define NO_INLINE __attribute__((noinline))
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define DEPRECATED(msg) __attribute__((deprecated(msg)))
+#else
+#define DEPRECATED(msg) __attribute__((deprecated))
+#endif
+
+#else  // Other compilers
+
+#define FORCE_INLINE
+#define NO_INLINE
+#define DEPRECATED(msg)
+
+#endif
diff --git a/include/lib/ArduinoJson/Polyfills/ctype.hpp b/include/lib/ArduinoJson/Polyfills/ctype.hpp
new file mode 100644
index 0000000..2d52703
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/ctype.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+inline bool isdigit(char c) {
+  return '0' <= c && c <= '9';
+}
+
+inline bool issign(char c) {
+  return '-' == c || c == '+';
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/isFloat.hpp b/include/lib/ArduinoJson/Polyfills/isFloat.hpp
new file mode 100644
index 0000000..973b89f
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/isFloat.hpp
@@ -0,0 +1,38 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <string.h>  // for strcmp
+#include "./ctype.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+inline bool isFloat(const char* s) {
+  if (!s) return false;
+
+  if (!strcmp(s, "NaN")) return true;
+  if (issign(*s)) s++;
+  if (!strcmp(s, "Infinity")) return true;
+  if (*s == '\0') return false;
+
+  while (isdigit(*s)) s++;
+
+  if (*s == '.') {
+    s++;
+    while (isdigit(*s)) s++;
+  }
+
+  if (*s == 'e' || *s == 'E') {
+    s++;
+    if (issign(*s)) s++;
+    if (!isdigit(*s)) return false;
+    while (isdigit(*s)) s++;
+  }
+
+  return *s == '\0';
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/isInteger.hpp b/include/lib/ArduinoJson/Polyfills/isInteger.hpp
new file mode 100644
index 0000000..8049079
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/isInteger.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "./ctype.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+inline bool isInteger(const char* s) {
+  if (!s || !*s) return false;
+  if (issign(*s)) s++;
+  while (isdigit(*s)) s++;
+  return *s == '\0';
+}
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/Polyfills/math.hpp b/include/lib/ArduinoJson/Polyfills/math.hpp
new file mode 100644
index 0000000..48773ed
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/math.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+bool isNaN(T x) {
+  return x != x;
+}
+
+template <typename T>
+bool isInfinity(T x) {
+  return x != 0.0 && x * 2 == x;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/parseFloat.hpp b/include/lib/ArduinoJson/Polyfills/parseFloat.hpp
new file mode 100644
index 0000000..49b0f6f
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/parseFloat.hpp
@@ -0,0 +1,90 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../TypeTraits/FloatTraits.hpp"
+#include "./ctype.hpp"
+#include "./math.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T>
+inline T parseFloat(const char* s) {
+  typedef FloatTraits<T> traits;
+  typedef typename traits::mantissa_type mantissa_t;
+  typedef typename traits::exponent_type exponent_t;
+
+  if (!s) return 0;  // NULL
+
+  bool negative_result = false;
+  switch (*s) {
+    case '-':
+      negative_result = true;
+      s++;
+      break;
+    case '+':
+      s++;
+      break;
+  }
+
+  if (*s == 't') return 1;  // true
+  if (*s == 'n' || *s == 'N') return traits::nan();
+  if (*s == 'i' || *s == 'I')
+    return negative_result ? -traits::inf() : traits::inf();
+
+  mantissa_t mantissa = 0;
+  exponent_t exponent_offset = 0;
+
+  while (isdigit(*s)) {
+    if (mantissa < traits::mantissa_max / 10)
+      mantissa = mantissa * 10 + (*s - '0');
+    else
+      exponent_offset++;
+    s++;
+  }
+
+  if (*s == '.') {
+    s++;
+    while (isdigit(*s)) {
+      if (mantissa < traits::mantissa_max / 10) {
+        mantissa = mantissa * 10 + (*s - '0');
+        exponent_offset--;
+      }
+      s++;
+    }
+  }
+
+  int exponent = 0;
+  if (*s == 'e' || *s == 'E') {
+    s++;
+    bool negative_exponent = false;
+    if (*s == '-') {
+      negative_exponent = true;
+      s++;
+    } else if (*s == '+') {
+      s++;
+    }
+
+    while (isdigit(*s)) {
+      exponent = exponent * 10 + (*s - '0');
+      if (exponent + exponent_offset > traits::exponent_max) {
+        if (negative_exponent)
+          return negative_result ? -0.0f : 0.0f;
+        else
+          return negative_result ? -traits::inf() : traits::inf();
+      }
+      s++;
+    }
+    if (negative_exponent) exponent = -exponent;
+  }
+  exponent += exponent_offset;
+
+  T result = traits::make_float(static_cast<T>(mantissa), exponent);
+
+  return negative_result ? -result : result;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/Polyfills/parseInteger.hpp b/include/lib/ArduinoJson/Polyfills/parseInteger.hpp
new file mode 100644
index 0000000..e8f1974
--- /dev/null
+++ b/include/lib/ArduinoJson/Polyfills/parseInteger.hpp
@@ -0,0 +1,41 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdlib.h>
+
+#include "../Configuration.hpp"
+#include "./ctype.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+template <typename T>
+T parseInteger(const char *s) {
+  if (!s) return 0;  // NULL
+
+  if (*s == 't') return 1;  // "true"
+
+  T result = 0;
+  bool negative_result = false;
+
+  switch (*s) {
+    case '-':
+      negative_result = true;
+      s++;
+      break;
+    case '+':
+      s++;
+      break;
+  }
+
+  while (isdigit(*s)) {
+    result = T(result * 10 + T(*s - '0'));
+    s++;
+  }
+
+  return negative_result ? T(~result + 1) : result;
+}
+}
+}
diff --git a/include/lib/ArduinoJson/RawJson.hpp b/include/lib/ArduinoJson/RawJson.hpp
new file mode 100644
index 0000000..4beb980
--- /dev/null
+++ b/include/lib/ArduinoJson/RawJson.hpp
@@ -0,0 +1,46 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+
+namespace Internals {
+// A special type of data that can be used to insert pregenerated JSON portions.
+template <typename T>
+class RawJsonString {
+ public:
+  explicit RawJsonString(T str) : _str(str) {}
+  operator T() const {
+    return _str;
+  }
+
+ private:
+  T _str;
+};
+
+template <typename String>
+struct StringTraits<RawJsonString<String>, void> {
+  static bool is_null(RawJsonString<String> source) {
+    return StringTraits<String>::is_null(static_cast<String>(source));
+  }
+
+  typedef RawJsonString<const char*> duplicate_t;
+
+  template <typename Buffer>
+  static duplicate_t duplicate(RawJsonString<String> source, Buffer* buffer) {
+    return duplicate_t(StringTraits<String>::duplicate(source, buffer));
+  }
+
+  static const bool has_append = false;
+  static const bool has_equals = false;
+  static const bool should_duplicate = StringTraits<String>::should_duplicate;
+};
+}
+
+template <typename T>
+inline Internals::RawJsonString<T> RawJson(T str) {
+  return Internals::RawJsonString<T>(str);
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/DummyPrint.hpp b/include/lib/ArduinoJson/Serialization/DummyPrint.hpp
new file mode 100644
index 0000000..9fdf2d6
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/DummyPrint.hpp
@@ -0,0 +1,22 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A dummy Print implementation used in JsonPrintable::measureLength()
+class DummyPrint {
+ public:
+  size_t print(char) {
+    return 1;
+  }
+
+  size_t print(const char* s) {
+    return strlen(s);
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp b/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp
new file mode 100644
index 0000000..41be639
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/DynamicStringBuilder.hpp
@@ -0,0 +1,35 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../StringTraits/StringTraits.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A Print implementation that allows to write in a String
+template <typename TString>
+class DynamicStringBuilder {
+ public:
+  DynamicStringBuilder(TString &str) : _str(str) {}
+
+  size_t print(char c) {
+    StringTraits<TString>::append(_str, c);
+    return 1;
+  }
+
+  size_t print(const char *s) {
+    size_t initialLen = _str.length();
+    StringTraits<TString>::append(_str, s);
+    return _str.length() - initialLen;
+  }
+
+ private:
+  DynamicStringBuilder &operator=(const DynamicStringBuilder &);
+
+  TString &_str;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/FloatParts.hpp b/include/lib/ArduinoJson/Serialization/FloatParts.hpp
new file mode 100644
index 0000000..c14e3b5
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/FloatParts.hpp
@@ -0,0 +1,89 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "../Polyfills/math.hpp"
+#include "../TypeTraits/FloatTraits.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TFloat>
+struct FloatParts {
+  uint32_t integral;
+  uint32_t decimal;
+  int16_t exponent;
+  int8_t decimalPlaces;
+
+  FloatParts(TFloat value) {
+    uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
+    decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
+
+    exponent = normalize(value);
+
+    integral = uint32_t(value);
+    // reduce number of decimal places by the number of integral places
+    for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
+      maxDecimalPart /= 10;
+      decimalPlaces--;
+    }
+
+    TFloat remainder = (value - TFloat(integral)) * TFloat(maxDecimalPart);
+
+    decimal = uint32_t(remainder);
+    remainder = remainder - TFloat(decimal);
+
+    // rounding:
+    // increment by 1 if remainder >= 0.5
+    decimal += uint32_t(remainder * 2);
+    if (decimal >= maxDecimalPart) {
+      decimal = 0;
+      integral++;
+      if (exponent && integral >= 10) {
+        exponent++;
+        integral = 1;
+      }
+    }
+
+    // remove trailing zeros
+    while (decimal % 10 == 0 && decimalPlaces > 0) {
+      decimal /= 10;
+      decimalPlaces--;
+    }
+  }
+
+  static int16_t normalize(TFloat& value) {
+    typedef FloatTraits<TFloat> traits;
+    int16_t powersOf10 = 0;
+
+    int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
+    int bit = 1 << index;
+
+    if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
+      for (; index >= 0; index--) {
+        if (value >= traits::positiveBinaryPowerOfTen(index)) {
+          value *= traits::negativeBinaryPowerOfTen(index);
+          powersOf10 = int16_t(powersOf10 + bit);
+        }
+        bit >>= 1;
+      }
+    }
+
+    if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
+      for (; index >= 0; index--) {
+        if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) {
+          value *= traits::positiveBinaryPowerOfTen(index);
+          powersOf10 = int16_t(powersOf10 - bit);
+        }
+        bit >>= 1;
+      }
+    }
+
+    return powersOf10;
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp b/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp
new file mode 100644
index 0000000..864f9aa
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/IndentedPrint.hpp
@@ -0,0 +1,68 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Decorator on top of Print to allow indented output.
+// This class is used by JsonPrintable::prettyPrintTo() but can also be used
+// for your own purpose, like logging.
+template <typename Print>
+class IndentedPrint {
+ public:
+  explicit IndentedPrint(Print &p) : sink(&p) {
+    level = 0;
+    tabSize = 2;
+    isNewLine = true;
+  }
+
+  size_t print(char c) {
+    size_t n = 0;
+    if (isNewLine) n += writeTabs();
+    n += sink->print(c);
+    isNewLine = c == '\n';
+    return n;
+  }
+
+  size_t print(const char *s) {
+    // TODO: optimize
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+
+  // Adds one level of indentation
+  void indent() {
+    if (level < MAX_LEVEL) level++;
+  }
+
+  // Removes one level of indentation
+  void unindent() {
+    if (level > 0) level--;
+  }
+
+  // Set the number of space printed for each level of indentation
+  void setTabSize(uint8_t n) {
+    if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE;
+  }
+
+ private:
+  Print *sink;
+  uint8_t level : 4;
+  uint8_t tabSize : 3;
+  bool isNewLine : 1;
+
+  size_t writeTabs() {
+    size_t n = 0;
+    for (int i = 0; i < level * tabSize; i++) n += sink->print(' ');
+    return n;
+  }
+
+  static const int MAX_LEVEL = 15;    // because it's only 4 bits
+  static const int MAX_TAB_SIZE = 7;  // because it's only 3 bits
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp b/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp
new file mode 100644
index 0000000..43d413a
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonPrintable.hpp
@@ -0,0 +1,117 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+#include "DummyPrint.hpp"
+#include "DynamicStringBuilder.hpp"
+#include "IndentedPrint.hpp"
+#include "JsonSerializer.hpp"
+#include "JsonWriter.hpp"
+#include "Prettyfier.hpp"
+#include "StaticStringBuilder.hpp"
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+#include "StreamPrintAdapter.hpp"
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Implements all the overloads of printTo() and prettyPrintTo()
+// Caution: this class use a template parameter to avoid virtual methods.
+// This is a bit curious but allows to reduce the size of JsonVariant, JsonArray
+// and JsonObject.
+template <typename T>
+class JsonPrintable {
+ public:
+  template <typename Print>
+  typename EnableIf<!StringTraits<Print>::has_append, size_t>::type printTo(
+      Print &print) const {
+    JsonWriter<Print> writer(print);
+    JsonSerializer<JsonWriter<Print> >::serialize(downcast(), writer);
+    return writer.bytesWritten();
+  }
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+  std::ostream &printTo(std::ostream &os) const {
+    StreamPrintAdapter adapter(os);
+    printTo(adapter);
+    return os;
+  }
+#endif
+
+  size_t printTo(char *buffer, size_t bufferSize) const {
+    StaticStringBuilder sb(buffer, bufferSize);
+    return printTo(sb);
+  }
+
+  template <size_t N>
+  size_t printTo(char (&buffer)[N]) const {
+    return printTo(buffer, N);
+  }
+
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_append, size_t>::type printTo(
+      TString &str) const {
+    DynamicStringBuilder<TString> sb(str);
+    return printTo(sb);
+  }
+
+  template <typename Print>
+  size_t prettyPrintTo(IndentedPrint<Print> &print) const {
+    Prettyfier<Print> p(print);
+    return printTo(p);
+  }
+
+  size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
+    StaticStringBuilder sb(buffer, bufferSize);
+    return prettyPrintTo(sb);
+  }
+
+  template <size_t N>
+  size_t prettyPrintTo(char (&buffer)[N]) const {
+    return prettyPrintTo(buffer, N);
+  }
+
+  template <typename Print>
+  typename EnableIf<!StringTraits<Print>::has_append, size_t>::type
+  prettyPrintTo(Print &print) const {
+    IndentedPrint<Print> indentedPrint(print);
+    return prettyPrintTo(indentedPrint);
+  }
+
+  template <typename TString>
+  typename EnableIf<StringTraits<TString>::has_append, size_t>::type
+  prettyPrintTo(TString &str) const {
+    DynamicStringBuilder<TString> sb(str);
+    return prettyPrintTo(sb);
+  }
+
+  size_t measureLength() const {
+    DummyPrint dp;
+    return printTo(dp);
+  }
+
+  size_t measurePrettyLength() const {
+    DummyPrint dp;
+    return prettyPrintTo(dp);
+  }
+
+ private:
+  const T &downcast() const {
+    return *static_cast<const T *>(this);
+  }
+};
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+template <typename T>
+inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
+  return v.printTo(os);
+}
+#endif
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp b/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp
new file mode 100644
index 0000000..0cb537f
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonSerializer.hpp
@@ -0,0 +1,32 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonWriter.hpp"
+
+namespace ArduinoJson {
+
+class JsonArray;
+class JsonObject;
+class JsonVariant;
+
+namespace Internals {
+
+class JsonArraySubscript;
+template <typename TKey>
+class JsonObjectSubscript;
+
+template <typename Writer>
+class JsonSerializer {
+ public:
+  static void serialize(const JsonArray &, Writer &);
+  static void serialize(const JsonArraySubscript &, Writer &);
+  static void serialize(const JsonObject &, Writer &);
+  template <typename TKey>
+  static void serialize(const JsonObjectSubscript<TKey> &, Writer &);
+  static void serialize(const JsonVariant &, Writer &);
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp b/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp
new file mode 100644
index 0000000..0faae27
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonSerializerImpl.hpp
@@ -0,0 +1,103 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../JsonArray.hpp"
+#include "../JsonArraySubscript.hpp"
+#include "../JsonObject.hpp"
+#include "../JsonObjectSubscript.hpp"
+#include "../JsonVariant.hpp"
+#include "JsonSerializer.hpp"
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArray& array, Writer& writer) {
+  writer.beginArray();
+
+  JsonArray::const_iterator it = array.begin();
+  while (it != array.end()) {
+    serialize(*it, writer);
+
+    ++it;
+    if (it == array.end()) break;
+
+    writer.writeComma();
+  }
+
+  writer.endArray();
+}
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonArraySubscript& arraySubscript, Writer& writer) {
+  serialize(arraySubscript.as<JsonVariant>(), writer);
+}
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObject& object, Writer& writer) {
+  writer.beginObject();
+
+  JsonObject::const_iterator it = object.begin();
+  while (it != object.end()) {
+    writer.writeString(it->key);
+    writer.writeColon();
+    serialize(it->value, writer);
+
+    ++it;
+    if (it == object.end()) break;
+
+    writer.writeComma();
+  }
+
+  writer.endObject();
+}
+
+template <typename Writer>
+template <typename TKey>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonObjectSubscript<TKey>& objectSubscript, Writer& writer) {
+  serialize(objectSubscript.template as<JsonVariant>(), writer);
+}
+
+template <typename Writer>
+inline void ArduinoJson::Internals::JsonSerializer<Writer>::serialize(
+    const JsonVariant& variant, Writer& writer) {
+  switch (variant._type) {
+    case JSON_FLOAT:
+      writer.writeFloat(variant._content.asFloat);
+      return;
+
+    case JSON_ARRAY:
+      serialize(*variant._content.asArray, writer);
+      return;
+
+    case JSON_OBJECT:
+      serialize(*variant._content.asObject, writer);
+      return;
+
+    case JSON_STRING:
+      writer.writeString(variant._content.asString);
+      return;
+
+    case JSON_UNPARSED:
+      writer.writeRaw(variant._content.asString);
+      return;
+
+    case JSON_NEGATIVE_INTEGER:
+      writer.writeRaw('-');  // Falls through.
+
+    case JSON_POSITIVE_INTEGER:
+      writer.writeInteger(variant._content.asInteger);
+      return;
+
+    case JSON_BOOLEAN:
+      writer.writeBoolean(variant._content.asInteger != 0);
+      return;
+
+    default:  // JSON_UNDEFINED
+      return;
+  }
+}
diff --git a/include/lib/ArduinoJson/Serialization/JsonWriter.hpp b/include/lib/ArduinoJson/Serialization/JsonWriter.hpp
new file mode 100644
index 0000000..146d51d
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/JsonWriter.hpp
@@ -0,0 +1,155 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdint.h>
+#include "../Data/Encoding.hpp"
+#include "../Data/JsonInteger.hpp"
+#include "../Polyfills/attributes.hpp"
+#include "../Serialization/FloatParts.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Writes the JSON tokens to a Print implementation
+// This class is used by:
+// - JsonArray::writeTo()
+// - JsonObject::writeTo()
+// - JsonVariant::writeTo()
+// Its derived by PrettyJsonWriter that overrides some members to add
+// indentation.
+template <typename Print>
+class JsonWriter {
+ public:
+  explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
+
+  // Returns the number of bytes sent to the Print implementation.
+  // This is very handy for implementations of printTo() that must return the
+  // number of bytes written.
+  size_t bytesWritten() const {
+    return _length;
+  }
+
+  void beginArray() {
+    writeRaw('[');
+  }
+  void endArray() {
+    writeRaw(']');
+  }
+
+  void beginObject() {
+    writeRaw('{');
+  }
+  void endObject() {
+    writeRaw('}');
+  }
+
+  void writeColon() {
+    writeRaw(':');
+  }
+  void writeComma() {
+    writeRaw(',');
+  }
+
+  void writeBoolean(bool value) {
+    writeRaw(value ? "true" : "false");
+  }
+
+  void writeString(const char *value) {
+    if (!value) {
+      writeRaw("null");
+    } else {
+      writeRaw('\"');
+      while (*value) writeChar(*value++);
+      writeRaw('\"');
+    }
+  }
+
+  void writeChar(char c) {
+    char specialChar = Encoding::escapeChar(c);
+    if (specialChar) {
+      writeRaw('\\');
+      writeRaw(specialChar);
+    } else {
+      writeRaw(c);
+    }
+  }
+
+  template <typename TFloat>
+  void writeFloat(TFloat value) {
+    if (isNaN(value)) return writeRaw("NaN");
+
+    if (value < 0.0) {
+      writeRaw('-');
+      value = -value;
+    }
+
+    if (isInfinity(value)) return writeRaw("Infinity");
+
+    FloatParts<TFloat> parts(value);
+
+    writeInteger(parts.integral);
+    if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces);
+
+    if (parts.exponent < 0) {
+      writeRaw("e-");
+      writeInteger(-parts.exponent);
+    }
+
+    if (parts.exponent > 0) {
+      writeRaw('e');
+      writeInteger(parts.exponent);
+    }
+  }
+
+  template <typename UInt>
+  void writeInteger(UInt value) {
+    char buffer[22];
+    char *end = buffer + sizeof(buffer) - 1;
+    char *ptr = end;
+
+    *ptr = 0;
+    do {
+      *--ptr = char(value % 10 + '0');
+      value = UInt(value / 10);
+    } while (value);
+
+    writeRaw(ptr);
+  }
+
+  void writeDecimals(uint32_t value, int8_t width) {
+    // buffer should be big enough for all digits, the dot and the null
+    // terminator
+    char buffer[16];
+    char *ptr = buffer + sizeof(buffer) - 1;
+
+    // write the string in reverse order
+    *ptr = 0;
+    while (width--) {
+      *--ptr = char(value % 10 + '0');
+      value /= 10;
+    }
+    *--ptr = '.';
+
+    // and dump it in the right order
+    writeRaw(ptr);
+  }
+
+  void writeRaw(const char *s) {
+    _length += _sink.print(s);
+  }
+  void writeRaw(char c) {
+    _length += _sink.print(c);
+  }
+
+ protected:
+  Print &_sink;
+  size_t _length;
+
+ private:
+  JsonWriter &operator=(const JsonWriter &);  // cannot be assigned
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/Prettyfier.hpp b/include/lib/ArduinoJson/Serialization/Prettyfier.hpp
new file mode 100644
index 0000000..8b4f0d2
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/Prettyfier.hpp
@@ -0,0 +1,133 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IndentedPrint.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// Converts a compact JSON string into an indented one.
+template <typename Print>
+class Prettyfier {
+ public:
+  explicit Prettyfier(IndentedPrint<Print>& p) : _sink(p) {
+    _previousChar = 0;
+    _inString = false;
+  }
+
+  size_t print(char c) {
+    size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
+    _previousChar = c;
+    return n;
+  }
+
+  size_t print(const char* s) {
+    // TODO: optimize
+    size_t n = 0;
+    while (*s) n += print(*s++);
+    return n;
+  }
+
+ private:
+  Prettyfier& operator=(const Prettyfier&);  // cannot be assigned
+
+  bool inEmptyBlock() {
+    return _previousChar == '{' || _previousChar == '[';
+  }
+
+  size_t handleStringChar(char c) {
+    bool isQuote = c == '"' && _previousChar != '\\';
+
+    if (isQuote) _inString = false;
+
+    return _sink.print(c);
+  }
+
+  size_t handleMarkupChar(char c) {
+    switch (c) {
+      case '{':
+      case '[':
+        return writeBlockOpen(c);
+
+      case '}':
+      case ']':
+        return writeBlockClose(c);
+
+      case ':':
+        return writeColon();
+
+      case ',':
+        return writeComma();
+
+      case '"':
+        return writeQuoteOpen();
+
+      default:
+        return writeNormalChar(c);
+    }
+  }
+
+  size_t writeBlockClose(char c) {
+    size_t n = 0;
+    n += unindentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+
+  size_t writeBlockOpen(char c) {
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+
+  size_t writeColon() {
+    size_t n = 0;
+    n += _sink.print(": ");
+    return n;
+  }
+
+  size_t writeComma() {
+    size_t n = 0;
+    n += _sink.print(",\r\n");
+    return n;
+  }
+
+  size_t writeQuoteOpen() {
+    _inString = true;
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print('"');
+    return n;
+  }
+
+  size_t writeNormalChar(char c) {
+    size_t n = 0;
+    n += indentIfNeeded();
+    n += _sink.print(c);
+    return n;
+  }
+
+  size_t indentIfNeeded() {
+    if (!inEmptyBlock()) return 0;
+
+    _sink.indent();
+    return _sink.print("\r\n");
+  }
+
+  size_t unindentIfNeeded() {
+    if (inEmptyBlock()) return 0;
+
+    _sink.unindent();
+    return _sink.print("\r\n");
+  }
+
+  char _previousChar;
+  IndentedPrint<Print>& _sink;
+  bool _inString;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp b/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp
new file mode 100644
index 0000000..9617bbd
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/StaticStringBuilder.hpp
@@ -0,0 +1,36 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A Print implementation that allows to write in a char[]
+class StaticStringBuilder {
+ public:
+  StaticStringBuilder(char *buf, size_t size) : end(buf + size - 1), p(buf) {
+    *p = '\0';
+  }
+
+  size_t print(char c) {
+    if (p >= end) return 0;
+    *p++ = c;
+    *p = '\0';
+    return 1;
+  }
+
+  size_t print(const char *s) {
+    char *begin = p;
+    while (p < end && *s) *p++ = *s++;
+    *p = '\0';
+    return size_t(p - begin);
+  }
+
+ private:
+  char *end;
+  char *p;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp b/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp
new file mode 100644
index 0000000..60f0af4
--- /dev/null
+++ b/include/lib/ArduinoJson/Serialization/StreamPrintAdapter.hpp
@@ -0,0 +1,39 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+
+#include <ostream>
+
+namespace ArduinoJson {
+namespace Internals {
+
+class StreamPrintAdapter {
+ public:
+  explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
+
+  size_t print(char c) {
+    _os << c;
+    return 1;
+  }
+
+  size_t print(const char* s) {
+    _os << s;
+    return strlen(s);
+  }
+
+ private:
+  // cannot be assigned
+  StreamPrintAdapter& operator=(const StreamPrintAdapter&);
+
+  std::ostream& _os;
+};
+}
+}
+
+#endif  // ARDUINOJSON_ENABLE_STD_STREAM
diff --git a/include/lib/ArduinoJson/StaticJsonBuffer.hpp b/include/lib/ArduinoJson/StaticJsonBuffer.hpp
new file mode 100644
index 0000000..267d9d0
--- /dev/null
+++ b/include/lib/ArduinoJson/StaticJsonBuffer.hpp
@@ -0,0 +1,126 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "JsonBufferBase.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+class StaticJsonBufferBase : public JsonBufferBase<StaticJsonBufferBase> {
+ public:
+  class String {
+   public:
+    String(StaticJsonBufferBase* parent) : _parent(parent) {
+      _start = parent->_buffer + parent->_size;
+    }
+
+    void append(char c) {
+      if (_parent->canAlloc(1)) {
+        char* last = static_cast<char*>(_parent->doAlloc(1));
+        *last = c;
+      }
+    }
+
+    const char* c_str() const {
+      if (_parent->canAlloc(1)) {
+        char* last = static_cast<char*>(_parent->doAlloc(1));
+        *last = '\0';
+        return _start;
+      } else {
+        return NULL;
+      }
+    }
+
+   private:
+    StaticJsonBufferBase* _parent;
+    char* _start;
+  };
+
+  StaticJsonBufferBase(char* buffer, size_t capa)
+      : _buffer(buffer), _capacity(capa), _size(0) {}
+
+  // Gets the capacity of the buffer in bytes
+  size_t capacity() const {
+    return _capacity;
+  }
+
+  // Gets the current usage of the buffer in bytes
+  size_t size() const {
+    return _size;
+  }
+
+  // Allocates the specified amount of bytes in the buffer
+  virtual void* alloc(size_t bytes) {
+    alignNextAlloc();
+    if (!canAlloc(bytes)) return NULL;
+    return doAlloc(bytes);
+  }
+
+  // Resets the buffer.
+  // USE WITH CAUTION: this invalidates all previously allocated data
+  void clear() {
+    _size = 0;
+  }
+
+  String startString() {
+    return String(this);
+  }
+
+ protected:
+  ~StaticJsonBufferBase() {}
+
+ private:
+  void alignNextAlloc() {
+    _size = round_size_up(_size);
+  }
+
+  bool canAlloc(size_t bytes) const {
+    return _size + bytes <= _capacity;
+  }
+
+  void* doAlloc(size_t bytes) {
+    void* p = &_buffer[_size];
+    _size += bytes;
+    return p;
+  }
+
+  char* _buffer;
+  size_t _capacity;
+  size_t _size;
+};
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+// Implements a JsonBuffer with fixed memory allocation.
+// The template paramenter CAPACITY specifies the capacity of the buffer in
+// bytes.
+template <size_t CAPACITY>
+class StaticJsonBuffer : public Internals::StaticJsonBufferBase {
+ public:
+  explicit StaticJsonBuffer()
+      : Internals::StaticJsonBufferBase(_buffer, CAPACITY) {}
+
+ private:
+  char _buffer[CAPACITY];
+};
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#pragma GCC diagnostic pop
+#endif
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp b/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp
new file mode 100644
index 0000000..5db0852
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/ArduinoStream.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
+
+#include <Stream.h>
+
+namespace ArduinoJson {
+namespace Internals {
+
+struct ArduinoStreamTraits {
+  class Reader {
+    Stream& _stream;
+    char _current, _next;
+
+   public:
+    Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {}
+
+    void move() {
+      _current = _next;
+      _next = 0;
+    }
+
+    char current() {
+      if (!_current) _current = read();
+      return _current;
+    }
+
+    char next() {
+      // assumes that current() has been called
+      if (!_next) _next = read();
+      return _next;
+    }
+
+   private:
+    char read() {
+      // don't use _stream.read() as it ignores the timeout
+      char c = 0;
+      _stream.readBytes(&c, 1);
+      return c;
+    }
+  };
+
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+
+template <typename TStream>
+struct StringTraits<
+    TStream,
+    // match any type that is derived from Stream:
+    typename EnableIf<
+        IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type>
+    : ArduinoStreamTraits {};
+}
+}
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/CharPointer.hpp b/include/lib/ArduinoJson/StringTraits/CharPointer.hpp
new file mode 100644
index 0000000..98896cc
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/CharPointer.hpp
@@ -0,0 +1,64 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TChar>
+struct CharPointerTraits {
+  class Reader {
+    const TChar* _ptr;
+
+   public:
+    Reader(const TChar* ptr)
+        : _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
+
+    void move() {
+      ++_ptr;
+    }
+
+    char current() const {
+      return char(_ptr[0]);
+    }
+
+    char next() const {
+      return char(_ptr[1]);
+    }
+  };
+
+  static bool equals(const TChar* str, const char* expected) {
+    const char* actual = reinterpret_cast<const char*>(str);
+    if (!actual || !expected) return actual == expected;
+    return strcmp(actual, expected) == 0;
+  }
+
+  static bool is_null(const TChar* str) {
+    return !str;
+  }
+
+  typedef const char* duplicate_t;
+
+  template <typename Buffer>
+  static duplicate_t duplicate(const TChar* str, Buffer* buffer) {
+    if (!str) return NULL;
+    size_t size = strlen(reinterpret_cast<const char*>(str)) + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy(dup, str, size);
+    return static_cast<duplicate_t>(dup);
+  }
+
+  static const bool has_append = false;
+  static const bool has_equals = true;
+  static const bool should_duplicate = !IsConst<TChar>::value;
+};
+
+// char*, unsigned char*, signed char*
+// const char*, const unsigned char*, const signed char*
+template <typename TChar>
+struct StringTraits<TChar*, typename EnableIf<IsChar<TChar>::value>::type>
+    : CharPointerTraits<TChar> {};
+}  // namespace Internals
+}  // namespace ArduinoJson
diff --git a/include/lib/ArduinoJson/StringTraits/FlashString.hpp b/include/lib/ArduinoJson/StringTraits/FlashString.hpp
new file mode 100644
index 0000000..0701b9b
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/FlashString.hpp
@@ -0,0 +1,61 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_PROGMEM
+
+namespace ArduinoJson {
+namespace Internals {
+template <>
+struct StringTraits<const __FlashStringHelper*, void> {
+  class Reader {
+    const char* _ptr;
+
+   public:
+    Reader(const __FlashStringHelper* ptr)
+        : _ptr(reinterpret_cast<const char*>(ptr)) {}
+
+    void move() {
+      _ptr++;
+    }
+
+    char current() const {
+      return pgm_read_byte_near(_ptr);
+    }
+
+    char next() const {
+      return pgm_read_byte_near(_ptr + 1);
+    }
+  };
+
+  static bool equals(const __FlashStringHelper* str, const char* expected) {
+    const char* actual = reinterpret_cast<const char*>(str);
+    if (!actual || !expected) return actual == expected;
+    return strcmp_P(expected, actual) == 0;
+  }
+
+  static bool is_null(const __FlashStringHelper* str) {
+    return !str;
+  }
+
+  typedef const char* duplicate_t;
+
+  template <typename Buffer>
+  static duplicate_t duplicate(const __FlashStringHelper* str, Buffer* buffer) {
+    if (!str) return NULL;
+    size_t size = strlen_P((const char*)str) + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy_P(dup, (const char*)str, size);
+    return static_cast<duplicate_t>(dup);
+  }
+
+  static const bool has_append = false;
+  static const bool has_equals = true;
+  static const bool should_duplicate = true;
+};
+}  // namespace Internals
+}  // namespace ArduinoJson
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StdStream.hpp b/include/lib/ArduinoJson/StringTraits/StdStream.hpp
new file mode 100644
index 0000000..227c744
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StdStream.hpp
@@ -0,0 +1,60 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_STD_STREAM
+
+#include <istream>
+
+namespace ArduinoJson {
+namespace Internals {
+
+struct StdStreamTraits {
+  class Reader {
+    std::istream& _stream;
+    char _current, _next;
+
+   public:
+    Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {}
+
+    void move() {
+      _current = _next;
+      _next = 0;
+    }
+
+    char current() {
+      if (!_current) _current = read();
+      return _current;
+    }
+
+    char next() {
+      // assumes that current() has been called
+      if (!_next) _next = read();
+      return _next;
+    }
+
+   private:
+    Reader& operator=(const Reader&);  // Visual Studio C4512
+
+    char read() {
+      return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
+    }
+  };
+
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+
+template <typename TStream>
+struct StringTraits<
+    TStream,
+    // match any type that is derived from std::istream:
+    typename EnableIf<IsBaseOf<
+        std::istream, typename RemoveReference<TStream>::type>::value>::type>
+    : StdStreamTraits {};
+}
+}
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StdString.hpp b/include/lib/ArduinoJson/StringTraits/StdString.hpp
new file mode 100644
index 0000000..35f4461
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StdString.hpp
@@ -0,0 +1,77 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#if ARDUINOJSON_ENABLE_STD_STRING || ARDUINOJSON_ENABLE_ARDUINO_STRING
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+#include <WString.h>
+#endif
+
+#if ARDUINOJSON_ENABLE_STD_STRING
+#include <string>
+#endif
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TString>
+struct StdStringTraits {
+  typedef const char* duplicate_t;
+
+  template <typename Buffer>
+  static duplicate_t duplicate(const TString& str, Buffer* buffer) {
+    if (!str.c_str()) return NULL;  // <- Arduino string can return NULL
+    size_t size = str.length() + 1;
+    void* dup = buffer->alloc(size);
+    if (dup != NULL) memcpy(dup, str.c_str(), size);
+    return static_cast<duplicate_t>(dup);
+  }
+
+  static bool is_null(const TString& str) {
+    // Arduino's String::c_str() can return NULL
+    return !str.c_str();
+  }
+
+  struct Reader : CharPointerTraits<char>::Reader {
+    Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
+  };
+
+  static bool equals(const TString& str, const char* expected) {
+    // Arduino's String::c_str() can return NULL
+    const char* actual = str.c_str();
+    if (!actual || !expected) return actual == expected;
+    return 0 == strcmp(actual, expected);
+  }
+
+  static void append(TString& str, char c) {
+    str += c;
+  }
+
+  static void append(TString& str, const char* s) {
+    str += s;
+  }
+
+  static const bool has_append = true;
+  static const bool has_equals = true;
+  static const bool should_duplicate = true;
+};
+
+#if ARDUINOJSON_ENABLE_ARDUINO_STRING
+template <>
+struct StringTraits<String, void> : StdStringTraits<String> {};
+template <>
+struct StringTraits<StringSumHelper, void> : StdStringTraits<StringSumHelper> {
+};
+#endif
+
+#if ARDUINOJSON_ENABLE_STD_STRING
+template <>
+struct StringTraits<std::string, void> : StdStringTraits<std::string> {};
+#endif
+}  // namespace Internals
+}  // namespace ArduinoJson
+
+#endif
diff --git a/include/lib/ArduinoJson/StringTraits/StringTraits.hpp b/include/lib/ArduinoJson/StringTraits/StringTraits.hpp
new file mode 100644
index 0000000..dd5694b
--- /dev/null
+++ b/include/lib/ArduinoJson/StringTraits/StringTraits.hpp
@@ -0,0 +1,36 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <string.h>
+#include "../Configuration.hpp"
+#include "../TypeTraits/EnableIf.hpp"
+#include "../TypeTraits/IsBaseOf.hpp"
+#include "../TypeTraits/IsChar.hpp"
+#include "../TypeTraits/IsConst.hpp"
+#include "../TypeTraits/RemoveReference.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename TString, typename Enable = void>
+struct StringTraits {
+  static const bool has_append = false;
+  static const bool has_equals = false;
+};
+
+template <typename TString>
+struct StringTraits<const TString, void> : StringTraits<TString> {};
+
+template <typename TString>
+struct StringTraits<TString&, void> : StringTraits<TString> {};
+}
+}
+
+#include "ArduinoStream.hpp"
+#include "CharPointer.hpp"
+#include "FlashString.hpp"
+#include "StdStream.hpp"
+#include "StdString.hpp"
diff --git a/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp b/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp
new file mode 100644
index 0000000..83fc5e0
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/EnableIf.hpp
@@ -0,0 +1,19 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T if Condition is true.
+template <bool Condition, typename T = void>
+struct EnableIf {};
+
+template <typename T>
+struct EnableIf<true, T> {
+  typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp b/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp
new file mode 100644
index 0000000..648cc82
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/FloatTraits.hpp
@@ -0,0 +1,171 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include <stdint.h>
+#include <stdlib.h>  // for size_t
+#include "../Configuration.hpp"
+#include "../Polyfills/math.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+template <typename T, size_t = sizeof(T)>
+struct FloatTraits {};
+
+template <typename T>
+struct FloatTraits<T, 8 /*64bits*/> {
+  typedef int64_t mantissa_type;
+  static const short mantissa_bits = 52;
+  static const mantissa_type mantissa_max =
+      (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+
+  typedef int16_t exponent_type;
+  static const exponent_type exponent_max = 308;
+
+  template <typename TExponent>
+  static T make_float(T m, TExponent e) {
+    if (e > 0) {
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= positiveBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    } else {
+      e = TExponent(-e);
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= negativeBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    }
+    return m;
+  }
+
+  static T positiveBinaryPowerOfTen(int index) {
+    static T factors[] = {
+        1e1,
+        1e2,
+        1e4,
+        1e8,
+        1e16,
+        forge(0x4693B8B5, 0xB5056E17),  // 1e32
+        forge(0x4D384F03, 0xE93FF9F5),  // 1e64
+        forge(0x5A827748, 0xF9301D32),  // 1e128
+        forge(0x75154FDD, 0x7F73BF3C)   // 1e256
+    };
+    return factors[index];
+  }
+
+  static T negativeBinaryPowerOfTen(int index) {
+    static T factors[] = {
+        forge(0x3FB99999, 0x9999999A),  // 1e-1
+        forge(0x3F847AE1, 0x47AE147B),  // 1e-2
+        forge(0x3F1A36E2, 0xEB1C432D),  // 1e-4
+        forge(0x3E45798E, 0xE2308C3A),  // 1e-8
+        forge(0x3C9CD2B2, 0x97D889BC),  // 1e-16
+        forge(0x3949F623, 0xD5A8A733),  // 1e-32
+        forge(0x32A50FFD, 0x44F4A73D),  // 1e-64
+        forge(0x255BBA08, 0xCF8C979D),  // 1e-128
+        forge(0x0AC80628, 0x64AC6F43)   // 1e-256
+    };
+    return factors[index];
+  }
+
+  static T negativeBinaryPowerOfTenPlusOne(int index) {
+    static T factors[] = {
+        1e0,
+        forge(0x3FB99999, 0x9999999A),  // 1e-1
+        forge(0x3F50624D, 0xD2F1A9FC),  // 1e-3
+        forge(0x3E7AD7F2, 0x9ABCAF48),  // 1e-7
+        forge(0x3CD203AF, 0x9EE75616),  // 1e-15
+        forge(0x398039D6, 0x65896880),  // 1e-31
+        forge(0x32DA53FC, 0x9631D10D),  // 1e-63
+        forge(0x25915445, 0x81B7DEC2),  // 1e-127
+        forge(0x0AFE07B2, 0x7DD78B14)   // 1e-255
+    };
+    return factors[index];
+  }
+
+  static T nan() {
+    return forge(0x7ff80000, 0x00000000);
+  }
+
+  static T inf() {
+    return forge(0x7ff00000, 0x00000000);
+  }
+
+  // constructs a double floating point values from its binary representation
+  // we use this function to workaround platforms with single precision literals
+  // (for example, when -fsingle-precision-constant is passed to GCC)
+  static T forge(uint32_t msb, uint32_t lsb) {
+    union {
+      uint64_t integerBits;
+      T floatBits;
+    };
+    integerBits = (uint64_t(msb) << 32) | lsb;
+    return floatBits;
+  }
+};
+
+template <typename T>
+struct FloatTraits<T, 4 /*32bits*/> {
+  typedef int32_t mantissa_type;
+  static const short mantissa_bits = 23;
+  static const mantissa_type mantissa_max =
+      (static_cast<mantissa_type>(1) << mantissa_bits) - 1;
+
+  typedef int8_t exponent_type;
+  static const exponent_type exponent_max = 38;
+
+  template <typename TExponent>
+  static T make_float(T m, TExponent e) {
+    if (e > 0) {
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= positiveBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    } else {
+      e = -e;
+      for (uint8_t index = 0; e != 0; index++) {
+        if (e & 1) m *= negativeBinaryPowerOfTen(index);
+        e >>= 1;
+      }
+    }
+    return m;
+  }
+
+  static T positiveBinaryPowerOfTen(int index) {
+    static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f};
+    return factors[index];
+  }
+
+  static T negativeBinaryPowerOfTen(int index) {
+    static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f};
+    return factors[index];
+  }
+
+  static T negativeBinaryPowerOfTenPlusOne(int index) {
+    static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f};
+    return factors[index];
+  }
+
+  static T forge(uint32_t bits) {
+    union {
+      uint32_t integerBits;
+      T floatBits;
+    };
+    integerBits = bits;
+    return floatBits;
+  }
+
+  static T nan() {
+    return forge(0x7fc00000);
+  }
+
+  static T inf() {
+    return forge(0x7f800000);
+  }
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsArray.hpp b/include/lib/ArduinoJson/TypeTraits/IsArray.hpp
new file mode 100644
index 0000000..2599231
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsArray.hpp
@@ -0,0 +1,24 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct IsArray {
+  static const bool value = false;
+};
+template <typename T>
+struct IsArray<T[]> {
+  static const bool value = true;
+};
+template <typename T, size_t N>
+struct IsArray<T[N]> {
+  static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp b/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp
new file mode 100644
index 0000000..bf24e96
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsBaseOf.hpp
@@ -0,0 +1,27 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if Derived inherits from TBase is an
+// integral type.
+template <typename TBase, typename TDerived>
+class IsBaseOf {
+ protected:  // <- to avoid GCC's "all member functions in class are private"
+  typedef char Yes[1];
+  typedef char No[2];
+
+  static Yes &probe(const TBase *);
+  static No &probe(...);
+
+ public:
+  enum {
+    value = sizeof(probe(reinterpret_cast<TDerived *>(0))) == sizeof(Yes)
+  };
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsChar.hpp b/include/lib/ArduinoJson/TypeTraits/IsChar.hpp
new file mode 100644
index 0000000..d97cec2
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsChar.hpp
@@ -0,0 +1,23 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is a charater
+template <typename T>
+struct IsChar {
+  static const bool value = IsSame<T, char>::value ||
+                            IsSame<T, signed char>::value ||
+                            IsSame<T, unsigned char>::value;
+};
+
+template <typename T>
+struct IsChar<const T> : IsChar<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsConst.hpp b/include/lib/ArduinoJson/TypeTraits/IsConst.hpp
new file mode 100644
index 0000000..512ee5c
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsConst.hpp
@@ -0,0 +1,21 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct IsConst {
+  static const bool value = false;
+};
+
+template <typename T>
+struct IsConst<const T> {
+  static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp b/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
new file mode 100644
index 0000000..e41a682
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsFloatingPoint.hpp
@@ -0,0 +1,18 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is a floating point type
+template <typename T>
+struct IsFloatingPoint {
+  static const bool value = IsSame<T, float>::value || IsSame<T, double>::value;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp
new file mode 100644
index 0000000..17ae5f2
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsIntegral.hpp
@@ -0,0 +1,26 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsSame.hpp"
+#include "IsSignedIntegral.hpp"
+#include "IsUnsignedIntegral.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsIntegral {
+  static const bool value = IsSignedIntegral<T>::value ||
+                            IsUnsignedIntegral<T>::value ||
+                            IsSame<T, char>::value;
+  // CAUTION: differs from std::is_integral as it doesn't include bool
+};
+
+template <typename T>
+struct IsIntegral<const T> : IsIntegral<T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsSame.hpp b/include/lib/ArduinoJson/TypeTraits/IsSame.hpp
new file mode 100644
index 0000000..06567c9
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsSame.hpp
@@ -0,0 +1,21 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if types T and U are the same.
+template <typename T, typename U>
+struct IsSame {
+  static const bool value = false;
+};
+
+template <typename T>
+struct IsSame<T, T> {
+  static const bool value = true;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp
new file mode 100644
index 0000000..7334eb9
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsSignedIntegral.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsSignedIntegral {
+  static const bool value =
+      IsSame<T, signed char>::value || IsSame<T, signed short>::value ||
+      IsSame<T, signed int>::value || IsSame<T, signed long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+      IsSame<T, signed long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+      IsSame<T, signed __int64>::value ||
+#endif
+      false;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp b/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp
new file mode 100644
index 0000000..938423f
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsUnsignedIntegral.hpp
@@ -0,0 +1,28 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "../Configuration.hpp"
+#include "IsSame.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that returns true if T is an integral type.
+template <typename T>
+struct IsUnsignedIntegral {
+  static const bool value =
+      IsSame<T, unsigned char>::value || IsSame<T, unsigned short>::value ||
+      IsSame<T, unsigned int>::value || IsSame<T, unsigned long>::value ||
+#if ARDUINOJSON_USE_LONG_LONG
+      IsSame<T, unsigned long long>::value ||
+#endif
+#if ARDUINOJSON_USE_INT64
+      IsSame<T, unsigned __int64>::value ||
+#endif
+      false;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp b/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp
new file mode 100644
index 0000000..f8b299f
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/IsVariant.hpp
@@ -0,0 +1,17 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#include "IsBaseOf.hpp"
+
+namespace ArduinoJson {
+namespace Internals {
+
+class JsonVariantTag {};
+
+template <typename T>
+struct IsVariant : IsBaseOf<JsonVariantTag, T> {};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp b/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp
new file mode 100644
index 0000000..39d4cb5
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/RemoveConst.hpp
@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the const modifier
+template <typename T>
+struct RemoveConst {
+  typedef T type;
+};
+template <typename T>
+struct RemoveConst<const T> {
+  typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp b/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp
new file mode 100644
index 0000000..395a128
--- /dev/null
+++ b/include/lib/ArduinoJson/TypeTraits/RemoveReference.hpp
@@ -0,0 +1,20 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+namespace ArduinoJson {
+namespace Internals {
+
+// A meta-function that return the type T without the reference modifier.
+template <typename T>
+struct RemoveReference {
+  typedef T type;
+};
+template <typename T>
+struct RemoveReference<T&> {
+  typedef T type;
+};
+}
+}
diff --git a/include/lib/ArduinoJson/version.hpp b/include/lib/ArduinoJson/version.hpp
new file mode 100644
index 0000000..a71c3ab
--- /dev/null
+++ b/include/lib/ArduinoJson/version.hpp
@@ -0,0 +1,10 @@
+// ArduinoJson - arduinojson.org
+// Copyright Benoit Blanchon 2014-2018
+// MIT License
+
+#pragma once
+
+#define ARDUINOJSON_VERSION "5.13.2"
+#define ARDUINOJSON_VERSION_MAJOR 5
+#define ARDUINOJSON_VERSION_MINOR 13
+#define ARDUINOJSON_VERSION_REVISION 2
diff --git a/include/lib/ubjson/ubj.h b/include/lib/ubjson/ubj.h
new file mode 100644
index 0000000..a65d104
--- /dev/null
+++ b/include/lib/ubjson/ubj.h
@@ -0,0 +1,230 @@
+#ifndef UBJ_H
+#define UBJ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include<inttypes.h>
+#include<stdio.h>
+
+typedef enum
+{
+	UBJ_MIXED=0,			//NOT a type...or the type is mixed
+
+	UBJ_NULLTYPE,
+	UBJ_NOOP,
+	UBJ_BOOL_TRUE,
+	UBJ_BOOL_FALSE,
+	
+	UBJ_CHAR,
+	UBJ_STRING,
+	UBJ_HIGH_PRECISION,
+
+	UBJ_INT8,
+	UBJ_UINT8 ,
+	UBJ_INT16,
+	UBJ_INT32,
+	UBJ_INT64,
+	UBJ_FLOAT32 ,
+	UBJ_FLOAT64,
+
+	UBJ_ARRAY,
+	UBJ_OBJECT,
+
+	UBJ_NUM_TYPES				//this is the size of how many types there are (chris' trick)
+} UBJ_TYPE;
+
+
+
+//////////here is the declarations for the writer API////////////////////////////////////
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct ubjw_context_t_s;
+typedef struct ubjw_context_t_s ubjw_context_t;
+
+ubjw_context_t* ubjw_open_callback(void* userdata,
+	size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata),
+	int(*close_cb)(void* userdata),
+	void(*error_cb)(const char* error_msg)
+	);
+ubjw_context_t* ubjw_open_file(FILE*);
+ubjw_context_t* ubjw_open_memory(uint8_t* dst_b, uint8_t* dst_e);
+
+size_t ubjw_close_context(ubjw_context_t* ctx);
+
+void ubjw_write_string(ubjw_context_t* dst, const char* out);
+void ubjw_write_char(ubjw_context_t* dst, char out);
+
+void ubjw_write_uint8(ubjw_context_t* dst, uint8_t out);
+void ubjw_write_int8(ubjw_context_t* dst, int8_t out);
+void ubjw_write_int16(ubjw_context_t* dst, int16_t out);
+void ubjw_write_int32(ubjw_context_t* dst, int32_t out);
+void ubjw_write_int64(ubjw_context_t* dst, int64_t out);
+void ubjw_write_high_precision(ubjw_context_t* dst, const char* hp);
+
+void ubjw_write_integer(ubjw_context_t* dst, int64_t out);
+UBJ_TYPE ubjw_min_integer_type(int64_t in);
+
+void ubjw_write_float32(ubjw_context_t* dst, float out);
+void ubjw_write_float64(ubjw_context_t* dst, double out);
+
+void ubjw_write_floating_point(ubjw_context_t* dst, double out);
+
+void ubjw_write_noop(ubjw_context_t* dst);
+void ubjw_write_null(ubjw_context_t* dst);
+void ubjw_write_bool(ubjw_context_t* dst, uint8_t out);
+
+void ubjw_begin_array(ubjw_context_t* dst, UBJ_TYPE type, size_t count);
+
+void ubjw_begin_object(ubjw_context_t* dst, UBJ_TYPE type, size_t count);
+void ubjw_write_key(ubjw_context_t* dst, const char* key);
+void ubjw_end(ubjw_context_t* dst);
+
+//output an efficient buffer of types
+void ubjw_write_buffer(ubjw_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count);
+
+//Proposal for N-D arrays
+void ubjw_begin_ndarray(ubjw_context_t* dst, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+void ubjw_write_ndbuffer(ubjw_context_t* dst,const uint8_t* data, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+
+
+//////////here is the declarations for the reader API////////////////////////////////////
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct ubjr_context_t_s;
+typedef struct ubjr_context_t_s ubjr_context_t;
+
+//Open up a reader context for reading using a custom calllback
+ubjr_context_t* ubjr_open_callback(void* userdata,
+	size_t(*read_cb)(void* data, size_t size, size_t count, void* userdata),
+	int(*peek_cb)(void* userdata),
+	int(*close_cb)(void* userdata),
+	void(*error_cb)(const char* error_msg)
+	);
+
+//Open a context initialized to a UBJ file
+ubjr_context_t* ubjr_open_file(FILE*);
+
+//Open up a context initialized to a memory dump of a UBJ file (or a segment of a UBJ file)
+ubjr_context_t* ubjr_open_memory(const uint8_t* dst_b, const uint8_t* dst_e);
+
+//Close a reader context 
+size_t ubjr_close_context(ubjr_context_t* ctx);
+
+typedef char* ubjr_string_t;
+
+//An array that you read from the stream
+typedef struct ubjr_array_t_s
+{
+	uint8_t originally_sized;
+	UBJ_TYPE type;	
+	size_t size;	//total number of elements
+	void* values;
+	uint8_t num_dims;
+	size_t* dims;	//this could be faster if it was constant size, but would also make the size of the dynamic object a LOT bigger
+
+} ubjr_array_t;
+
+//a map that you read from the stream
+typedef struct ubjr_object_t_s
+{
+	uint8_t originally_sized;
+	UBJ_TYPE type;
+	size_t size;
+	void* values;
+	ubjr_string_t* keys;
+	void* metatable;		//don't use this..only useful for computing object_lookup
+} ubjr_object_t;
+
+//a dynamic type that you parsed.
+typedef struct ubjr_dynamic_t_s
+{
+	UBJ_TYPE type;
+	union
+	{
+		uint8_t boolean;
+		double real;
+		int64_t integer;
+		ubjr_string_t string;
+		ubjr_array_t container_array;
+		ubjr_object_t container_object;
+	};
+} ubjr_dynamic_t;
+
+//Parse a dynamic object from the stream
+ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx);
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn);
+
+ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key);
+size_t ubjr_local_type_size(UBJ_TYPE typ);//should be equivalent to sizeof()
+size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices);
+
+
+//output an efficient buffer of types
+///void ubjr_read_buffer(struct ubjr_context_t* dst, const uint8_t* data, UBJ_TYPE type, size_t count);
+
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn);
+void ubjr_cleanup_array(ubjr_array_t* arr);
+void ubjr_cleanup_object(ubjr_object_t* obj);
+
+
+
+///////UBJ_RW api
+
+void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize);
+//ubjrw_append_object(ubjw_context_t* ctx, ubjr_dynamic_t dobj);
+//ubjrw_append_array(ubjw_context_t* ctx, ubjr_dynamic_t dobj);
+
+#ifdef __cplusplus
+}
+
+#include<iostream>
+
+static size_t write_os(const void* data, size_t size, size_t count, void* userdata)
+{
+	size_t n = size*count;
+	reinterpret_cast<std::ostream*>(userdata)->write(data, n);
+	return n;
+}
+static void close_os(void* userdata)
+{
+	reinterpret_cast<std::ostream*>(userdata)->close();
+}
+
+static size_t read_is(void* data, size_t size, size_t count, void* userdata)
+{
+	size_t n = size*count;
+	reinterpret_cast<std::istream*>(userdata)->read(data, n);
+	return n;
+}
+static int peek_is(void* userdata)
+{
+	return reinterpret_cast<std::istream*>(userdata)->peek();
+}
+static void close_is(void* userdata)
+{
+	reinterpret_cast<std::istream*>(userdata)->close();
+}
+
+static ubjw_context_t* ubjw_open_stream(std::ostream& outstream)
+{
+	return ubjw_open_callback((void*)&outstream, write_os, close_os, NULL);
+}
+
+static ubjr_context_t* ubjr_open_stream(std::istream& instream)
+{
+	return ubjr_open_callback((void*)&instream, read_is, peek_is, close_is, NULL);
+}
+
+
+
+#endif
+
+#endif
diff --git a/include/lib/ubjson/ubj_internal.h b/include/lib/ubjson/ubj_internal.h
new file mode 100644
index 0000000..fc61697
--- /dev/null
+++ b/include/lib/ubjson/ubj_internal.h
@@ -0,0 +1,163 @@
+#ifndef UBJ_INTERNAL_H
+#define UBJ_INTERNAL_H
+
+#include "ubj.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if _MSC_VER
+#define inline __inline
+#endif
+
+
+static const uint8_t UBJI_TYPEC_convert[UBJ_NUM_TYPES] = "\x00ZNTFCSHiUIlLdD[{";
+
+static const int UBJI_TYPE_size[UBJ_NUM_TYPES] =
+	{ -1,	 //MIXED
+	0,	 //NULLTYPE
+	0,	 //NOOP
+	0,   //BOOL_TRUE
+	0,   //BOOL_FALSE
+	1,   //CHAR
+	sizeof(const char*), //STRING
+	sizeof(const char*), //high-precision
+	1,					//INT8
+	1,					//UINT8
+	2,					//int16
+	4,					//int32
+	8,					//int64
+	4,					//float32
+	8,					//float64
+	-1,					//array
+	-1					//object
+	};
+
+static const size_t UBJR_TYPE_localsize[UBJ_NUM_TYPES] =
+{
+	sizeof(ubjr_dynamic_t),	 //MIXED
+	0,	 //NULLTYPE
+	0,	 //NOOP
+	0,   //BOOL_TRUE
+	0,   //BOOL_FALSE
+	sizeof(ubjr_string_t),   //CHAR
+	sizeof(ubjr_string_t), //STRING
+	sizeof(ubjr_string_t), //high-precision
+	sizeof(int8_t),					//INT8
+	sizeof(uint8_t),					//UINT8
+	sizeof(int16_t),					//int16
+	sizeof(int32_t),					//int32
+	sizeof(int64_t),					//int64
+	sizeof(float),					//float32
+	sizeof(double),					//float64
+	sizeof(ubjr_array_t),					//array
+	sizeof(ubjr_object_t)					//object
+};
+
+static inline void _to_bigendian16(uint8_t* outbuffer, uint16_t input)
+{
+	*outbuffer++ = (input >> 8); // Get top order byte (guaranteed endian-independent since machine registers)
+	*outbuffer++ = input & 0xFF; // Get bottom order byte
+}
+static inline void _to_bigendian32(uint8_t* outbuffer, uint32_t input)
+{
+	_to_bigendian16(outbuffer, (uint16_t)(input >> 16)); // Get top order 2 bytes
+	_to_bigendian16(outbuffer + 2, (uint16_t)(input & 0xFFFF)); // Get bottom order 2 bytes
+}
+static inline void _to_bigendian64(uint8_t* outbuffer, uint64_t input)
+{
+	_to_bigendian32(outbuffer, (uint32_t)(input >> 32));
+	_to_bigendian32(outbuffer + 4, (uint32_t)(input & 0xFFFFFFFF));
+}
+
+static inline uint8_t _is_bigendian()
+{
+	int i = 1;
+	char *low = (char*)&i;
+	return *low ? 0 : 1;
+}
+
+#define BUF_BIG_ENDIAN_SWAP(type,func,ptr,num)  \
+	{											\
+		size_t i;type* d = (type*)ptr; 					\
+		for (i = 0; i < num; i++)				\
+		{										\
+			func((uint8_t*)&d[i], d[i]);		\
+		}										\
+	}											\
+
+static inline void buf_endian_swap(uint8_t* buf, size_t sz, size_t n)
+{
+	if (!_is_bigendian())
+	{
+		switch (sz)
+		{
+		case 1:
+		case 0:
+			break;
+		case 2:
+			BUF_BIG_ENDIAN_SWAP(uint16_t, _to_bigendian16,buf,n);
+			break;
+		case 4:
+			BUF_BIG_ENDIAN_SWAP(uint32_t, _to_bigendian32,buf,n);
+			break;
+		case 8:
+			BUF_BIG_ENDIAN_SWAP(uint64_t, _to_bigendian64,buf,n);
+			break;
+		};
+	}
+}
+
+//warning...null-terminated strings are assumed...when this is not necessarily valid. FIXED: we don't use null-terminated strings in the reader (NOT FIXED...string type is awkward)
+static inline ubjr_dynamic_t priv_ubjr_pointer_to_dynamic(UBJ_TYPE typ, const void* dat)
+{
+	ubjr_dynamic_t outdyn;
+	outdyn.type = typ;
+	size_t n = 1;
+	switch (typ)
+	{
+	case UBJ_NULLTYPE:
+	case UBJ_NOOP:
+		break;
+	case UBJ_BOOL_TRUE:
+	case UBJ_BOOL_FALSE:
+		outdyn.boolean = (typ == UBJ_BOOL_TRUE ? 1 : 0);
+		break;
+	case UBJ_HIGH_PRECISION:
+	case UBJ_STRING:
+	case UBJ_CHAR://possibly if char allocate, otherwise don't
+		outdyn.string = *(const ubjr_string_t*)dat;
+		break;
+	case UBJ_INT8:
+		outdyn.integer = *(const int8_t*)dat;
+		break;
+	case UBJ_UINT8:
+		outdyn.integer = *(const uint8_t*)dat;
+		break;
+	case UBJ_INT16:
+		outdyn.integer = *(const int16_t*)dat;
+		break;
+	case UBJ_INT32:
+		outdyn.integer = *(const int32_t*)dat;
+		break;
+	case UBJ_INT64:
+		outdyn.integer = *(const int64_t*)dat;
+		break;
+	case UBJ_FLOAT32:
+		outdyn.real = *(const float*)dat;
+		break;
+	case UBJ_FLOAT64:
+		outdyn.real = *(const double*)dat;
+		break;
+	case UBJ_ARRAY:
+		outdyn.container_array = *(const ubjr_array_t*)dat;
+		break;
+	case UBJ_OBJECT:
+		outdyn.container_object = *(const ubjr_object_t*)dat;
+		break;
+	case UBJ_MIXED:
+		outdyn = *(const ubjr_dynamic_t*)dat;
+	};
+	return outdyn;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/app/prototest/Makefile.inc b/src/app/prototest/Makefile.inc
new file mode 100644
index 0000000..d501de1
--- /dev/null
+++ b/src/app/prototest/Makefile.inc
@@ -0,0 +1,3 @@
+loop ?= 1
+
+TARGETS += src/lib/ubjson/ubjr.c src/lib/ubjson/ubjw.c
diff --git a/src/app/prototest/main.cc b/src/app/prototest/main.cc
new file mode 100644
index 0000000..c7d0838
--- /dev/null
+++ b/src/app/prototest/main.cc
@@ -0,0 +1,30 @@
+#include "arch.h"
+#include "driver/gpio.h"
+#include "driver/stdout.h"
+#include "lib/ArduinoJson.h"
+
+void loop(void)
+{
+	char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+	ArduinoJson::StaticJsonBuffer<200> jsonBuffer;
+	ArduinoJson::JsonObject& root = jsonBuffer.parseObject(json);
+	const char *sensor = root["sensor"];
+	kout << "sensor: " << sensor << endl;
+	gpio.led_toggle(1);
+#ifdef TIMER_S
+	kout << dec << uptime.get_s() << endl;
+#endif
+}
+
+int main(void)
+{
+	arch.setup();
+	gpio.setup();
+	kout.setup();
+
+	gpio.led_on(0);
+	kout << "Hello, World!" << endl;
+	arch.idle_loop();
+
+	return 0;
+}
diff --git a/src/lib/ubjson/ubjr.c b/src/lib/ubjson/ubjr.c
new file mode 100644
index 0000000..461459e
--- /dev/null
+++ b/src/lib/ubjson/ubjr.c
@@ -0,0 +1,516 @@
+#include "lib/ubjson/ubj.h"
+#include "lib/ubjson/ubj_internal.h"
+#include <stdlib.h>
+#include <string.h>
+
+#if _MSC_VER
+#define inline __inline
+#endif
+
+typedef struct ubjr_context_t_s
+{
+	size_t (*read_cb )(void* data, size_t size, size_t count, void* userdata);
+	int (*peek_cb )(void* userdata);
+	int    (*close_cb)(void* userdata);
+	void   (*error_cb)(const char* error_msg);
+
+	void* userdata;
+
+//	struct _ubjr_container_t container_stack[CONTAINER_STACK_MAX];
+//	struct _ubjr_container_t* head;
+
+	uint8_t ignore_container_flags;
+
+	uint16_t last_error_code;
+
+	size_t total_read;
+} ubjr_context_t;
+
+ubjr_context_t* ubjr_open_callback(void* userdata,
+	size_t(*read_cb)(void* data, size_t size, size_t count, void* userdata),
+	int(*peek_cb)(void* userdata),
+	int(*close_cb)(void* userdata),
+	void(*error_cb)(const char* error_msg)
+	)
+{
+	ubjr_context_t* ctx = (ubjr_context_t*)malloc(sizeof(ubjr_context_t));
+	ctx->userdata = userdata;
+	ctx->read_cb = read_cb;
+	ctx->peek_cb = peek_cb;
+	ctx->close_cb = close_cb;
+	ctx->error_cb = error_cb;
+
+
+/*	ctx->head = ctx->container_stack;
+	ctx->head->flags = 0;
+	ctx->head->type = UBJ_MIXED;
+	ctx->head->elements_remaining = 0;
+
+	ctx->ignore_container_flags = 0;*/
+
+	ctx->last_error_code = 0;
+
+	ctx->total_read = 0;
+	return ctx;
+}
+
+size_t ubjr_close_context(ubjr_context_t* ctx)
+{
+	size_t n = ctx->total_read;
+	free(ctx);
+	return n;
+}
+
+static inline uint8_t priv_ubjr_context_getc(ubjr_context_t* ctx)
+{
+	uint8_t a;
+	ctx->total_read += 1;
+	ctx->read_cb(&a, 1, 1, ctx->userdata);
+	return a;
+}
+
+static int fpeek(void* fp)
+{
+    int c;
+    c = fgetc(fp);
+    ungetc(c, fp);
+
+    return c;
+}
+
+ubjr_context_t* ubjr_open_file(FILE* fd)
+{
+	return ubjr_open_callback(fd, (void*)fread,(void*)fpeek,(void*)fclose, NULL);
+}
+
+struct mem_r_fd
+{
+	const uint8_t *begin, *current, *end;
+};
+static int memclose(void* mfd)
+{
+	//free(mfd);
+	return 0;
+}
+static size_t memread(void* data, size_t size, size_t count, struct mem_r_fd* fp)
+{
+	size_t n = size*count;
+	size_t lim = fp->end - fp->current;
+	if (lim < n)
+	{
+		n = lim;
+	}
+	memcpy(data, fp->current, n);
+	fp->current += n;
+	return n;
+}
+static int mempeek(struct mem_r_fd* mfd)
+{
+	return *mfd->current;
+}
+
+ubjr_context_t* ubjr_open_memory(const uint8_t* be, const uint8_t* en)
+{
+	struct mem_r_fd* mfd = (struct mem_r_fd*)malloc(sizeof(struct mem_r_fd));
+	mfd->current = be;
+	mfd->begin = be;
+	mfd->end = en;
+	return ubjr_open_callback(mfd, (void*)memread, (void*)mempeek,(void*)memclose, NULL);
+}
+
+static inline int priv_ubjr_context_peek(ubjr_context_t* ctx)
+{
+	return ctx->peek_cb(ctx->userdata);
+}
+static inline size_t priv_ubjr_context_read(ubjr_context_t* ctx,uint8_t* dst,size_t n)
+{
+	size_t nr=ctx->read_cb(dst,n,1,ctx->userdata);
+	ctx->total_read+=nr;
+	return nr;
+}
+
+typedef struct priv_ubjr_sorted_key_t_s
+{
+	ubjr_string_t key;
+	const uint8_t* value;
+
+} priv_ubjr_sorted_key_t;
+
+static int _obj_key_cmp(const void* av, const void* bv)
+{
+	const priv_ubjr_sorted_key_t *a, *b;
+	a = (const priv_ubjr_sorted_key_t*)av;
+	b = (const priv_ubjr_sorted_key_t*)bv;
+	return strcmp(a->key,b->key);
+}
+
+static inline UBJ_TYPE priv_ubjr_type_from_char(uint8_t c)
+{
+	int i = 0;								//TODO: Benchmark this and see if it should be a switch statement where the compiler implements fastest switch e.g. binary search (17 cases might be binary search fast)
+	for (i = 0; i < UBJ_NUM_TYPES && UBJI_TYPEC_convert[i] != c; i++);
+	return (UBJ_TYPE)i;
+}
+
+size_t ubjr_local_type_size(UBJ_TYPE typ)
+{
+	return UBJR_TYPE_localsize[typ];
+}
+
+
+static inline priv_ubjr_sorted_key_t* priv_ubjr_object_build_sorted_keys(ubjr_object_t* obj)
+{
+	priv_ubjr_sorted_key_t* sorted_keysmem = malloc(obj->size*sizeof(priv_ubjr_sorted_key_t));
+	size_t i;
+	for (i = 0; i < obj->size; i++)
+	{
+		sorted_keysmem[i].key = obj->keys[i];
+		sorted_keysmem[i].value = (const uint8_t*)obj->values + i*UBJR_TYPE_localsize[obj->type];
+	}
+	qsort(sorted_keysmem, obj->size, sizeof(priv_ubjr_sorted_key_t), _obj_key_cmp);
+	return sorted_keysmem;
+}
+
+static inline uint8_t priv_ubjr_read_1b(ubjr_context_t* ctx)
+{
+	return priv_ubjr_context_getc(ctx);
+}
+static inline uint16_t priv_ubjr_read_2b(ubjr_context_t* ctx)
+{
+	return (uint16_t)priv_ubjr_read_1b(ctx) << 8 | (uint16_t)priv_ubjr_read_1b(ctx);
+}
+static inline uint32_t priv_ubjr_read_4b(ubjr_context_t* ctx)
+{
+	return (uint32_t)priv_ubjr_read_2b(ctx) << 16 | (uint32_t)priv_ubjr_read_2b(ctx);
+}
+static inline uint64_t priv_ubjr_read_8b(ubjr_context_t* ctx)
+{
+	return (uint64_t)priv_ubjr_read_4b(ctx) << 32 | (uint64_t)priv_ubjr_read_4b(ctx);
+}
+
+static inline int64_t priv_ubjw_read_integer(ubjr_context_t* ctx)
+{
+	ubjr_dynamic_t d = ubjr_read_dynamic(ctx);
+	if (d.type >= UBJ_INT8 && d.type <= UBJ_INT64)
+		return d.integer;
+	return 0;//error
+}
+
+static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx);
+static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx);
+static inline void priv_ubjr_read_to_ptr(ubjr_context_t* ctx, uint8_t* dst, UBJ_TYPE typ)
+{
+	int64_t n = 1;
+	char *tstr;
+	switch (typ)
+	{
+	case UBJ_MIXED:
+	{
+		*(ubjr_dynamic_t*)dst = ubjr_read_dynamic(ctx);
+		break;
+	}
+	case UBJ_STRING:
+	case UBJ_HIGH_PRECISION:
+	{
+		n = priv_ubjw_read_integer(ctx);
+	}
+	case UBJ_CHAR:
+	{
+		tstr = malloc(n + 1);
+		priv_ubjr_context_read(ctx, tstr, n);
+		tstr[n] = 0;
+		*(ubjr_string_t*)dst = tstr;
+		break;
+	}
+	case UBJ_INT8:
+	case UBJ_UINT8:
+	{
+		*dst = priv_ubjr_read_1b(ctx);
+		break;
+	}
+	case UBJ_INT16:
+	{
+		*(uint16_t*)dst = priv_ubjr_read_2b(ctx);
+		break;
+	}
+	case UBJ_INT32:
+	case UBJ_FLOAT32:
+	{
+		*(uint32_t*)dst = priv_ubjr_read_4b(ctx);
+		break;
+	}
+	case UBJ_INT64:
+	case UBJ_FLOAT64:
+	{
+		*(uint64_t*)dst = priv_ubjr_read_8b(ctx);
+		break;
+	}
+	case UBJ_ARRAY:
+	{
+		*(ubjr_array_t*)dst = priv_ubjr_read_raw_array(ctx);
+		break;
+	}
+	case UBJ_OBJECT:
+	{
+		*(ubjr_object_t*)dst = priv_ubjr_read_raw_object(ctx);
+		break;
+	}
+	};
+}
+
+ubjr_dynamic_t ubjr_object_lookup(ubjr_object_t* obj, const char* key)
+{
+	if (obj->metatable == NULL)
+	{
+		//memcpy(obj->sorted_keys,obj->keys)
+		obj->metatable = priv_ubjr_object_build_sorted_keys(obj);
+	}
+	void* result=bsearch(key, obj->metatable,obj->size, sizeof(priv_ubjr_sorted_key_t),_obj_key_cmp);
+	if (result == NULL)
+	{
+		ubjr_dynamic_t nulldyn;
+		nulldyn.type = UBJ_NULLTYPE;
+		return nulldyn;
+	}
+	const priv_ubjr_sorted_key_t* result_key = (const priv_ubjr_sorted_key_t*)result;
+	return priv_ubjr_pointer_to_dynamic(obj->type,result_key->value);
+}
+
+size_t ubjr_ndarray_index(const ubjr_array_t* arr, const size_t* indices)
+{
+	//multi-dimensional array to linear array lookup
+	size_t cstride = 1;
+	size_t cdex = 0;
+	uint8_t i;
+	uint8_t nd = arr->num_dims;
+	const size_t* dims = arr->dims;
+	for (i = 0; i<nd; i++)
+	{
+		cdex += cstride*indices[i];
+		cstride *= dims[i];
+	}
+	return cdex;
+}
+
+
+
+ubjr_dynamic_t ubjr_read_dynamic(ubjr_context_t* ctx)
+{
+	ubjr_dynamic_t scratch; //scratch memory
+	UBJ_TYPE newtyp = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
+	priv_ubjr_read_to_ptr(ctx, (uint8_t*)&scratch, newtyp);
+	return priv_ubjr_pointer_to_dynamic(newtyp, &scratch);
+}
+
+static inline void priv_read_container_params(ubjr_context_t* ctx, UBJ_TYPE* typout, size_t* sizeout)
+{
+	int nextchar = priv_ubjr_context_peek(ctx);
+	if (nextchar == '$')
+	{
+		priv_ubjr_context_getc(ctx);
+		*typout = priv_ubjr_type_from_char(priv_ubjr_context_getc(ctx));
+		nextchar = priv_ubjr_context_peek(ctx);
+	}
+	else
+	{
+		*typout = UBJ_MIXED;
+	}
+
+	if (nextchar == '#')
+	{
+		priv_ubjr_context_getc(ctx);
+		*sizeout = priv_ubjw_read_integer(ctx);
+	}
+	else
+	{
+		*sizeout = 0;
+	}
+}
+//TODO: This can be reused for object
+
+static inline ubjr_array_t priv_ubjr_read_raw_array(ubjr_context_t* ctx)
+{
+	ubjr_array_t myarray;
+	priv_read_container_params(ctx,&myarray.type,&myarray.size);
+	myarray.num_dims = 1;
+	myarray.dims = NULL;
+	if (myarray.type != UBJ_MIXED && myarray.size==0) //params detected this is a typed array but no size was detected..possibly an N-D array?
+	{
+		if (priv_ubjr_context_peek(ctx) == '@')
+		{
+			uint8_t dselect;
+			priv_ubjr_context_getc(ctx);//skip over the '@' marker
+			myarray.num_dims = priv_ubjr_context_getc(ctx);//since max is 8, no type indicator needed...always a int7 type
+			myarray.dims = malloc(sizeof(size_t)*myarray.num_dims);
+			myarray.size = 1;
+			for (dselect = 0; dselect < myarray.num_dims; dselect++)
+			{
+				size_t d = priv_ubjw_read_integer(ctx);
+				myarray.dims[dselect] = d;
+				myarray.size *= d;
+			}
+		}
+	}
+
+	size_t ls = UBJR_TYPE_localsize[myarray.type];
+	if (myarray.size == 0)
+	{
+		myarray.originally_sized = 0;
+		size_t arrpot = 0;
+		myarray.values=malloc(1*ls+1); //the +1 is for memory for the 0-size elements
+		for (myarray.size = 0; priv_ubjr_context_peek(ctx) != ']'; myarray.size++)
+		{
+			if (myarray.size >= (1ULL << arrpot))
+			{
+				arrpot ++;
+				myarray.values = realloc(myarray.values, (1ULL << arrpot)*ls+1);
+			}
+			priv_ubjr_read_to_ptr(ctx,(uint8_t*)myarray.values + ls*myarray.size,myarray.type);
+		}
+		priv_ubjr_context_getc(ctx); // read the closing ']'
+	}
+	else
+	{
+		myarray.originally_sized = 1;
+		size_t i;
+		myarray.values = malloc(ls*myarray.size+1);
+		size_t sz = UBJI_TYPE_size[myarray.type];
+
+		if (sz >= 0 && myarray.type != UBJ_STRING && myarray.type != UBJ_HIGH_PRECISION && myarray.type != UBJ_CHAR && myarray.type != UBJ_MIXED) //constant size,fastread
+		{
+			priv_ubjr_context_read(ctx, myarray.values, sz*myarray.size);
+			buf_endian_swap(myarray.values, sz, myarray.size); //do nothing for 0-sized buffers
+		}
+		else
+		{
+			for (i = 0; i < myarray.size; i++)
+			{
+				priv_ubjr_read_to_ptr(ctx, (uint8_t*)myarray.values + ls*i, myarray.type);
+			}
+		}
+	}
+	if (myarray.dims == NULL)
+	{
+		myarray.dims = malloc(sizeof(size_t));
+		myarray.dims[0] = myarray.size;
+	}
+	return myarray;
+}
+
+static inline ubjr_object_t priv_ubjr_read_raw_object(ubjr_context_t* ctx)
+{
+	ubjr_object_t myobject;
+	myobject.metatable = NULL;
+	priv_read_container_params(ctx, &myobject.type, &myobject.size);
+
+	size_t ls = UBJR_TYPE_localsize[myobject.type];
+	if (myobject.size == 0)
+	{
+		myobject.originally_sized = 0;
+		size_t arrpot = 0;
+		myobject.values = malloc(1 * ls + 1); //the +1 is for memory for the 0-size elements
+		myobject.keys = malloc(1 * sizeof(ubjr_string_t));
+		for (myobject.size = 0; priv_ubjr_context_peek(ctx) != '}'; myobject.size++)
+		{
+			if (myobject.size >= (1ULL << arrpot))
+			{
+				arrpot++;
+				myobject.values = realloc(myobject.values, (1ULL << arrpot)*ls + 1);
+				myobject.keys = realloc((uint8_t*)myobject.keys, (1ULL << arrpot)*sizeof(ubjr_string_t));
+			}
+			priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + myobject.size), UBJ_STRING);
+			priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*myobject.size, myobject.type);
+		}
+		priv_ubjr_context_getc(ctx); // read the closing '}'
+	}
+	else
+	{
+		size_t i;
+		myobject.originally_sized = 1;
+		myobject.values = malloc(ls*myobject.size + 1);
+		myobject.keys = malloc(myobject.size * sizeof(ubjr_string_t));
+
+		for (i = 0; i < myobject.size; i++)
+		{
+			priv_ubjr_read_to_ptr(ctx, (uint8_t*)(myobject.keys + i), UBJ_STRING);
+			priv_ubjr_read_to_ptr(ctx, (uint8_t*)myobject.values + ls*i, myobject.type);
+		}
+	}
+	return myobject;
+}
+static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value);
+static inline priv_ubjr_cleanup_container(UBJ_TYPE type,size_t size,void* values)
+{
+	if(type == UBJ_MIXED || type == UBJ_ARRAY || type == UBJ_OBJECT || type == UBJ_STRING)
+	{
+		size_t ls=UBJR_TYPE_localsize[type];
+		uint8_t *viter,*vend;
+		viter=values;
+		vend=viter+ls*size;
+		for(;viter != vend;viter+=ls)
+		{
+			priv_ubjr_cleanup_pointer(type,(void*)viter);
+		}
+	}
+	free(values);
+}
+static inline void priv_ubjr_cleanup_pointer(UBJ_TYPE typ,void* value)
+{
+	switch(typ)
+	{
+		case UBJ_MIXED:
+		{
+			ubjr_dynamic_t* dyn=(ubjr_dynamic_t*)value;
+			switch(dyn->type)
+			{
+			case UBJ_STRING:
+				priv_ubjr_cleanup_pointer(UBJ_STRING,&dyn->string);
+				break;
+			case UBJ_ARRAY:
+				priv_ubjr_cleanup_pointer(UBJ_ARRAY,&dyn->container_array);
+				break;
+			case UBJ_OBJECT:
+				priv_ubjr_cleanup_pointer(UBJ_OBJECT,&dyn->container_object);
+				break;
+			};
+			break;
+		}
+		case UBJ_STRING:
+		{
+			ubjr_string_t* st=(ubjr_string_t*)value;
+			free((void*)*st);
+			break;
+		}
+		case UBJ_ARRAY:
+		{
+			ubjr_array_t* arr=(ubjr_array_t*)value;
+			priv_ubjr_cleanup_container(arr->type,arr->size,arr->values);
+			free(arr->dims);
+			break;
+		}
+		case UBJ_OBJECT:
+		{
+			ubjr_object_t* obj=(ubjr_object_t*)value;
+			priv_ubjr_cleanup_container(obj->type,obj->size,obj->values);
+			priv_ubjr_cleanup_container(UBJ_STRING,obj->size,obj->keys);
+			if(obj->metatable)
+			{
+				free(obj->metatable);
+			}
+			break;
+		}
+	};
+}
+
+void ubjr_cleanup_dynamic(ubjr_dynamic_t* dyn)
+{
+	priv_ubjr_cleanup_pointer(UBJ_MIXED,dyn);
+}
+void ubjr_cleanup_array(ubjr_array_t* arr)
+{
+	priv_ubjr_cleanup_pointer(UBJ_ARRAY,arr);
+}
+void ubjr_cleanup_object(ubjr_object_t* obj)
+{
+	priv_ubjr_cleanup_pointer(UBJ_OBJECT,obj);
+}
+
diff --git a/src/lib/ubjson/ubjrw.c b/src/lib/ubjson/ubjrw.c
new file mode 100644
index 0000000..5b8b102
--- /dev/null
+++ b/src/lib/ubjson/ubjrw.c
@@ -0,0 +1,169 @@
+#include "lib/ubjson/ubj_internal.h"
+
+static uint32_t compute_typemask(ubjr_dynamic_t* vals, size_t sz)
+{
+	uint32_t typemask = 0;
+	size_t i;
+	for (i = 0; i < sz; i++)
+	{
+		typemask |= 1UL << vals[i].type;
+	}
+	return typemask;
+}
+
+static inline UBJ_TYPE typemask2type(uint32_t v)
+{
+	unsigned int r = 0; // r will be lg(v)
+
+	while (v >>= 1) // unroll for more speed...
+	{
+		r++;
+	}
+	return (UBJ_TYPE)r;
+}
+static UBJ_TYPE compute_best_integer_type(ubjr_dynamic_t* vals, size_t sz)
+{
+	uint32_t typemask = 0;
+	size_t i;
+	for (i = 0; i < sz; i++)
+	{
+		typemask |= 1UL << ubjw_min_integer_type(vals[i].integer);
+	}
+	return typemask2type(typemask);
+}
+static uint32_t compute_best_string_type(ubjr_dynamic_t* vals, size_t sz)
+{
+	size_t i;
+	for (i = 0; i < sz; i++)
+	{
+		if (strlen(vals[i].string) > 1)
+		{
+			return UBJ_STRING;
+		}
+	}
+	return UBJ_CHAR;
+}
+static UBJ_TYPE optimize_type(UBJ_TYPE typein,ubjr_dynamic_t* vals, size_t sz)
+{
+	static const uint32_t intmask = (1 << UBJ_INT8) | (1 << UBJ_UINT8) | (1 << UBJ_INT16) | (1 << UBJ_INT32) | (1 << UBJ_INT64);
+	static const uint32_t stringmask = (1 << UBJ_STRING) | (1 << UBJ_CHAR);
+	if (typein != UBJ_MIXED)
+		return typein;
+	//integer optimization can be done here...
+	uint32_t tm = compute_typemask(vals, sz);
+	if ((tm & intmask) == tm) //if all values are integers
+	{
+		return compute_best_integer_type(vals,sz);	//calculate the optimum type given the data
+	}
+	else if ((tm & stringmask) == tm)
+	{
+		return compute_best_string_type(vals,sz);
+	}
+	else if(tm && !(tm & (tm- 1)))  //if only one bit is set in typemask
+	{
+		return typemask2type(tm); //figure out which bit is set.
+	}
+	else
+	{
+		return UBJ_MIXED;
+	}
+}
+
+void ubjrw_write_dynamic(ubjw_context_t* ctx, ubjr_dynamic_t dobj,uint8_t optimize)
+{
+	UBJ_TYPE ctyp,otyp;
+	size_t csize;
+	uint8_t* cvalues;
+	switch (dobj.type)
+	{
+	case UBJ_MIXED:
+		return;///error, can't be mixed
+	case UBJ_NULLTYPE:
+		ubjw_write_null(ctx);
+		return;
+	case UBJ_NOOP:
+		ubjw_write_noop(ctx);
+		return;
+	case UBJ_BOOL_FALSE:
+		ubjw_write_bool(ctx, 0);
+		return;
+	case UBJ_BOOL_TRUE:
+		ubjw_write_bool(ctx, 1);
+		return;
+	case UBJ_CHAR:
+		ubjw_write_char(ctx, *dobj.string);//first character of string
+		return;
+	case UBJ_STRING:
+		ubjw_write_string(ctx, dobj.string);
+		return;
+	case UBJ_HIGH_PRECISION:
+		ubjw_write_high_precision(ctx, dobj.string);
+		return;
+	case UBJ_INT8:
+		ubjw_write_int8(ctx, (int8_t)dobj.integer);
+		return;
+	case UBJ_UINT8:
+		ubjw_write_uint8(ctx, (uint8_t)dobj.integer);
+		return;
+	case UBJ_INT16:
+		ubjw_write_int16(ctx, (int16_t)dobj.integer);
+		return;
+	case UBJ_INT32:
+		ubjw_write_int32(ctx, (int32_t)dobj.integer);
+		return;
+	case UBJ_INT64:
+		ubjw_write_int64(ctx, dobj.integer);
+		return;
+	case UBJ_FLOAT32:
+		ubjw_write_float32(ctx, (float)dobj.real);
+		return;
+	case UBJ_FLOAT64:
+		ubjw_write_float64(ctx, dobj.real);
+		return;
+	case UBJ_ARRAY:
+		if ((dobj.container_array.originally_sized || optimize) //if we optimize an unsized array to a sized one or the original is sized
+			&& dobj.container_array.type != UBJ_MIXED 
+			&& dobj.container_array.type != UBJ_OBJECT 
+			&& dobj.container_array.type != UBJ_ARRAY)
+		{
+			ubjw_write_buffer(ctx, dobj.container_array.values, dobj.container_array.type, dobj.container_array.size);
+			return;
+		}
+		else
+		{
+			ctyp = dobj.container_array.type;
+			csize = dobj.container_array.size;
+			cvalues = dobj.container_array.values;
+			otyp = optimize ? optimize_type(ctyp,(ubjr_dynamic_t*)cvalues,csize) : ctyp;
+			ubjw_begin_array(ctx, otyp, (dobj.container_array.originally_sized || optimize) ? csize : 0);
+			break;
+		}
+	case UBJ_OBJECT:
+		{
+			ctyp = dobj.container_object.type;
+			csize = dobj.container_object.size;
+			cvalues = dobj.container_object.values;
+			otyp = optimize ? optimize_type(ctyp, (ubjr_dynamic_t*)cvalues, csize) : ctyp;
+			ubjw_begin_object(ctx, otyp, (dobj.container_object.originally_sized || optimize) ? csize : 0);
+			break;
+		}
+	};
+	{
+		size_t i;
+		ubjr_dynamic_t scratch;
+		size_t ls = UBJR_TYPE_localsize[ctyp];
+
+		for (i = 0; i < csize; i++)
+		{
+			if (dobj.type == UBJ_OBJECT)
+			{
+				ubjw_write_key(ctx, dobj.container_object.keys[i]);
+			}
+			scratch = priv_ubjr_pointer_to_dynamic(ctyp, cvalues + ls*i);
+			scratch.type = (otyp == UBJ_MIXED ? scratch.type : otyp);
+			ubjrw_write_dynamic(ctx, scratch,optimize);
+		}
+		ubjw_end(ctx);
+	}
+
+}
diff --git a/src/lib/ubjson/ubjw.c b/src/lib/ubjson/ubjw.c
new file mode 100644
index 0000000..78eec83
--- /dev/null
+++ b/src/lib/ubjson/ubjw.c
@@ -0,0 +1,618 @@
+#include "lib/ubjson/ubj.h"
+#include "lib/ubjson/ubj_internal.h"
+
+#define CONTAINER_IS_SIZED		0x1
+#define CONTAINER_IS_TYPED		0x2
+#define CONTAINER_IS_UBJ_ARRAY		0x4
+#define CONTAINER_IS_UBJ_OBJECT		0x8
+
+#define CONTAINER_EXPECTS_KEY	0x10
+
+#define CONTAINER_STACK_MAX		64
+#define BUFFER_OUT_SIZE			1024
+
+#define MAX_DIMS	8
+
+
+struct priv_ubjw_container_t
+{
+	uint8_t flags;
+	UBJ_TYPE type;
+	size_t elements_remaining;
+};
+
+struct ubjw_context_t_s
+{
+	size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata);
+	int(*close_cb)(void* userdata);
+	void (*error_cb)(const char* error_msg);
+	
+	void* userdata;
+
+	struct priv_ubjw_container_t container_stack[CONTAINER_STACK_MAX];
+	struct priv_ubjw_container_t* head;
+
+	uint8_t ignore_container_flags;
+
+	uint16_t last_error_code;
+
+	size_t total_written;
+};
+
+
+
+ubjw_context_t* ubjw_open_callback(void* userdata,
+	size_t(*write_cb)(const void* data, size_t size, size_t count, void* userdata),
+	int(*close_cb)(void* userdata),
+	void (*error_cb)(const char* error_msg)
+ 					)
+{
+	ubjw_context_t* ctx = (ubjw_context_t*)malloc(sizeof(ubjw_context_t));
+	ctx->userdata = userdata;
+	ctx->write_cb = write_cb;
+	ctx->close_cb = close_cb;
+	ctx->error_cb = error_cb;
+	
+	ctx->head = ctx->container_stack;
+	ctx->head->flags = 0;
+	ctx->head->type = UBJ_MIXED;
+	ctx->head->elements_remaining = 0;
+	//ctx->head->num_dims=1;
+
+	ctx->ignore_container_flags = 0;
+
+	ctx->last_error_code = 0;
+
+	ctx->total_written = 0;
+	return ctx;
+}
+ubjw_context_t* ubjw_open_file(FILE* fd)
+{
+	return ubjw_open_callback(fd, (void*)fwrite,(void*)fclose,NULL);
+}
+
+struct mem_w_fd
+{
+	uint8_t *begin,*current, *end;
+};
+
+static int memclose(void* mfd)
+{
+	free(mfd);
+	return 0;
+}
+static size_t memwrite(const void* data, size_t size, size_t count, struct mem_w_fd* fp)
+{
+	size_t n = size*count;
+	size_t lim = fp->end - fp->current;
+	if (lim < n)
+	{
+		n = lim;
+	}
+	memcpy(fp->current, data, n);
+	fp->current += n;
+	return n;
+}
+
+ubjw_context_t* ubjw_open_memory(uint8_t* be, uint8_t* en)
+{
+	struct mem_w_fd* mfd = (struct mem_w_fd*)malloc(sizeof(struct mem_w_fd));
+	mfd->current = be;
+	mfd->begin = be;
+	mfd->end = en;
+	return ubjw_open_callback(mfd, (void*)memwrite, (void*)memclose,NULL);
+}
+
+static inline void priv_ubjw_context_append(ubjw_context_t* ctx, uint8_t a)
+{
+	ctx->total_written += 1;
+	ctx->write_cb(&a, 1, 1, ctx->userdata);
+}
+
+static inline void priv_disassembly_begin(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+	priv_ubjw_context_append(ctx, (uint8_t)'[');
+#endif
+}
+static inline void priv_disassembly_end(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+	priv_ubjw_context_append(ctx, (uint8_t)']');
+#endif
+}
+static inline void priv_disassembly_indent(ubjw_context_t* ctx)
+{
+#ifdef UBJW_DISASSEMBLY_MODE
+	int n = ctx->head - ctx->container_stack;
+	int i;
+	priv_ubjw_context_append(ctx, (uint8_t)'\n');
+	for (i = 0; i < n; i++)
+	{
+		priv_ubjw_context_append(ctx, (uint8_t)'\t');
+	}
+#endif
+}
+
+static inline void priv_ubjw_context_finish_container(ubjw_context_t* ctx, struct priv_ubjw_container_t* head)
+{
+	if (head->flags & CONTAINER_IS_SIZED)
+	{
+		if (head->elements_remaining > 0)
+		{
+			//error not all elements written
+		}
+	}
+	else
+	{
+		priv_disassembly_begin(ctx);
+		if (head->flags & CONTAINER_IS_UBJ_ARRAY)
+		{
+			priv_ubjw_context_append(ctx, (uint8_t)']');
+		}
+		else if (head->flags & CONTAINER_IS_UBJ_OBJECT)
+		{
+			priv_ubjw_context_append(ctx, (uint8_t)'}');
+		}
+		priv_disassembly_end(ctx);
+	}
+}
+
+static inline priv_ubjw_container_stack_push(ubjw_context_t* ctx, const struct priv_ubjw_container_t* cnt)
+{
+	size_t height = ctx->head-ctx->container_stack+1;
+	if(height < CONTAINER_STACK_MAX)
+	{
+		*(++(ctx->head))=*cnt;
+	}
+	else
+	{
+		//todo::error
+	}
+}
+static inline struct priv_ubjw_container_t priv_ubjw_container_stack_pop(ubjw_context_t* ctx)
+{
+	return *ctx->head--;
+}
+
+size_t ubjw_close_context(ubjw_context_t* ctx)
+{
+	while (ctx->head > ctx->container_stack)
+	{
+		struct priv_ubjw_container_t cnt = priv_ubjw_container_stack_pop(ctx);
+		priv_ubjw_context_finish_container(ctx, &cnt);
+	};
+	size_t n = ctx->total_written;
+	if (ctx->close_cb)
+		ctx->close_cb(ctx->userdata);
+	free(ctx);
+	return n;
+}
+
+
+static inline size_t priv_ubjw_context_write(ubjw_context_t* ctx, const uint8_t* data, size_t sz)
+{
+	ctx->total_written += sz;
+	return ctx->write_cb(data, 1, sz, ctx->userdata);
+}
+
+static inline void priv_ubjw_tag_public(ubjw_context_t* ctx, UBJ_TYPE tid)
+{
+	struct priv_ubjw_container_t* ch = ctx->head;
+	if (!ctx->ignore_container_flags)
+	{
+
+		/*if (
+			(!(ch->flags & (CONTAINER_IS_UBJ_ARRAY | CONTAINER_IS_UBJ_OBJECT))) &&
+			(tid != UBJ_ARRAY && tid !=UBJ_OBJECT))
+		{
+			//error, only array and object can be first written
+		}*/
+
+		if (ch->flags & CONTAINER_IS_UBJ_OBJECT)
+		{
+			if (ch->flags & CONTAINER_EXPECTS_KEY)
+			{
+				//error,a key expected
+				return;
+			}
+			ch->flags |= CONTAINER_EXPECTS_KEY; //set key expected next time in this context
+		}
+		else
+		{
+			priv_disassembly_indent(ctx);
+		}
+
+		if (ch->flags & CONTAINER_IS_SIZED)
+		{
+			ch->elements_remaining--; //todo: error if elements remaining is 0;
+		}
+
+		if ((ch->flags & CONTAINER_IS_TYPED) && ch->type == tid)
+		{
+			return;
+		}
+	}
+	priv_disassembly_begin(ctx);
+	priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[tid]);
+	priv_disassembly_end(ctx);
+}
+
+static inline void priv_ubjw_write_raw_string(ubjw_context_t* ctx, const char* out)//TODO: possibly use a safe string
+{
+	size_t n = strlen(out);
+	ctx->ignore_container_flags = 1; 
+	ubjw_write_integer(ctx, (int64_t)n);
+	ctx->ignore_container_flags = 0;
+	priv_disassembly_begin(ctx);
+	priv_ubjw_context_write(ctx, (const uint8_t*)out, n);
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_string(ubjw_context_t* ctx, const char* out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_STRING);
+	priv_ubjw_write_raw_string(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_char(ubjw_context_t* ctx, char out)
+{
+	priv_disassembly_begin(ctx);
+	priv_ubjw_context_append(ctx, (uint8_t)out);
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_char(ubjw_context_t* ctx, char out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_CHAR);
+	priv_ubjw_write_raw_char(ctx, out);
+}
+
+#ifndef min
+static inline size_t min(size_t x,size_t y)
+{
+	return x < y ? x : y;
+}
+#endif
+
+#ifdef UBJW_DISASSEMBLY_MODE
+#include <stdarg.h>  
+#define DISASSEMBLY_PRINT_BUFFER_SIZE 1024
+
+static inline priv_disassembly_print(ubjw_context_t* ctx, const char* format,...)
+{
+	char buffer[DISASSEMBLY_PRINT_BUFFER_SIZE];
+	va_list args; 
+	va_start(args, format);
+	int n=vsnprintf(buffer, DISASSEMBLY_PRINT_BUFFER_SIZE, format, args);
+	n = min(n, DISASSEMBLY_PRINT_BUFFER_SIZE);
+	priv_ubjw_context_write(ctx, buffer,n);
+	va_end(args);
+}
+#endif
+
+static inline void priv_ubjw_write_raw_uint8(ubjw_context_t* ctx, uint8_t out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	priv_ubjw_context_append(ctx, out);
+#else
+	priv_disassembly_print(ctx, "%hhu", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_uint8(ubjw_context_t* ctx, uint8_t out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_UINT8);
+	priv_ubjw_write_raw_uint8(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_int8(ubjw_context_t* ctx, int8_t out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	priv_ubjw_context_append(ctx, *(uint8_t*)&out);
+#else
+	priv_disassembly_print(ctx, "%hhd", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_int8(ubjw_context_t* ctx, int8_t out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_INT8);
+	priv_ubjw_write_raw_int8(ctx, out);
+}
+
+static inline void priv_ubjw_write_raw_int16(ubjw_context_t* ctx, int16_t out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	uint8_t buf[2];
+	_to_bigendian16(buf, *(uint16_t*)&out);
+	priv_ubjw_context_write(ctx, buf, 2);
+#else
+	priv_disassembly_print(ctx, "%hd", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_int16(ubjw_context_t* ctx, int16_t out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_INT16);
+	priv_ubjw_write_raw_int16(ctx, out);
+}
+static inline void priv_ubjw_write_raw_int32(ubjw_context_t* ctx, int32_t out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	uint8_t buf[4];
+	_to_bigendian32(buf, *(uint32_t*)&out);
+	priv_ubjw_context_write(ctx, buf, 4);
+#else
+	priv_disassembly_print(ctx, "%ld", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_int32(ubjw_context_t* ctx, int32_t out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_INT32);
+	priv_ubjw_write_raw_int32(ctx, out);
+}
+static inline void priv_ubjw_write_raw_int64(ubjw_context_t* ctx, int64_t out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	uint8_t buf[8];
+	_to_bigendian64(buf, *(uint64_t*)&out);
+	priv_ubjw_context_write(ctx, buf, 8);
+#else
+	priv_disassembly_print(ctx, "%lld", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_int64(ubjw_context_t* ctx, int64_t out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_INT64);
+	priv_ubjw_write_raw_int64(ctx, out);
+}
+
+void ubjw_write_high_precision(ubjw_context_t* ctx, const char* hp)
+{
+	priv_ubjw_tag_public(ctx,UBJ_HIGH_PRECISION);
+	priv_ubjw_write_raw_string(ctx, hp);
+}
+UBJ_TYPE ubjw_min_integer_type(int64_t in)
+{
+	uint64_t mc = llabs(in);
+	if (mc < 0x80)
+	{
+		return UBJ_INT8;
+	}
+	else if (in > 0 && mc < 0x100)
+	{
+		return UBJ_UINT8;
+	}
+	else if (mc < 0x8000)
+	{
+		return UBJ_INT16;
+	}
+	else if (mc < 0x80000000)
+	{
+		return UBJ_INT32;
+	}
+	else
+	{
+		return UBJ_INT64;
+	}
+}
+
+void ubjw_write_integer(ubjw_context_t* ctx, int64_t out)
+{
+	switch (ubjw_min_integer_type(out))
+	{
+	case UBJ_INT8:
+		ubjw_write_int8(ctx, (int8_t)out);
+		break;
+	case UBJ_UINT8:
+		ubjw_write_uint8(ctx, (uint8_t)out);
+		break;
+	case UBJ_INT16:
+		ubjw_write_int16(ctx, (int16_t)out);
+		break;
+	case UBJ_INT32:
+		ubjw_write_int32(ctx, (int32_t)out);
+		break;
+	default:
+		ubjw_write_int64(ctx, out);
+		break;
+	};
+}
+
+static inline void priv_ubjw_write_raw_float32(ubjw_context_t* ctx, float out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	uint32_t fout = *(uint32_t*)&out;
+	uint8_t outbuf[4];
+	_to_bigendian32(outbuf, fout);
+	priv_ubjw_context_write(ctx, outbuf, 4);
+#else
+	priv_disassembly_print(ctx, "%g", out);
+#endif
+	priv_disassembly_end(ctx);
+
+}
+void ubjw_write_float32(ubjw_context_t* ctx, float out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_FLOAT32);
+	priv_ubjw_write_raw_float32(ctx, out);
+}
+static inline void priv_ubjw_write_raw_float64(ubjw_context_t* ctx, double out)
+{
+	priv_disassembly_begin(ctx);
+#ifndef UBJW_DISASSEMBLY_MODE
+	uint64_t fout = *(uint64_t*)&out;
+	uint8_t outbuf[8];
+	_to_bigendian64(outbuf, fout);
+	priv_ubjw_context_write(ctx, outbuf, 8);
+#else
+	priv_disassembly_print(ctx, "%g", out);
+#endif
+	priv_disassembly_end(ctx);
+}
+void ubjw_write_float64(ubjw_context_t* ctx, double out)
+{
+	priv_ubjw_tag_public(ctx,UBJ_FLOAT64);
+	priv_ubjw_write_raw_float64(ctx, out);
+}
+
+void ubjw_write_floating_point(ubjw_context_t* ctx, double out)
+{
+	//this may not be possible to implement correctly...for now we just write it as a float64'
+	ubjw_write_float64(ctx,out);
+}
+
+void ubjw_write_noop(ubjw_context_t* ctx)
+{
+	priv_ubjw_tag_public(ctx,UBJ_NOOP);
+}
+void ubjw_write_null(ubjw_context_t* ctx)
+{
+	priv_ubjw_tag_public(ctx,UBJ_NULLTYPE);
+}
+void ubjw_write_bool(ubjw_context_t* ctx, uint8_t out)
+{
+	priv_ubjw_tag_public(ctx,(out ? UBJ_BOOL_TRUE : UBJ_BOOL_FALSE));
+}
+
+void priv_ubjw_begin_container(struct priv_ubjw_container_t* cnt, ubjw_context_t* ctx, UBJ_TYPE typ, size_t count)
+{
+	cnt->flags=0;
+	cnt->elements_remaining = count;
+	cnt->type = typ;
+
+	if (typ != UBJ_MIXED)
+	{
+		if (count == 0)
+		{
+			//error and return;
+		}
+		priv_disassembly_begin(ctx);
+		priv_ubjw_context_append(ctx, '$');
+		priv_disassembly_end(ctx);
+
+		priv_disassembly_begin(ctx);
+		priv_ubjw_context_append(ctx, UBJI_TYPEC_convert[typ]);
+		priv_disassembly_end(ctx);
+
+		cnt->flags |= CONTAINER_IS_TYPED;
+	}
+	if (count != 0)
+	{
+		priv_disassembly_begin(ctx);
+		priv_ubjw_context_append(ctx, '#');
+		priv_disassembly_end(ctx);
+
+		ctx->ignore_container_flags = 1;
+		ubjw_write_integer(ctx, (int64_t)count);
+		ctx->ignore_container_flags = 0;
+		
+		cnt->flags |= CONTAINER_IS_SIZED;
+		cnt->elements_remaining = count;
+	}
+}
+void ubjw_begin_array(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
+{
+	priv_ubjw_tag_public(ctx, UBJ_ARRAY); //todo: should this happen before any erro potential?
+	struct priv_ubjw_container_t ch;
+	priv_ubjw_begin_container(&ch, ctx, type, count);
+	ch.flags |= CONTAINER_IS_UBJ_ARRAY;
+	priv_ubjw_container_stack_push(ctx, &ch);
+}
+void ubjw_begin_ndarray(ubjw_context_t* dst, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+void ubjw_write_ndbuffer(ubjw_context_t* dst, const uint8_t* data, UBJ_TYPE type, const size_t* dims, uint8_t ndims);
+
+void ubjw_begin_object(ubjw_context_t* ctx, UBJ_TYPE type, size_t count)
+{
+	priv_ubjw_tag_public(ctx, UBJ_OBJECT);
+	struct priv_ubjw_container_t ch;
+	priv_ubjw_begin_container(&ch, ctx, type, count);
+	ch.flags |= CONTAINER_EXPECTS_KEY | CONTAINER_IS_UBJ_OBJECT;
+	priv_ubjw_container_stack_push(ctx, &ch);
+}
+void ubjw_write_key(ubjw_context_t* ctx, const char* key)
+{
+	if (ctx->head->flags & CONTAINER_EXPECTS_KEY && ctx->head->flags & CONTAINER_IS_UBJ_OBJECT)
+	{
+		priv_disassembly_indent(ctx);
+		priv_ubjw_write_raw_string(ctx, key);
+		ctx->head->flags ^= CONTAINER_EXPECTS_KEY; //turn off container 
+	}
+	else
+	{
+		//error unexpected key
+	}
+}
+void ubjw_end(ubjw_context_t* ctx)
+{
+	struct priv_ubjw_container_t ch = priv_ubjw_container_stack_pop(ctx);
+	if ((ch.flags & CONTAINER_IS_UBJ_OBJECT) && !(ch.flags & CONTAINER_EXPECTS_KEY))
+	{
+		//error expected value
+	}
+	priv_disassembly_indent(ctx);
+	priv_ubjw_context_finish_container(ctx, &ch);
+}
+
+
+static inline void priv_ubjw_write_byteswap(ubjw_context_t* ctx, const uint8_t* data, int sz, size_t count)
+{
+	uint8_t buf[BUFFER_OUT_SIZE];
+
+	size_t i;
+	size_t nbytes = sz*count;
+	for (i = 0; i < nbytes; i+=BUFFER_OUT_SIZE)
+	{
+		size_t npass = min(nbytes - i, BUFFER_OUT_SIZE);
+		memcpy(buf, data + i, npass);
+		buf_endian_swap(buf, sz, npass/sz);
+		priv_ubjw_context_write(ctx, buf, npass);
+	}
+}
+void ubjw_write_buffer(ubjw_context_t* ctx, const uint8_t* data, UBJ_TYPE type, size_t count)
+{
+	int typesz = UBJI_TYPE_size[type];
+	if (typesz < 0)
+	{
+		//error cannot write an STC buffer of this type.
+	}
+	ubjw_begin_array(ctx, type, count);
+	if (type == UBJ_STRING || type == UBJ_HIGH_PRECISION)
+	{
+		const char** databufs = (const char**)data;
+		size_t i;
+		for (i = 0; i < count; i++)
+		{
+			priv_ubjw_write_raw_string(ctx, databufs[i]);
+		}
+	}
+#ifndef UBJW_DISASSEMBLY_MODE
+	else if (typesz == 1 || _is_bigendian())
+	{
+		size_t n = typesz*count;
+		priv_ubjw_context_write(ctx, data, typesz*count);
+	}
+	else if (typesz > 1) //and not big-endian
+	{
+		priv_ubjw_write_byteswap(ctx, data,typesz,count);
+	}
+#else
+	else
+	{
+		size_t i;
+		for (i = 0; i < count; i++)
+		{
+			ubjr_dynamic_t dyn = priv_ubjr_pointer_to_dynamic(type, data + i*typesz);
+			ubjrw_write_dynamic(ctx, dyn, 0);
+		}
+	}
+#endif
+	ubjw_end(ctx);
+}
-- 
GitLab