Browse Source

2023-02-17 - 2023-03-03
- huge code review, many changes to improve stability
- basic multilanguage support (pre-compile option)
- all strings used in program moved to header files and stored in progmem
- nearly all modules/features are now pre-compile configurable via settings.h and/or build flags
- move sensors configuration out of thermostat configuration as it will also be used in other firmware variants
- firmware variant HEATCONTROL code complete and well tested (currently only language version DE is fully implemented)
- firmware variant THERMOSTAT taken over from WiFiThermostat but not yet finished
- other firmware variants as "WiFiBlinds" (UART to MQTT bridge) not yet implemented

2023-02-17
- update arduinoWebSockets-2.1.4 -> arduinoWebSockets-2.3.6
##- update DHT-sensor-library-1.3.8 -> DHT-sensor-library-1.4.4
##- update Adafruit_Sensor-1.1.1 -> Adafruit_Sensor-1.1.7 (previously unused? necessary for DHT-sensor-library-1.3.8)
## --> reverted as often could not read DHT sensor with it. did not investigate why.
- update ArduinoJson-6.13.0 -> ArduinoJson-6.20.1
- update pubsubclient-2.7 -> pubsubclient-2.8
- update Bounce2-2.52 -> Bounce2-2.71
- building with ESP8266 Arduino Core v3.0.2 works now (but not tested much yet)
- building with ESP8266 Arduino Core v3.1.1 works now (but not tested much yet)
- FS: replaced deprecated SPIFFS with LittleFS
- config: complete rework - now saves binary structs instead of overly complicated to maintain json files to file system
- config: move secrets to its own struct, which is saved to "EEPROM" instead of file system to make extracting passwords much harder
- config: improve XOR encryption of secrets

2023-02-01
- started "universal" base firmware using code base of WiFiThermostat v0.7.1
- merged with WiFiBlinds dev version (also initially starting from WiFiThermostat) which already had many improvements
- make firmware variant configurable by pre-compile config switches

FloKra 1 year ago
commit
bafd39560a
100 changed files with 7746 additions and 0 deletions
  1. 6 0
      .clang-format
  2. 6 0
      .gitignore
  3. 67 0
      .travis.yml
  4. 10 0
      .vscode/extensions.json
  5. 3 0
      .vscode/settings.json
  6. 30 0
      changelog.txt
  7. 108 0
      lib/Adafruit_Sensor-1.1.7/.gitignore
  8. 87 0
      lib/Adafruit_Sensor-1.1.7/Adafruit_Sensor.cpp
  9. 196 0
      lib/Adafruit_Sensor-1.1.7/Adafruit_Sensor.h
  10. 202 0
      lib/Adafruit_Sensor-1.1.7/LICENSE.txt
  11. 239 0
      lib/Adafruit_Sensor-1.1.7/README.md
  12. 153 0
      lib/Adafruit_Sensor-1.1.7/examples/sensortest/sensortest.ino
  13. 11 0
      lib/Adafruit_Sensor-1.1.7/library.properties
  14. 16 0
      lib/Arduino-Temperature-Control-Library-3.9.1/.gitignore
  15. 1033 0
      lib/Arduino-Temperature-Control-Library-3.9.1/DallasTemperature.cpp
  16. 317 0
      lib/Arduino-Temperature-Control-Library-3.9.1/DallasTemperature.h
  17. 72 0
      lib/Arduino-Temperature-Control-Library-3.9.1/README.md
  18. 162 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Alarm/Alarm.ino
  19. 144 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/AlarmHandler/AlarmHandler.ino
  20. 35 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/ExternalPullup/ExternalPullup.ino
  21. 43 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Multibus_simple/Multibus_simple.ino
  22. 148 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Multiple/Multiple.ino
  23. 106 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/SaveRecallScratchPad/SaveRecallScratchPad.ino
  24. 47 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/SetUserData/SetUserData.ino
  25. 51 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Simple/Simple.ino
  26. 121 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Single/Single.ino
  27. 129 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Tester/Tester.ino
  28. 77 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/Timing/Timing.ino
  29. 45 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/TwoPin_DS18B20/TwoPin_DS18B20.ino
  30. 115 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/UserDataDemo/UserDataDemo.ino
  31. 107 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/UserDataWriteBatch/UserDataWriteBatch.ino
  32. 66 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/WaitForConversion/WaitForConversion.ino
  33. 80 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/WaitForConversion2/WaitForConversion2.ino
  34. 67 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/oneWireSearch/oneWireSearch.ino
  35. 92 0
      lib/Arduino-Temperature-Control-Library-3.9.1/examples/readPowerSupply/readPowerSupply.ino
  36. 78 0
      lib/Arduino-Temperature-Control-Library-3.9.1/keywords.txt
  37. 38 0
      lib/Arduino-Temperature-Control-Library-3.9.1/library.json
  38. 10 0
      lib/Arduino-Temperature-Control-Library-3.9.1/library.properties
  39. 12 0
      lib/ArduinoJson-6.20.1/.clang-format
  40. 1 0
      lib/ArduinoJson-6.20.1/.gitattributes
  41. 4 0
      lib/ArduinoJson-6.20.1/.github/FUNDING.yml
  42. 54 0
      lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/bug_report.md
  43. 8 0
      lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/config.yml
  44. 19 0
      lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/feature_request.md
  45. 51 0
      lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/help.md
  46. 602 0
      lib/ArduinoJson-6.20.1/.github/workflows/ci.yml
  47. 14 0
      lib/ArduinoJson-6.20.1/.github/workflows/lock.yml
  48. 74 0
      lib/ArduinoJson-6.20.1/.github/workflows/release.yml
  49. 20 0
      lib/ArduinoJson-6.20.1/.gitignore
  50. 3 0
      lib/ArduinoJson-6.20.1/.mbedignore
  51. 1 0
      lib/ArduinoJson-6.20.1/.prettierignore
  52. 14 0
      lib/ArduinoJson-6.20.1/.vscode/settings.json
  53. 5 0
      lib/ArduinoJson-6.20.1/ArduinoJson.h
  54. 825 0
      lib/ArduinoJson-6.20.1/CHANGELOG.md
  55. 25 0
      lib/ArduinoJson-6.20.1/CMakeLists.txt
  56. 10 0
      lib/ArduinoJson-6.20.1/CONTRIBUTING.md
  57. 10 0
      lib/ArduinoJson-6.20.1/LICENSE.txt
  58. 160 0
      lib/ArduinoJson-6.20.1/README.md
  59. 27 0
      lib/ArduinoJson-6.20.1/SUPPORT.md
  60. 37 0
      lib/ArduinoJson-6.20.1/appveyor.yml
  61. 1 0
      lib/ArduinoJson-6.20.1/component.mk
  62. 160 0
      lib/ArduinoJson-6.20.1/examples/JsonConfigFile/JsonConfigFile.ino
  63. 63 0
      lib/ArduinoJson-6.20.1/examples/JsonFilterExample/JsonFilterExample.ino
  64. 77 0
      lib/ArduinoJson-6.20.1/examples/JsonGeneratorExample/JsonGeneratorExample.ino
  65. 126 0
      lib/ArduinoJson-6.20.1/examples/JsonHttpClient/JsonHttpClient.ino
  66. 80 0
      lib/ArduinoJson-6.20.1/examples/JsonParserExample/JsonParserExample.ino
  67. 117 0
      lib/ArduinoJson-6.20.1/examples/JsonServer/JsonServer.ino
  68. 106 0
      lib/ArduinoJson-6.20.1/examples/JsonUdpBeacon/JsonUdpBeacon.ino
  69. 75 0
      lib/ArduinoJson-6.20.1/examples/MsgPackParser/MsgPackParser.ino
  70. 63 0
      lib/ArduinoJson-6.20.1/examples/ProgmemExample/ProgmemExample.ino
  71. 77 0
      lib/ArduinoJson-6.20.1/examples/StringExample/StringExample.ino
  72. 4 0
      lib/ArduinoJson-6.20.1/extras/ArduinoJsonConfig.cmake.in
  73. 101 0
      lib/ArduinoJson-6.20.1/extras/CompileOptions.cmake
  74. 8 0
      lib/ArduinoJson-6.20.1/extras/ci/espidf/CMakeLists.txt
  75. 6 0
      lib/ArduinoJson-6.20.1/extras/ci/espidf/main/CMakeLists.txt
  76. 4 0
      lib/ArduinoJson-6.20.1/extras/ci/espidf/main/component.mk
  77. 16 0
      lib/ArduinoJson-6.20.1/extras/ci/espidf/main/main.cpp
  78. 10 0
      lib/ArduinoJson-6.20.1/extras/ci/particle.sh
  79. 16 0
      lib/ArduinoJson-6.20.1/extras/conf_test/avr.cpp
  80. 16 0
      lib/ArduinoJson-6.20.1/extras/conf_test/esp8266.cpp
  81. 15 0
      lib/ArduinoJson-6.20.1/extras/conf_test/x64.cpp
  82. 15 0
      lib/ArduinoJson-6.20.1/extras/conf_test/x86.cpp
  83. 59 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/CMakeLists.txt
  84. 22 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/Makefile
  85. 2 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_corpus/.gitignore
  86. 11 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_fuzzer.cpp
  87. 10 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Comments.json
  88. 1 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/EmptyArray.json
  89. 1 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/EmptyObject.json
  90. 1 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/ExcessiveNesting.json
  91. 1 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/IntegerOverflow.json
  92. 24 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Numbers.json
  93. 53 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/OpenWeatherMap.json
  94. 8 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Strings.json
  95. 90 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/WeatherUnderground.json
  96. 2 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_corpus/.gitignore
  97. 11 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_fuzzer.cpp
  98. BIN
      lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/array16
  99. BIN
      lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/array32
  100. 1 0
      lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/false

+ 6 - 0
.clang-format

@@ -0,0 +1,6 @@
+UseTab: (VS Code current setting)
+IndentWidth: (VS Code current setting)
+BreakBeforeBraces: Allman
+AllowShortIfStatementsOnASingleLine: true
+IndentCaseLabels: false
+ColumnLimit: 0

+ 6 - 0
.gitignore

@@ -0,0 +1,6 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
+src/settings_secrets.h

+ 67 - 0
.travis.yml

@@ -0,0 +1,67 @@
+# Continuous Integration (CI) is the practice, in software
+# engineering, of merging all developer working copies with a shared mainline
+# several times a day < https://docs.platformio.org/page/ci/index.html >
+#
+# Documentation:
+#
+# * Travis CI Embedded Builds with PlatformIO
+#   < https://docs.travis-ci.com/user/integration/platformio/ >
+#
+# * PlatformIO integration with Travis CI
+#   < https://docs.platformio.org/page/ci/travis.html >
+#
+# * User Guide for `platformio ci` command
+#   < https://docs.platformio.org/page/userguide/cmd_ci.html >
+#
+#
+# Please choose one of the following templates (proposed below) and uncomment
+# it (remove "# " before each line) or use own configuration according to the
+# Travis CI documentation (see above).
+#
+
+
+#
+# Template #1: General project. Test it using existing `platformio.ini`.
+#
+
+# language: python
+# python:
+#     - "2.7"
+#
+# sudo: false
+# cache:
+#     directories:
+#         - "~/.platformio"
+#
+# install:
+#     - pip install -U platformio
+#     - platformio update
+#
+# script:
+#     - platformio run
+
+
+#
+# Template #2: The project is intended to be used as a library with examples.
+#
+
+# language: python
+# python:
+#     - "2.7"
+#
+# sudo: false
+# cache:
+#     directories:
+#         - "~/.platformio"
+#
+# env:
+#     - PLATFORMIO_CI_SRC=path/to/test/file.c
+#     - PLATFORMIO_CI_SRC=examples/file.ino
+#     - PLATFORMIO_CI_SRC=path/to/test/directory
+#
+# install:
+#     - pip install -U platformio
+#     - platformio update
+#
+# script:
+#     - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

+ 10 - 0
.vscode/extensions.json

@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}

+ 3 - 0
.vscode/settings.json

@@ -0,0 +1,3 @@
+{
+    "C_Cpp.dimInactiveRegions": false
+}

+ 30 - 0
changelog.txt

@@ -0,0 +1,30 @@
+2023-02-17 - 2023-03-03
+	- huge code review, many changes to improve stability
+	- basic multilanguage support (pre-compile option)
+		- all strings used in program moved to header files and stored in progmem
+	- nearly all modules/features are now pre-compile configurable via settings.h and/or build flags
+	- move sensors configuration out of thermostat configuration as it will also be used in other firmware variants
+	- firmware variant HEATCONTROL code complete and well tested (currently only language version DE is fully implemented)
+	- firmware variant THERMOSTAT taken over from WiFiThermostat but not yet finished
+	- other firmware variants as "WiFiBlinds" (UART to MQTT bridge) not yet implemented
+	
+2023-02-17
+	- update arduinoWebSockets-2.1.4 -> arduinoWebSockets-2.3.6
+	##- update DHT-sensor-library-1.3.8 -> DHT-sensor-library-1.4.4
+	##- update Adafruit_Sensor-1.1.1 -> Adafruit_Sensor-1.1.7 (previously unused? necessary for DHT-sensor-library-1.3.8) 
+	##  --> reverted as often could not read DHT sensor with it. did not investigate why.
+	- update ArduinoJson-6.13.0 -> ArduinoJson-6.20.1
+	- update pubsubclient-2.7 -> pubsubclient-2.8
+	- update Bounce2-2.52 -> Bounce2-2.71
+	- building with ESP8266 Arduino Core v3.0.2 works now (but not tested much yet)
+	- building with ESP8266 Arduino Core v3.1.1 works now (but not tested much yet)
+	- FS: replaced deprecated SPIFFS with LittleFS
+	- config: complete rework - now saves binary structs instead of overly complicated to maintain json files to file system
+	- config: move secrets to its own struct, which is saved to "EEPROM" instead of file system to make extracting passwords much harder
+	- config: improve XOR encryption of secrets
+	
+2023-02-01
+	- started "universal" base firmware using code base of WiFiThermostat v0.7.1
+	- merged with WiFiBlinds dev version (also initially starting from WiFiThermostat) which already had many improvements
+	- make firmware variant configurable by pre-compile config switches
+	

+ 108 - 0
lib/Adafruit_Sensor-1.1.7/.gitignore

@@ -0,0 +1,108 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.ko
+*.so
+*.so.dbg
+*.mod.c
+*.i
+*.lst
+*.symtypes
+*.order
+modules.builtin
+*.elf
+*.bin
+*.gz
+*.bz2
+*.lzma
+*.patch
+*.gcno
+
+#
+# Top-level generic files
+#
+/tags
+/TAGS
+/linux
+/vmlinux
+/vmlinuz
+/System.map
+/Module.markers
+/Module.symvers
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+!.mailmap
+
+#
+# Generated include files
+#
+include/config
+include/linux/version.h
+include/generated
+
+# stgit generated dirs
+patches-*
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+# QT-Creator files
+Makefile.am.user
+*.config
+*.creator
+*.creator.user
+*.files
+*.includes
+
+*.orig
+*~
+\#*#
+*.lo
+*.la
+Makefile
+Makefile.in
+aclocal.m4
+autoconfig.h
+autoconfig.h.in
+autom4te.cache/
+build-aux/
+config.log
+config.status
+configure
+libtool
+libupnp.pc
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+stamp-h1
+docs/doxygen
+

+ 87 - 0
lib/Adafruit_Sensor-1.1.7/Adafruit_Sensor.cpp

@@ -0,0 +1,87 @@
+#include "Adafruit_Sensor.h"
+
+/**************************************************************************/
+/*!
+    @brief  Prints sensor information to serial console
+*/
+/**************************************************************************/
+void Adafruit_Sensor::printSensorDetails(void) {
+  sensor_t sensor;
+  getSensor(&sensor);
+  Serial.println(F("------------------------------------"));
+  Serial.print(F("Sensor:       "));
+  Serial.println(sensor.name);
+  Serial.print(F("Type:         "));
+  switch ((sensors_type_t)sensor.type) {
+  case SENSOR_TYPE_ACCELEROMETER:
+    Serial.print(F("Acceleration (m/s2)"));
+    break;
+  case SENSOR_TYPE_MAGNETIC_FIELD:
+    Serial.print(F("Magnetic (uT)"));
+    break;
+  case SENSOR_TYPE_ORIENTATION:
+    Serial.print(F("Orientation (degrees)"));
+    break;
+  case SENSOR_TYPE_GYROSCOPE:
+    Serial.print(F("Gyroscopic (rad/s)"));
+    break;
+  case SENSOR_TYPE_LIGHT:
+    Serial.print(F("Light (lux)"));
+    break;
+  case SENSOR_TYPE_PRESSURE:
+    Serial.print(F("Pressure (hPa)"));
+    break;
+  case SENSOR_TYPE_PROXIMITY:
+    Serial.print(F("Distance (cm)"));
+    break;
+  case SENSOR_TYPE_GRAVITY:
+    Serial.print(F("Gravity (m/s2)"));
+    break;
+  case SENSOR_TYPE_LINEAR_ACCELERATION:
+    Serial.print(F("Linear Acceleration (m/s2)"));
+    break;
+  case SENSOR_TYPE_ROTATION_VECTOR:
+    Serial.print(F("Rotation vector"));
+    break;
+  case SENSOR_TYPE_RELATIVE_HUMIDITY:
+    Serial.print(F("Relative Humidity (%)"));
+    break;
+  case SENSOR_TYPE_AMBIENT_TEMPERATURE:
+    Serial.print(F("Ambient Temp (C)"));
+    break;
+  case SENSOR_TYPE_OBJECT_TEMPERATURE:
+    Serial.print(F("Object Temp (C)"));
+    break;
+  case SENSOR_TYPE_VOLTAGE:
+    Serial.print(F("Voltage (V)"));
+    break;
+  case SENSOR_TYPE_CURRENT:
+    Serial.print(F("Current (mA)"));
+    break;
+  case SENSOR_TYPE_COLOR:
+    Serial.print(F("Color (RGBA)"));
+    break;
+  case SENSOR_TYPE_TVOC:
+    Serial.print(F("Total Volatile Organic Compounds (ppb)"));
+    break;
+  case SENSOR_TYPE_VOC_INDEX:
+    Serial.print(F("Volatile Organic Compounds (Index)"));
+    break;
+  case SENSOR_TYPE_NOX_INDEX:
+    Serial.print(F("Nitrogen Oxides (Index)"));
+    break;
+  }
+
+  Serial.println();
+  Serial.print(F("Driver Ver:   "));
+  Serial.println(sensor.version);
+  Serial.print(F("Unique ID:    "));
+  Serial.println(sensor.sensor_id);
+  Serial.print(F("Min Value:    "));
+  Serial.println(sensor.min_value);
+  Serial.print(F("Max Value:    "));
+  Serial.println(sensor.max_value);
+  Serial.print(F("Resolution:   "));
+  Serial.println(sensor.resolution);
+  Serial.println(F("------------------------------------\n"));
+}

+ 196 - 0
lib/Adafruit_Sensor-1.1.7/Adafruit_Sensor.h

@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software< /span>
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
+ * extended sensor support to include color, voltage and current */
+
+#ifndef _ADAFRUIT_SENSOR_H
+#define _ADAFRUIT_SENSOR_H
+
+#ifndef ARDUINO
+#include <stdint.h>
+#elif ARDUINO >= 100
+#include "Arduino.h"
+#include "Print.h"
+#else
+#include "WProgram.h"
+#endif
+
+/* Constants */
+#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
+#define SENSORS_GRAVITY_MOON (1.6F)      /**< The moon's gravity in m/s^2 */
+#define SENSORS_GRAVITY_SUN (275.0F)     /**< The sun's gravity in m/s^2 */
+#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
+#define SENSORS_MAGFIELD_EARTH_MAX                                             \
+  (60.0F) /**< Maximum magnetic field on Earth's surface */
+#define SENSORS_MAGFIELD_EARTH_MIN                                             \
+  (30.0F) /**< Minimum magnetic field on Earth's surface */
+#define SENSORS_PRESSURE_SEALEVELHPA                                           \
+  (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
+#define SENSORS_DPS_TO_RADS                                                    \
+  (0.017453293F) /**< Degrees/s to rad/s multiplier                            \
+                  */
+#define SENSORS_RADS_TO_DPS                                                    \
+  (57.29577793F) /**< Rad/s to degrees/s  multiplier */
+#define SENSORS_GAUSS_TO_MICROTESLA                                            \
+  (100) /**< Gauss to micro-Tesla multiplier */
+
+/** Sensor types */
+typedef enum {
+  SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
+  SENSOR_TYPE_MAGNETIC_FIELD = (2),
+  SENSOR_TYPE_ORIENTATION = (3),
+  SENSOR_TYPE_GYROSCOPE = (4),
+  SENSOR_TYPE_LIGHT = (5),
+  SENSOR_TYPE_PRESSURE = (6),
+  SENSOR_TYPE_PROXIMITY = (8),
+  SENSOR_TYPE_GRAVITY = (9),
+  SENSOR_TYPE_LINEAR_ACCELERATION =
+      (10), /**< Acceleration not including gravity */
+  SENSOR_TYPE_ROTATION_VECTOR = (11),
+  SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
+  SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
+  SENSOR_TYPE_OBJECT_TEMPERATURE = (14),
+  SENSOR_TYPE_VOLTAGE = (15),
+  SENSOR_TYPE_CURRENT = (16),
+  SENSOR_TYPE_COLOR = (17),
+  SENSOR_TYPE_TVOC = (18),
+  SENSOR_TYPE_VOC_INDEX = (19),
+  SENSOR_TYPE_NOX_INDEX = (20)
+} sensors_type_t;
+
+/** struct sensors_vec_s is used to return a vector in a common format. */
+typedef struct {
+  union {
+    float v[3]; ///< 3D vector elements
+    struct {
+      float x; ///< X component of vector
+      float y; ///< Y component of vector
+      float z; ///< Z component of vector
+    };         ///< Struct for holding XYZ component
+    /* Orientation sensors */
+    struct {
+      float roll; /**< Rotation around the longitudinal axis (the plane body, 'X
+                     axis'). Roll is positive and increasing when moving
+                     downward. -90 degrees <= roll <= 90 degrees */
+      float pitch;   /**< Rotation around the lateral axis (the wing span, 'Y
+                        axis'). Pitch is positive and increasing when moving
+                        upwards. -180 degrees <= pitch <= 180 degrees) */
+      float heading; /**< Angle between the longitudinal axis (the plane body)
+                        and magnetic north, measured clockwise when viewing from
+                        the top of the device. 0-359 degrees */
+    };               ///< Struct for holding roll/pitch/heading
+  };                 ///< Union that can hold 3D vector array, XYZ components or
+                     ///< roll/pitch/heading
+  int8_t status;     ///< Status byte
+  uint8_t reserved[3]; ///< Reserved
+} sensors_vec_t;
+
+/** struct sensors_color_s is used to return color data in a common format. */
+typedef struct {
+  union {
+    float c[3]; ///< Raw 3-element data
+    /* RGB color space */
+    struct {
+      float r;   /**< Red component */
+      float g;   /**< Green component */
+      float b;   /**< Blue component */
+    };           ///< RGB data in floating point notation
+  };             ///< Union of various ways to describe RGB colorspace
+  uint32_t rgba; /**< 24-bit RGBA value */
+} sensors_color_t;
+
+/* Sensor event (36 bytes) */
+/** struct sensor_event_s is used to provide a single sensor event in a common
+ * format. */
+typedef struct {
+  int32_t version;   /**< must be sizeof(struct sensors_event_t) */
+  int32_t sensor_id; /**< unique sensor identifier */
+  int32_t type;      /**< sensor type */
+  int32_t reserved0; /**< reserved */
+  int32_t timestamp; /**< time is in milliseconds */
+  union {
+    float data[4];              ///< Raw data
+    sensors_vec_t acceleration; /**< acceleration values are in meter per second
+                                   per second (m/s^2) */
+    sensors_vec_t
+        magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
+    sensors_vec_t orientation; /**< orientation values are in degrees */
+    sensors_vec_t gyro;        /**< gyroscope values are in rad/s */
+    float temperature; /**< temperature is in degrees centigrade (Celsius) */
+    float distance;    /**< distance in centimeters */
+    float light;       /**< light in SI lux units */
+    float pressure;    /**< pressure in hectopascal (hPa) */
+    float relative_humidity; /**< relative humidity in percent */
+    float current;           /**< current in milliamps (mA) */
+    float voltage;           /**< voltage in volts (V) */
+    float tvoc;              /**< Total Volatile Organic Compounds, in ppb */
+    float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is
+                          normal (unitless) */
+    float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal
+                          (unitless) */
+    sensors_color_t color; /**< color in RGB component values */
+  };                       ///< Union for the wide ranges of data we can carry
+} sensors_event_t;
+
+/* Sensor details (40 bytes) */
+/** struct sensor_s is used to describe basic information about a specific
+ * sensor. */
+typedef struct {
+  char name[12];     /**< sensor name */
+  int32_t version;   /**< version of the hardware + driver */
+  int32_t sensor_id; /**< unique sensor identifier */
+  int32_t type;      /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
+  float max_value;   /**< maximum value of this sensor's value in SI units */
+  float min_value;   /**< minimum value of this sensor's value in SI units */
+  float resolution; /**< smallest difference between two values reported by this
+                       sensor */
+  int32_t min_delay; /**< min delay in microseconds between events. zero = not a
+                        constant rate */
+} sensor_t;
+
+/** @brief Common sensor interface to unify various sensors.
+ * Intentionally modeled after sensors.h in the Android API:
+ * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h
+ */
+class Adafruit_Sensor {
+public:
+  // Constructor(s)
+  Adafruit_Sensor() {}
+  virtual ~Adafruit_Sensor() {}
+
+  // These must be defined by the subclass
+
+  /*! @brief Whether we should automatically change the range (if possible) for
+     higher precision
+      @param enabled True if we will try to autorange */
+  virtual void enableAutoRange(bool enabled) {
+    (void)enabled; /* suppress unused warning */
+  };
+
+  /*! @brief Get the latest sensor event
+      @returns True if able to fetch an event */
+  virtual bool getEvent(sensors_event_t *) = 0;
+  /*! @brief Get info about the sensor itself */
+  virtual void getSensor(sensor_t *) = 0;
+
+  void printSensorDetails(void);
+
+private:
+  bool _autoRange;
+};
+
+#endif

+ 202 - 0
lib/Adafruit_Sensor-1.1.7/LICENSE.txt

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 239 - 0
lib/Adafruit_Sensor-1.1.7/README.md

@@ -0,0 +1,239 @@
+# Adafruit Unified Sensor Driver #
+
+Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing.
+
+One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road.
+
+Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement.
+
+By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor.  This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse.
+
+The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire.
+
+## Unified Sensor Drivers ##
+
+The following drivers are based on the Adafruit Unified Sensor Driver:
+
+**Accelerometers**
+  - [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345)
+  - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
+  - [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library)
+
+**Gyroscope**
+  - [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U)
+
+**Light**
+  - [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561)
+  - [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library)
+
+**Magnetometers**
+  - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC)
+  - [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified)
+  
+**Barometric Pressure**
+  - [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified)
+  - [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library)
+
+**Humidity & Temperature**
+  - [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library)
+
+**Humidity, Temperature, & Barometric Pressure**
+  - [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/)
+
+**Orientation**
+ - [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055)
+
+**All in one device**
+- [Adafruit_LSM9DS0](https://github.com/adafruit/Adafruit_LSM9DS0_Library) (accelerometer, gyroscope, magnetometer)
+- [Adafruit_LSM9DS1](https://github.com/adafruit/Adafruit_LSM9DS1/) (accelerometer, gyroscope, magnetometer)
+
+
+## How Does it Work? ##
+
+Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class.  There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values:
+
+## Sensor Types (`sensors_type_t`)
+
+These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc.
+
+```c++
+/** Sensor types */
+typedef enum
+{
+  SENSOR_TYPE_ACCELEROMETER         = (1),
+  SENSOR_TYPE_MAGNETIC_FIELD        = (2),
+  SENSOR_TYPE_ORIENTATION           = (3),
+  SENSOR_TYPE_GYROSCOPE             = (4),
+  SENSOR_TYPE_LIGHT                 = (5),
+  SENSOR_TYPE_PRESSURE              = (6),
+  SENSOR_TYPE_PROXIMITY             = (8),
+  SENSOR_TYPE_GRAVITY               = (9),
+  SENSOR_TYPE_LINEAR_ACCELERATION   = (10),
+  SENSOR_TYPE_ROTATION_VECTOR       = (11),
+  SENSOR_TYPE_RELATIVE_HUMIDITY     = (12),
+  SENSOR_TYPE_AMBIENT_TEMPERATURE   = (13),
+  SENSOR_TYPE_VOLTAGE               = (15),
+  SENSOR_TYPE_CURRENT               = (16),
+  SENSOR_TYPE_COLOR                 = (17),
+  SENSOR_TYPE_TVOC                  = (18),
+  SENSOR_TYPE_VOC_INDEX             = (19),
+  SENSOR_TYPE_NOX_INDEX             = (20)
+} sensors_type_t;
+```
+
+## Sensor Details (`sensor_t`)
+
+This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer.
+
+```c++
+/* Sensor details (40 bytes) */
+/** struct sensor_s is used to describe basic information about a specific sensor. */
+typedef struct
+{
+    char     name[12];
+    int32_t  version;
+    int32_t  sensor_id;
+    int32_t  type;
+    float    max_value;
+    float    min_value;
+    float    resolution;
+    int32_t  min_delay;
+} sensor_t;
+```
+
+The individual fields are intended to be used as follows:
+
+- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2")
+- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver
+- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network
+- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h
+- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit)
+- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit)
+- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit)
+- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate
+
+## Sensor Data/Events (`sensors_event_t`)
+
+This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales.
+
+```c++
+/* Sensor event (36 bytes) */
+/** struct sensor_event_s is used to provide a single sensor event in a common format. */
+typedef struct
+{
+    int32_t version;
+    int32_t sensor_id;
+    int32_t type;
+    int32_t reserved0;
+    int32_t timestamp;
+    union
+    {
+        float           data[4];
+        sensors_vec_t   acceleration;
+        sensors_vec_t   magnetic;
+        sensors_vec_t   orientation;
+        sensors_vec_t   gyro;
+        float           temperature;
+        float           distance;
+        float           light;
+        float           pressure;
+        float           relative_humidity;
+        float           current;
+        float           voltage;
+        float           tvoc;
+        float           voc_index;
+        float           nox_index;
+        sensors_color_t color;
+    };
+} sensors_event_t;
+```
+It includes the following fields:
+
+- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future
+- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!)
+- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h
+- **timestamp**: time in milliseconds when the sensor value was read
+- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below)
+
+## Required Functions
+
+In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions:
+
+```c++
+bool getEvent(sensors_event_t*);
+```
+Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data.  You should call this function as often as you want to update your data.
+
+```c++
+void getSensor(sensor_t*);
+```
+Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc.
+
+## Standardised SI values for `sensors_event_t`
+
+A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above.  This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales:
+
+- **acceleration**: values are in **meter per second per second** (m/s^2)
+- **magnetic**: values are in **micro-Tesla** (uT)
+- **orientation**: values are in **degrees**
+- **gyro**: values are in **rad/s**
+- **temperature**: values in **degrees centigrade** (Celsius) 
+- **distance**: values are in **centimeters**
+- **light**: values are in **SI lux** units
+- **pressure**: values are in **hectopascal** (hPa)
+- **relative\_humidity**: values are in **percent**
+- **current**: values are in **milliamps** (mA)
+- **voltage**: values are in **volts** (V)
+- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format
+- **tvoc**: values are in **parts per billion** (ppb)
+- **voc_index**: values are an **index** from 1-500 with 100 being normal
+- **nox_index**: values are an **index** from 1-500 with 100 being normal
+
+
+## The Unified Driver Abstraction Layer in Practice ##
+
+Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created.
+
+Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t).
+
+An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below:
+
+```c++
+ Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345);
+ ...
+ /* Get a new sensor event */ 
+ sensors_event_t event;
+ tsl.getEvent(&event);
+ 
+ /* Display the results (light is measured in lux) */
+ if (event.light)
+ {
+   Serial.print(event.light); Serial.println(" lux");
+ }
+ else
+ {
+   /* If event.light = 0 lux the sensor is probably saturated
+      and no reliable data could be generated! */
+   Serial.println("Sensor overload");
+ }
+```
+
+Similarly, we can get the basic technical capabilities of this sensor with the following code:
+
+```c++
+ sensor_t sensor;
+ 
+ sensor_t sensor;
+ tsl.getSensor(&sensor);
+
+ /* Display the sensor details */
+ Serial.println("------------------------------------");
+ Serial.print  ("Sensor:       "); Serial.println(sensor.name);
+ Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
+ Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
+ Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" lux");
+ Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" lux");
+ Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" lux");  
+ Serial.println("------------------------------------");
+ Serial.println("");
+```

+ 153 - 0
lib/Adafruit_Sensor-1.1.7/examples/sensortest/sensortest.ino

@@ -0,0 +1,153 @@
+#include <Wire.h>
+#include <Adafruit_Sensor.h>
+#include <Adafruit_ADXL343.h>
+
+/* Assign a unique ID to this sensor at the same time */
+/* Uncomment following line for default Wire bus      */
+Adafruit_ADXL343 accel = Adafruit_ADXL343(12345);
+
+/* NeoTrellis M4, etc.                    */
+/* Uncomment following line for Wire1 bus */
+//Adafruit_ADXL343 accel = Adafruit_ADXL343(12345, &Wire1);
+
+void displaySensorDetails(void)
+{
+  sensor_t sensor;
+  accel.getSensor(&sensor);
+  Serial.println("------------------------------------");
+  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
+  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
+  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
+  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
+  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
+  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" m/s^2");
+  Serial.println("------------------------------------");
+  Serial.println("");
+  delay(500);
+}
+
+void displayDataRate(void)
+{
+  Serial.print  ("Data Rate:    ");
+
+  switch(accel.getDataRate())
+  {
+    case ADXL343_DATARATE_3200_HZ:
+      Serial.print  ("3200 ");
+      break;
+    case ADXL343_DATARATE_1600_HZ:
+      Serial.print  ("1600 ");
+      break;
+    case ADXL343_DATARATE_800_HZ:
+      Serial.print  ("800 ");
+      break;
+    case ADXL343_DATARATE_400_HZ:
+      Serial.print  ("400 ");
+      break;
+    case ADXL343_DATARATE_200_HZ:
+      Serial.print  ("200 ");
+      break;
+    case ADXL343_DATARATE_100_HZ:
+      Serial.print  ("100 ");
+      break;
+    case ADXL343_DATARATE_50_HZ:
+      Serial.print  ("50 ");
+      break;
+    case ADXL343_DATARATE_25_HZ:
+      Serial.print  ("25 ");
+      break;
+    case ADXL343_DATARATE_12_5_HZ:
+      Serial.print  ("12.5 ");
+      break;
+    case ADXL343_DATARATE_6_25HZ:
+      Serial.print  ("6.25 ");
+      break;
+    case ADXL343_DATARATE_3_13_HZ:
+      Serial.print  ("3.13 ");
+      break;
+    case ADXL343_DATARATE_1_56_HZ:
+      Serial.print  ("1.56 ");
+      break;
+    case ADXL343_DATARATE_0_78_HZ:
+      Serial.print  ("0.78 ");
+      break;
+    case ADXL343_DATARATE_0_39_HZ:
+      Serial.print  ("0.39 ");
+      break;
+    case ADXL343_DATARATE_0_20_HZ:
+      Serial.print  ("0.20 ");
+      break;
+    case ADXL343_DATARATE_0_10_HZ:
+      Serial.print  ("0.10 ");
+      break;
+    default:
+      Serial.print  ("???? ");
+      break;
+  }
+  Serial.println(" Hz");
+}
+
+void displayRange(void)
+{
+  Serial.print  ("Range:         +/- ");
+
+  switch(accel.getRange())
+  {
+    case ADXL343_RANGE_16_G:
+      Serial.print  ("16 ");
+      break;
+    case ADXL343_RANGE_8_G:
+      Serial.print  ("8 ");
+      break;
+    case ADXL343_RANGE_4_G:
+      Serial.print  ("4 ");
+      break;
+    case ADXL343_RANGE_2_G:
+      Serial.print  ("2 ");
+      break;
+    default:
+      Serial.print  ("?? ");
+      break;
+  }
+  Serial.println(" g");
+}
+
+void setup(void)
+{
+  Serial.begin(9600);
+  while (!Serial);
+  Serial.println("Accelerometer Test"); Serial.println("");
+
+  /* Initialise the sensor */
+  if(!accel.begin())
+  {
+    /* There was a problem detecting the ADXL343 ... check your connections */
+    Serial.println("Ooops, no ADXL343 detected ... Check your wiring!");
+    while(1);
+  }
+
+  /* Set the range to whatever is appropriate for your project */
+  accel.setRange(ADXL343_RANGE_16_G);
+  // accel.setRange(ADXL343_RANGE_8_G);
+  // accel.setRange(ADXL343_RANGE_4_G);
+  // accel.setRange(ADXL343_RANGE_2_G);
+
+  /* Display some basic information on this sensor */
+  displaySensorDetails();
+  displayDataRate();
+  displayRange();
+  Serial.println("");
+}
+
+void loop(void)
+{
+  /* Get a new sensor event */
+  sensors_event_t event;
+  accel.getEvent(&event);
+
+  /* Display the results (acceleration is measured in m/s^2) */
+  Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print("  ");
+  Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print("  ");
+  Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
+  delay(500);
+}

+ 11 - 0
lib/Adafruit_Sensor-1.1.7/library.properties

@@ -0,0 +1,11 @@
+name=Adafruit Unified Sensor
+version=1.1.7
+author=Adafruit <info@adafruit.com>
+maintainer=Adafruit <info@adafruit.com>
+sentence=Required for all Adafruit Unified Sensor based libraries.
+paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries.
+category=Sensors
+url=https://github.com/adafruit/Adafruit_Sensor
+architectures=*
+includes=Adafruit_Sensor.h
+

+ 16 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/.gitignore

@@ -0,0 +1,16 @@
+.idea
+classes
+target
+out
+build
+*.iml
+*.ipr
+*.iws
+*.log
+*.war
+.idea
+.project
+.classpath
+.settings
+.gradle
+.vscode

+ 1033 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/DallasTemperature.cpp

@@ -0,0 +1,1033 @@
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+
+#include "DallasTemperature.h"
+
+#if ARDUINO >= 100
+#include "Arduino.h"
+#else
+extern "C" {
+#include "WConstants.h"
+}
+#endif
+
+// OneWire commands
+#define STARTCONVO      0x44  // Tells device to take a temperature reading and put it on the scratchpad
+#define COPYSCRATCH     0x48  // Copy scratchpad to EEPROM
+#define READSCRATCH     0xBE  // Read from scratchpad
+#define WRITESCRATCH    0x4E  // Write to scratchpad
+#define RECALLSCRATCH   0xB8  // Recall from EEPROM to scratchpad
+#define READPOWERSUPPLY 0xB4  // Determine if device needs parasite power
+#define ALARMSEARCH     0xEC  // Query bus for devices with an alarm condition
+
+// Scratchpad locations
+#define TEMP_LSB        0
+#define TEMP_MSB        1
+#define HIGH_ALARM_TEMP 2
+#define LOW_ALARM_TEMP  3
+#define CONFIGURATION   4
+#define INTERNAL_BYTE   5
+#define COUNT_REMAIN    6
+#define COUNT_PER_C     7
+#define SCRATCHPAD_CRC  8
+
+// DSROM FIELDS
+#define DSROM_FAMILY    0
+#define DSROM_CRC       7
+
+// Device resolution
+#define TEMP_9_BIT  0x1F //  9 bit
+#define TEMP_10_BIT 0x3F // 10 bit
+#define TEMP_11_BIT 0x5F // 11 bit
+#define TEMP_12_BIT 0x7F // 12 bit
+
+#define MAX_CONVERSION_TIMEOUT		750
+
+// Alarm handler
+#define NO_ALARM_HANDLER ((AlarmHandler *)0)
+
+
+DallasTemperature::DallasTemperature() {
+#if REQUIRESALARMS
+	setAlarmHandler(NO_ALARM_HANDLER);
+#endif
+    useExternalPullup = false;
+}
+
+DallasTemperature::DallasTemperature(OneWire* _oneWire) : DallasTemperature() {
+	setOneWire(_oneWire);
+}
+
+bool DallasTemperature::validFamily(const uint8_t* deviceAddress) {
+	switch (deviceAddress[DSROM_FAMILY]) {
+	case DS18S20MODEL:
+	case DS18B20MODEL:
+	case DS1822MODEL:
+	case DS1825MODEL:
+	case DS28EA00MODEL:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/*
+ * Constructs DallasTemperature with strong pull-up turned on. Strong pull-up is mandated in DS18B20 datasheet for parasitic
+ * power (2 wires) setup. (https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf, p. 7, section 'Powering the DS18B20').
+ */
+DallasTemperature::DallasTemperature(OneWire* _oneWire, uint8_t _pullupPin) : DallasTemperature(_oneWire) {
+  setPullupPin(_pullupPin);
+}
+
+void DallasTemperature::setPullupPin(uint8_t _pullupPin) {
+	useExternalPullup = true;
+	pullupPin = _pullupPin;
+	pinMode(pullupPin, OUTPUT);
+	deactivateExternalPullup();
+}
+
+void DallasTemperature::setOneWire(OneWire* _oneWire) {
+
+	_wire = _oneWire;
+	devices = 0;
+	ds18Count = 0;
+	parasite = false;
+	bitResolution = 9;
+	waitForConversion = true;
+	checkForConversion = true;
+  autoSaveScratchPad = true;
+
+}
+
+// initialise the bus
+void DallasTemperature::begin(void) {
+
+	DeviceAddress deviceAddress;
+
+	_wire->reset_search();
+	devices = 0; // Reset the number of devices when we enumerate wire devices
+	ds18Count = 0; // Reset number of DS18xxx Family devices
+
+	while (_wire->search(deviceAddress)) {
+
+		if (validAddress(deviceAddress)) {
+			devices++;
+
+			if (validFamily(deviceAddress)) {
+				ds18Count++;
+
+				if (!parasite && readPowerSupply(deviceAddress))
+					parasite = true;
+
+				uint8_t b = getResolution(deviceAddress);
+				if (b > bitResolution) bitResolution = b;
+			}
+		}
+	}
+}
+
+// returns the number of devices found on the bus
+uint8_t DallasTemperature::getDeviceCount(void) {
+	return devices;
+}
+
+uint8_t DallasTemperature::getDS18Count(void) {
+	return ds18Count;
+}
+
+// returns true if address is valid
+bool DallasTemperature::validAddress(const uint8_t* deviceAddress) {
+	return (_wire->crc8(deviceAddress, 7) == deviceAddress[DSROM_CRC]);
+}
+
+// finds an address at a given index on the bus
+// returns true if the device was found
+bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) {
+
+	uint8_t depth = 0;
+
+	_wire->reset_search();
+
+	while (depth <= index && _wire->search(deviceAddress)) {
+		if (depth == index && validAddress(deviceAddress))
+			return true;
+		depth++;
+	}
+
+	return false;
+
+}
+
+// attempt to determine if the device at the given address is connected to the bus
+bool DallasTemperature::isConnected(const uint8_t* deviceAddress) {
+
+	ScratchPad scratchPad;
+	return isConnected(deviceAddress, scratchPad);
+
+}
+
+// attempt to determine if the device at the given address is connected to the bus
+// also allows for updating the read scratchpad
+bool DallasTemperature::isConnected(const uint8_t* deviceAddress,
+		uint8_t* scratchPad) {
+	bool b = readScratchPad(deviceAddress, scratchPad);
+	return b && !isAllZeros(scratchPad) && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
+}
+
+bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress,
+		uint8_t* scratchPad) {
+
+	// send the reset command and fail fast
+	int b = _wire->reset();
+	if (b == 0)
+		return false;
+
+	_wire->select(deviceAddress);
+	_wire->write(READSCRATCH);
+
+	// Read all registers in a simple loop
+	// byte 0: temperature LSB
+	// byte 1: temperature MSB
+	// byte 2: high alarm temp
+	// byte 3: low alarm temp
+	// byte 4: DS18S20: store for crc
+	//         DS18B20 & DS1822: configuration register
+	// byte 5: internal use & crc
+	// byte 6: DS18S20: COUNT_REMAIN
+	//         DS18B20 & DS1822: store for crc
+	// byte 7: DS18S20: COUNT_PER_C
+	//         DS18B20 & DS1822: store for crc
+	// byte 8: SCRATCHPAD_CRC
+	for (uint8_t i = 0; i < 9; i++) {
+		scratchPad[i] = _wire->read();
+	}
+
+	b = _wire->reset();
+	return (b == 1);
+}
+
+void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress,
+		const uint8_t* scratchPad) {
+
+	_wire->reset();
+	_wire->select(deviceAddress);
+	_wire->write(WRITESCRATCH);
+	_wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp
+	_wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp
+
+	// DS1820 and DS18S20 have no configuration register
+	if (deviceAddress[DSROM_FAMILY] != DS18S20MODEL)
+		_wire->write(scratchPad[CONFIGURATION]);
+
+  if (autoSaveScratchPad)
+    saveScratchPad(deviceAddress);
+  else
+    _wire->reset();
+}
+
+// returns true if parasite mode is used (2 wire)
+// returns false if normal mode is used (3 wire)
+// if no address is given (or nullptr) it checks if any device on the bus
+// uses parasite mode.
+// See issue #145
+bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress)
+{
+	bool parasiteMode = false;
+	_wire->reset();
+	if (deviceAddress == nullptr)
+		_wire->skip();
+	else
+		_wire->select(deviceAddress);
+
+	_wire->write(READPOWERSUPPLY);
+	if (_wire->read_bit() == 0)
+		parasiteMode = true;
+	_wire->reset();
+	return parasiteMode;
+}
+
+// set resolution of all devices to 9, 10, 11, or 12 bits
+// if new resolution is out of range, it is constrained.
+void DallasTemperature::setResolution(uint8_t newResolution) {
+
+	bitResolution = constrain(newResolution, 9, 12);
+	DeviceAddress deviceAddress;
+	for (uint8_t i = 0; i < devices; i++) {
+		getAddress(deviceAddress, i);
+		setResolution(deviceAddress, bitResolution, true);
+	}
+}
+
+/*  PROPOSAL */
+
+// set resolution of a device to 9, 10, 11, or 12 bits
+// if new resolution is out of range, 9 bits is used.
+bool DallasTemperature::setResolution(const uint8_t* deviceAddress,
+                                      uint8_t newResolution, bool skipGlobalBitResolutionCalculation) {
+
+  bool success = false;
+
+  // DS1820 and DS18S20 have no resolution configuration register
+  if (deviceAddress[DSROM_FAMILY] == DS18S20MODEL)
+  {
+    success = true;
+  }
+  else
+  {
+
+   // handle the sensors with configuration register
+    newResolution = constrain(newResolution, 9, 12);
+    uint8_t newValue = 0;
+    ScratchPad scratchPad;
+
+    // we can only update the sensor if it is connected
+    if (isConnected(deviceAddress, scratchPad))
+    {
+      switch (newResolution) {
+        case 12:
+          newValue = TEMP_12_BIT;
+          break;
+        case 11:
+          newValue = TEMP_11_BIT;
+          break;
+        case 10:
+          newValue = TEMP_10_BIT;
+          break;
+        case 9:
+        default:
+          newValue = TEMP_9_BIT;
+          break;
+      }
+
+      // if it needs to be updated we write the new value
+      if (scratchPad[CONFIGURATION] != newValue)
+      {
+		scratchPad[CONFIGURATION] = newValue;
+        writeScratchPad(deviceAddress, scratchPad);
+      }
+      // done
+      success = true;
+    }
+  }
+
+  // do we need to update the max resolution used?
+  if (skipGlobalBitResolutionCalculation == false)
+  {
+    bitResolution = newResolution;
+    if (devices > 1)
+    {
+      for (uint8_t i = 0; i < devices; i++)
+      {
+        if (bitResolution == 12) break;
+        DeviceAddress deviceAddr;
+        getAddress(deviceAddr, i);
+        uint8_t b = getResolution(deviceAddr);
+        if (b > bitResolution) bitResolution = b;
+      }
+    }
+  }
+
+  return success;
+}
+
+
+// returns the global resolution
+uint8_t DallasTemperature::getResolution() {
+	return bitResolution;
+}
+
+// returns the current resolution of the device, 9-12
+// returns 0 if device not found
+uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) {
+
+	// DS1820 and DS18S20 have no resolution configuration register
+	if (deviceAddress[DSROM_FAMILY] == DS18S20MODEL)
+		return 12;
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+		switch (scratchPad[CONFIGURATION]) {
+		case TEMP_12_BIT:
+			return 12;
+
+		case TEMP_11_BIT:
+			return 11;
+
+		case TEMP_10_BIT:
+			return 10;
+
+		case TEMP_9_BIT:
+			return 9;
+		}
+	}
+	return 0;
+
+}
+
+
+// sets the value of the waitForConversion flag
+// TRUE : function requestTemperature() etc returns when conversion is ready
+// FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!)
+//        (1) programmer has to check if the needed delay has passed
+//        (2) but the application can do meaningful things in that time
+void DallasTemperature::setWaitForConversion(bool flag) {
+	waitForConversion = flag;
+}
+
+// gets the value of the waitForConversion flag
+bool DallasTemperature::getWaitForConversion() {
+	return waitForConversion;
+}
+
+// sets the value of the checkForConversion flag
+// TRUE : function requestTemperature() etc will 'listen' to an IC to determine whether a conversion is complete
+// FALSE: function requestTemperature() etc will wait a set time (worst case scenario) for a conversion to complete
+void DallasTemperature::setCheckForConversion(bool flag) {
+	checkForConversion = flag;
+}
+
+// gets the value of the waitForConversion flag
+bool DallasTemperature::getCheckForConversion() {
+	return checkForConversion;
+}
+
+bool DallasTemperature::isConversionComplete() {
+	uint8_t b = _wire->read_bit();
+	return (b == 1);
+}
+
+// sends command for all devices on the bus to perform a temperature conversion
+void DallasTemperature::requestTemperatures() {
+
+	_wire->reset();
+	_wire->skip();
+	_wire->write(STARTCONVO, parasite);
+
+	// ASYNC mode?
+	if (!waitForConversion)
+		return;
+	blockTillConversionComplete(bitResolution);
+
+}
+
+// sends command for one device to perform a temperature by address
+// returns FALSE if device is disconnected
+// returns TRUE  otherwise
+bool DallasTemperature::requestTemperaturesByAddress(
+		const uint8_t* deviceAddress) {
+
+	uint8_t bitResolution = getResolution(deviceAddress);
+	if (bitResolution == 0) {
+		return false; //Device disconnected
+	}
+
+	_wire->reset();
+	_wire->select(deviceAddress);
+	_wire->write(STARTCONVO, parasite);
+
+	// ASYNC mode?
+	if (!waitForConversion)
+		return true;
+
+	blockTillConversionComplete(bitResolution);
+
+	return true;
+
+}
+
+// Continue to check if the IC has responded with a temperature
+void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) {
+
+  if (checkForConversion && !parasite) {
+    unsigned long start = millis();
+    while (!isConversionComplete() && (millis() - start < MAX_CONVERSION_TIMEOUT ))
+      yield();
+  } else {
+    unsigned long delms = millisToWaitForConversion(bitResolution);
+    activateExternalPullup();
+    delay(delms);
+    deactivateExternalPullup();
+  }
+
+}
+
+// returns number of milliseconds to wait till conversion is complete (based on IC datasheet)
+int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) {
+
+	switch (bitResolution) {
+	case 9:
+		return 94;
+	case 10:
+		return 188;
+	case 11:
+		return 375;
+	default:
+		return 750;
+	}
+
+}
+
+// Sends command to one device to save values from scratchpad to EEPROM by index
+// Returns true if no errors were encountered, false indicates failure
+bool DallasTemperature::saveScratchPadByIndex(uint8_t deviceIndex) {
+  
+  DeviceAddress deviceAddress;
+  if (!getAddress(deviceAddress, deviceIndex)) return false;
+  
+  return saveScratchPad(deviceAddress);
+  
+}
+
+// Sends command to one or more devices to save values from scratchpad to EEPROM
+// If optional argument deviceAddress is omitted the command is send to all devices
+// Returns true if no errors were encountered, false indicates failure
+bool DallasTemperature::saveScratchPad(const uint8_t* deviceAddress) {
+  
+  if (_wire->reset() == 0)
+    return false;
+  
+  if (deviceAddress == nullptr)
+    _wire->skip();
+  else
+    _wire->select(deviceAddress);
+  
+  _wire->write(COPYSCRATCH,parasite);
+
+  // Specification: NV Write Cycle Time is typically 2ms, max 10ms
+  // Waiting 20ms to allow for sensors that take longer in practice
+  if (!parasite) {
+    delay(20);
+  } else {
+    activateExternalPullup();
+    delay(20);
+    deactivateExternalPullup();
+  }
+  
+  return _wire->reset() == 1;
+  
+}
+
+// Sends command to one device to recall values from EEPROM to scratchpad by index
+// Returns true if no errors were encountered, false indicates failure
+bool DallasTemperature::recallScratchPadByIndex(uint8_t deviceIndex) {
+
+  DeviceAddress deviceAddress;
+  if (!getAddress(deviceAddress, deviceIndex)) return false;
+  
+  return recallScratchPad(deviceAddress);
+
+}
+
+// Sends command to one or more devices to recall values from EEPROM to scratchpad
+// If optional argument deviceAddress is omitted the command is send to all devices
+// Returns true if no errors were encountered, false indicates failure
+bool DallasTemperature::recallScratchPad(const uint8_t* deviceAddress) {
+  
+  if (_wire->reset() == 0)
+    return false;
+  
+  if (deviceAddress == nullptr)
+    _wire->skip();
+  else
+    _wire->select(deviceAddress);
+  
+  _wire->write(RECALLSCRATCH,parasite);
+
+  // Specification: Strong pullup only needed when writing to EEPROM (and temp conversion)
+  unsigned long start = millis();
+  while (_wire->read_bit() == 0) {
+    // Datasheet doesn't specify typical/max duration, testing reveals typically within 1ms
+    if (millis() - start > 20) return false;
+    yield();
+  }
+  
+  return _wire->reset() == 1;
+  
+}
+
+// Sets the autoSaveScratchPad flag
+void DallasTemperature::setAutoSaveScratchPad(bool flag) {
+  autoSaveScratchPad = flag;
+}
+
+// Gets the autoSaveScratchPad flag
+bool DallasTemperature::getAutoSaveScratchPad() {
+  return autoSaveScratchPad;
+}
+
+void DallasTemperature::activateExternalPullup() {
+	if(useExternalPullup)
+		digitalWrite(pullupPin, LOW);
+}
+
+void DallasTemperature::deactivateExternalPullup() {
+	if(useExternalPullup)
+		digitalWrite(pullupPin, HIGH);
+}
+
+// sends command for one device to perform a temp conversion by index
+bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) {
+
+	DeviceAddress deviceAddress;
+	getAddress(deviceAddress, deviceIndex);
+
+	return requestTemperaturesByAddress(deviceAddress);
+
+}
+
+// Fetch temperature for device index
+float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) {
+
+	DeviceAddress deviceAddress;
+	if (!getAddress(deviceAddress, deviceIndex)) {
+		return DEVICE_DISCONNECTED_C;
+	}
+	return getTempC((uint8_t*) deviceAddress);
+}
+
+// Fetch temperature for device index
+float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) {
+
+	DeviceAddress deviceAddress;
+
+	if (!getAddress(deviceAddress, deviceIndex)) {
+		return DEVICE_DISCONNECTED_F;
+	}
+
+	return getTempF((uint8_t*) deviceAddress);
+
+}
+
+// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7
+int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress,
+		uint8_t* scratchPad) {
+
+	int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11)
+			| (((int16_t) scratchPad[TEMP_LSB]) << 3);
+
+	/*
+	 DS1820 and DS18S20 have a 9-bit temperature register.
+
+	 Resolutions greater than 9-bit can be calculated using the data from
+	 the temperature, and COUNT REMAIN and COUNT PER °C registers in the
+	 scratchpad.  The resolution of the calculation depends on the model.
+
+	 While the COUNT PER °C register is hard-wired to 16 (10h) in a
+	 DS18S20, it changes with temperature in DS1820.
+
+	 After reading the scratchpad, the TEMP_READ value is obtained by
+	 truncating the 0.5°C bit (bit 0) from the temperature data. The
+	 extended resolution temperature can then be calculated using the
+	 following equation:
+
+	                                  COUNT_PER_C - COUNT_REMAIN
+	 TEMPERATURE = TEMP_READ - 0.25 + --------------------------
+	                                         COUNT_PER_C
+
+	 Hagai Shatz simplified this to integer arithmetic for a 12 bits
+	 value for a DS18S20, and James Cameron added legacy DS1820 support.
+
+	 See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html
+	 */
+
+	if ((deviceAddress[DSROM_FAMILY] == DS18S20MODEL) && (scratchPad[COUNT_PER_C] != 0)) {
+		fpTemperature = ((fpTemperature & 0xfff0) << 3) - 32
+				+ (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7)
+						/ scratchPad[COUNT_PER_C]);
+	}
+
+	return fpTemperature;
+}
+
+// returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the
+// device's scratch pad cannot be read successfully.
+// the numeric value of DEVICE_DISCONNECTED_RAW is defined in
+// DallasTemperature.h. It is a large negative number outside the
+// operating range of the device
+int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress) {
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad))
+		return calculateTemperature(deviceAddress, scratchPad);
+	return DEVICE_DISCONNECTED_RAW;
+
+}
+
+// returns temperature in degrees C or DEVICE_DISCONNECTED_C if the
+// device's scratch pad cannot be read successfully.
+// the numeric value of DEVICE_DISCONNECTED_C is defined in
+// DallasTemperature.h. It is a large negative number outside the
+// operating range of the device
+float DallasTemperature::getTempC(const uint8_t* deviceAddress) {
+	return rawToCelsius(getTemp(deviceAddress));
+}
+
+// returns temperature in degrees F or DEVICE_DISCONNECTED_F if the
+// device's scratch pad cannot be read successfully.
+// the numeric value of DEVICE_DISCONNECTED_F is defined in
+// DallasTemperature.h. It is a large negative number outside the
+// operating range of the device
+float DallasTemperature::getTempF(const uint8_t* deviceAddress) {
+	return rawToFahrenheit(getTemp(deviceAddress));
+}
+
+// returns true if the bus requires parasite power
+bool DallasTemperature::isParasitePowerMode(void) {
+	return parasite;
+}
+
+// IF alarm is not used one can store a 16 bit int of userdata in the alarm
+// registers. E.g. an ID of the sensor.
+// See github issue #29
+
+// note if device is not connected it will fail writing the data.
+void DallasTemperature::setUserData(const uint8_t* deviceAddress,
+		int16_t data) {
+	// return when stored value == new value
+	if (getUserData(deviceAddress) == data)
+		return;
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+		scratchPad[HIGH_ALARM_TEMP] = data >> 8;
+		scratchPad[LOW_ALARM_TEMP] = data & 255;
+		writeScratchPad(deviceAddress, scratchPad);
+	}
+}
+
+int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) {
+	int16_t data = 0;
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+		data = scratchPad[HIGH_ALARM_TEMP] << 8;
+		data += scratchPad[LOW_ALARM_TEMP];
+	}
+	return data;
+}
+
+// note If address cannot be found no error will be reported.
+int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) {
+	DeviceAddress deviceAddress;
+	getAddress(deviceAddress, deviceIndex);
+	return getUserData((uint8_t*) deviceAddress);
+}
+
+void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) {
+	DeviceAddress deviceAddress;
+	getAddress(deviceAddress, deviceIndex);
+	setUserData((uint8_t*) deviceAddress, data);
+}
+
+// Convert float Celsius to Fahrenheit
+float DallasTemperature::toFahrenheit(float celsius) {
+	return (celsius * 1.8f) + 32.0f;
+}
+
+// Convert float Fahrenheit to Celsius
+float DallasTemperature::toCelsius(float fahrenheit) {
+	return (fahrenheit - 32.0f) * 0.555555556f;
+}
+
+// convert from raw to Celsius
+float DallasTemperature::rawToCelsius(int16_t raw) {
+
+	if (raw <= DEVICE_DISCONNECTED_RAW)
+		return DEVICE_DISCONNECTED_C;
+	// C = RAW/128
+	return (float) raw * 0.0078125f;
+
+}
+
+// convert from raw to Fahrenheit
+float DallasTemperature::rawToFahrenheit(int16_t raw) {
+
+	if (raw <= DEVICE_DISCONNECTED_RAW)
+		return DEVICE_DISCONNECTED_F;
+	// C = RAW/128
+	// F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32
+	return ((float) raw * 0.0140625f) + 32.0f;
+
+}
+
+// Returns true if all bytes of scratchPad are '\0'
+bool DallasTemperature::isAllZeros(const uint8_t * const scratchPad, const size_t length) {
+	for (size_t i = 0; i < length; i++) {
+		if (scratchPad[i] != 0) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+#if REQUIRESALARMS
+
+/*
+
+ ALARMS:
+
+ TH and TL Register Format
+
+ BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0
+ S    2^6   2^5   2^4   2^3   2^2   2^1   2^0
+
+ Only bits 11 through 4 of the temperature register are used
+ in the TH and TL comparison since TH and TL are 8-bit
+ registers. If the measured temperature is lower than or equal
+ to TL or higher than or equal to TH, an alarm condition exists
+ and an alarm flag is set inside the DS18B20. This flag is
+ updated after every temperature measurement; therefore, if the
+ alarm condition goes away, the flag will be turned off after
+ the next temperature conversion.
+
+ */
+
+// sets the high alarm temperature for a device in degrees Celsius
+// accepts a float, but the alarm resolution will ignore anything
+// after a decimal point.  valid range is -55C - 125C
+void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress,
+		int8_t celsius) {
+
+	// return when stored value == new value
+	if (getHighAlarmTemp(deviceAddress) == celsius)
+		return;
+
+	// make sure the alarm temperature is within the device's range
+	if (celsius > 125)
+		celsius = 125;
+	else if (celsius < -55)
+		celsius = -55;
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+		scratchPad[HIGH_ALARM_TEMP] = (uint8_t) celsius;
+		writeScratchPad(deviceAddress, scratchPad);
+	}
+
+}
+
+// sets the low alarm temperature for a device in degrees Celsius
+// accepts a float, but the alarm resolution will ignore anything
+// after a decimal point.  valid range is -55C - 125C
+void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress,
+		int8_t celsius) {
+
+	// return when stored value == new value
+	if (getLowAlarmTemp(deviceAddress) == celsius)
+		return;
+
+	// make sure the alarm temperature is within the device's range
+	if (celsius > 125)
+		celsius = 125;
+	else if (celsius < -55)
+		celsius = -55;
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+		scratchPad[LOW_ALARM_TEMP] = (uint8_t) celsius;
+		writeScratchPad(deviceAddress, scratchPad);
+	}
+
+}
+
+// returns a int8_t with the current high alarm temperature or
+// DEVICE_DISCONNECTED for an address
+int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) {
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad))
+		return (int8_t) scratchPad[HIGH_ALARM_TEMP];
+	return DEVICE_DISCONNECTED_C;
+
+}
+
+// returns a int8_t with the current low alarm temperature or
+// DEVICE_DISCONNECTED for an address
+int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) {
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad))
+		return (int8_t) scratchPad[LOW_ALARM_TEMP];
+	return DEVICE_DISCONNECTED_C;
+
+}
+
+// resets internal variables used for the alarm search
+void DallasTemperature::resetAlarmSearch() {
+
+	alarmSearchJunction = -1;
+	alarmSearchExhausted = 0;
+	for (uint8_t i = 0; i < 7; i++) {
+		alarmSearchAddress[i] = 0;
+	}
+
+}
+
+// This is a modified version of the OneWire::search method.
+//
+// Also added the OneWire search fix documented here:
+// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295
+//
+// Perform an alarm search. If this function returns a '1' then it has
+// enumerated the next device and you may retrieve the ROM from the
+// OneWire::address variable. If there are no devices, no further
+// devices, or something horrible happens in the middle of the
+// enumeration then a 0 is returned.  If a new device is found then
+// its address is copied to newAddr.  Use
+// DallasTemperature::resetAlarmSearch() to start over.
+bool DallasTemperature::alarmSearch(uint8_t* newAddr) {
+
+	uint8_t i;
+	int8_t lastJunction = -1;
+	uint8_t done = 1;
+
+	if (alarmSearchExhausted)
+		return false;
+	if (!_wire->reset())
+		return false;
+
+	// send the alarm search command
+	_wire->write(0xEC, 0);
+
+	for (i = 0; i < 64; i++) {
+
+		uint8_t a = _wire->read_bit();
+		uint8_t nota = _wire->read_bit();
+		uint8_t ibyte = i / 8;
+		uint8_t ibit = 1 << (i & 7);
+
+		// I don't think this should happen, this means nothing responded, but maybe if
+		// something vanishes during the search it will come up.
+		if (a && nota)
+			return false;
+
+		if (!a && !nota) {
+			if (i == alarmSearchJunction) {
+				// this is our time to decide differently, we went zero last time, go one.
+				a = 1;
+				alarmSearchJunction = lastJunction;
+			} else if (i < alarmSearchJunction) {
+
+				// take whatever we took last time, look in address
+				if (alarmSearchAddress[ibyte] & ibit) {
+					a = 1;
+				} else {
+					// Only 0s count as pending junctions, we've already exhausted the 0 side of 1s
+					a = 0;
+					done = 0;
+					lastJunction = i;
+				}
+			} else {
+				// we are blazing new tree, take the 0
+				a = 0;
+				alarmSearchJunction = i;
+				done = 0;
+			}
+			// OneWire search fix
+			// See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295
+		}
+
+		if (a)
+			alarmSearchAddress[ibyte] |= ibit;
+		else
+			alarmSearchAddress[ibyte] &= ~ibit;
+
+		_wire->write_bit(a);
+	}
+
+	if (done)
+		alarmSearchExhausted = 1;
+	for (i = 0; i < 8; i++)
+		newAddr[i] = alarmSearchAddress[i];
+	return true;
+
+}
+
+// returns true if device address might have an alarm condition
+// (only an alarm search can verify this)
+bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) {
+
+	ScratchPad scratchPad;
+	if (isConnected(deviceAddress, scratchPad)) {
+
+		int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7;
+
+		// check low alarm
+		if (temp <= (int8_t) scratchPad[LOW_ALARM_TEMP])
+			return true;
+
+		// check high alarm
+		if (temp >= (int8_t) scratchPad[HIGH_ALARM_TEMP])
+			return true;
+	}
+
+	// no alarm
+	return false;
+
+}
+
+// returns true if any device is reporting an alarm condition on the bus
+bool DallasTemperature::hasAlarm(void) {
+
+	DeviceAddress deviceAddress;
+	resetAlarmSearch();
+	return alarmSearch(deviceAddress);
+}
+
+// runs the alarm handler for all devices returned by alarmSearch()
+// unless there no _AlarmHandler exist.
+void DallasTemperature::processAlarms(void) {
+
+if (!hasAlarmHandler())
+{
+	return;
+}
+
+	resetAlarmSearch();
+	DeviceAddress alarmAddr;
+
+	while (alarmSearch(alarmAddr)) {
+		if (validAddress(alarmAddr)) {
+			_AlarmHandler(alarmAddr);
+		}
+	}
+}
+
+// sets the alarm handler
+void DallasTemperature::setAlarmHandler(const AlarmHandler *handler) {
+	_AlarmHandler = handler;
+}
+
+// checks if AlarmHandler has been set.
+bool DallasTemperature::hasAlarmHandler()
+{
+  return _AlarmHandler != NO_ALARM_HANDLER;
+}
+
+#endif
+
+#if REQUIRESNEW
+
+// MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object
+void* DallasTemperature::operator new(unsigned int size) { // Implicit NSS obj size
+
+	void * p;// void pointer
+	p = malloc(size);// Allocate memory
+	memset((DallasTemperature*)p,0,size);// Initialise memory
+
+	//!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method
+	return (DallasTemperature*) p;// Cast blank region to NSS pointer
+}
+
+// MnetCS 2009 -  Free the memory used by this instance
+void DallasTemperature::operator delete(void* p) {
+
+	DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer
+	pNss->~DallasTemperature();// Destruct the object
+
+	free(p);// Free the memory
+}
+
+#endif

+ 317 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/DallasTemperature.h

@@ -0,0 +1,317 @@
+#ifndef DallasTemperature_h
+#define DallasTemperature_h
+
+#define DALLASTEMPLIBVERSION "3.8.1" // To be deprecated -> TODO remove in 4.0.0
+
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+
+// set to true to include code for new and delete operators
+#ifndef REQUIRESNEW
+#define REQUIRESNEW false
+#endif
+
+// set to true to include code implementing alarm search functions
+#ifndef REQUIRESALARMS
+#define REQUIRESALARMS true
+#endif
+
+#include <inttypes.h>
+#ifdef __STM32F1__
+#include <OneWireSTM.h>
+#else
+#include <OneWire.h>
+#endif
+
+// Model IDs
+#define DS18S20MODEL 0x10  // also DS1820
+#define DS18B20MODEL 0x28  // also MAX31820
+#define DS1822MODEL  0x22
+#define DS1825MODEL  0x3B
+#define DS28EA00MODEL 0x42
+
+// Error Codes
+#define DEVICE_DISCONNECTED_C -127
+#define DEVICE_DISCONNECTED_F -196.6
+#define DEVICE_DISCONNECTED_RAW -7040
+
+// For readPowerSupply on oneWire bus
+// definition of nullptr for C++ < 11, using official workaround:
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
+#if __cplusplus < 201103L
+const class
+{
+public:
+	template <class T>
+	operator T *() const
+	{
+		return 0;
+	}
+	template <class C, class T>
+	operator T C::*() const
+	{
+		return 0;
+	}
+
+private:
+	void operator&() const;
+} nullptr = {};
+#endif
+
+typedef uint8_t DeviceAddress[8];
+
+class DallasTemperature {
+public:
+
+	DallasTemperature();
+	DallasTemperature(OneWire*);
+	DallasTemperature(OneWire*, uint8_t);
+
+	void setOneWire(OneWire*);
+
+    void setPullupPin(uint8_t);
+
+	// initialise bus
+	void begin(void);
+
+	// returns the number of devices found on the bus
+	uint8_t getDeviceCount(void);
+
+	// returns the number of DS18xxx Family devices on bus
+	uint8_t getDS18Count(void);
+
+	// returns true if address is valid
+	bool validAddress(const uint8_t*);
+
+	// returns true if address is of the family of sensors the lib supports.
+	bool validFamily(const uint8_t* deviceAddress);
+
+	// finds an address at a given index on the bus
+	bool getAddress(uint8_t*, uint8_t);
+
+	// attempt to determine if the device at the given address is connected to the bus
+	bool isConnected(const uint8_t*);
+
+	// attempt to determine if the device at the given address is connected to the bus
+	// also allows for updating the read scratchpad
+	bool isConnected(const uint8_t*, uint8_t*);
+
+	// read device's scratchpad
+	bool readScratchPad(const uint8_t*, uint8_t*);
+
+	// write device's scratchpad
+	void writeScratchPad(const uint8_t*, const uint8_t*);
+
+	// read device's power requirements
+	bool readPowerSupply(const uint8_t* deviceAddress = nullptr);
+
+	// get global resolution
+	uint8_t getResolution();
+
+	// set global resolution to 9, 10, 11, or 12 bits
+	void setResolution(uint8_t);
+
+	// returns the device resolution: 9, 10, 11, or 12 bits
+	uint8_t getResolution(const uint8_t*);
+
+	// set resolution of a device to 9, 10, 11, or 12 bits
+	bool setResolution(const uint8_t*, uint8_t,
+			bool skipGlobalBitResolutionCalculation = false);
+
+	// sets/gets the waitForConversion flag
+	void setWaitForConversion(bool);
+	bool getWaitForConversion(void);
+
+	// sets/gets the checkForConversion flag
+	void setCheckForConversion(bool);
+	bool getCheckForConversion(void);
+
+	// sends command for all devices on the bus to perform a temperature conversion
+	void requestTemperatures(void);
+
+	// sends command for one device to perform a temperature conversion by address
+	bool requestTemperaturesByAddress(const uint8_t*);
+
+	// sends command for one device to perform a temperature conversion by index
+	bool requestTemperaturesByIndex(uint8_t);
+
+	// returns temperature raw value (12 bit integer of 1/128 degrees C)
+	int16_t getTemp(const uint8_t*);
+
+	// returns temperature in degrees C
+	float getTempC(const uint8_t*);
+
+	// returns temperature in degrees F
+	float getTempF(const uint8_t*);
+
+	// Get temperature for device index (slow)
+	float getTempCByIndex(uint8_t);
+
+	// Get temperature for device index (slow)
+	float getTempFByIndex(uint8_t);
+
+	// returns true if the bus requires parasite power
+	bool isParasitePowerMode(void);
+
+	// Is a conversion complete on the wire? Only applies to the first sensor on the wire.
+	bool isConversionComplete(void);
+
+  int16_t millisToWaitForConversion(uint8_t);
+  
+  // Sends command to one device to save values from scratchpad to EEPROM by index
+  // Returns true if no errors were encountered, false indicates failure
+  bool saveScratchPadByIndex(uint8_t);
+  
+  // Sends command to one or more devices to save values from scratchpad to EEPROM
+  // Returns true if no errors were encountered, false indicates failure
+  bool saveScratchPad(const uint8_t* = nullptr);
+  
+  // Sends command to one device to recall values from EEPROM to scratchpad by index
+  // Returns true if no errors were encountered, false indicates failure
+  bool recallScratchPadByIndex(uint8_t);
+  
+  // Sends command to one or more devices to recall values from EEPROM to scratchpad
+  // Returns true if no errors were encountered, false indicates failure
+  bool recallScratchPad(const uint8_t* = nullptr);
+  
+  // Sets the autoSaveScratchPad flag
+  void setAutoSaveScratchPad(bool);
+  
+  // Gets the autoSaveScratchPad flag
+  bool getAutoSaveScratchPad(void);
+
+#if REQUIRESALARMS
+
+	typedef void AlarmHandler(const uint8_t*);
+
+	// sets the high alarm temperature for a device
+	// accepts a int8_t.  valid range is -55C - 125C
+	void setHighAlarmTemp(const uint8_t*, int8_t);
+
+	// sets the low alarm temperature for a device
+	// accepts a int8_t.  valid range is -55C - 125C
+	void setLowAlarmTemp(const uint8_t*, int8_t);
+
+	// returns a int8_t with the current high alarm temperature for a device
+	// in the range -55C - 125C
+	int8_t getHighAlarmTemp(const uint8_t*);
+
+	// returns a int8_t with the current low alarm temperature for a device
+	// in the range -55C - 125C
+	int8_t getLowAlarmTemp(const uint8_t*);
+
+	// resets internal variables used for the alarm search
+	void resetAlarmSearch(void);
+
+	// search the wire for devices with active alarms
+	bool alarmSearch(uint8_t*);
+
+	// returns true if ia specific device has an alarm
+	bool hasAlarm(const uint8_t*);
+
+	// returns true if any device is reporting an alarm on the bus
+	bool hasAlarm(void);
+
+	// runs the alarm handler for all devices returned by alarmSearch()
+	void processAlarms(void);
+
+	// sets the alarm handler
+	void setAlarmHandler(const AlarmHandler *);
+
+	// returns true if an AlarmHandler has been set
+	bool hasAlarmHandler();
+
+#endif
+
+	// if no alarm handler is used the two bytes can be used as user data
+	// example of such usage is an ID.
+	// note if device is not connected it will fail writing the data.
+	// note if address cannot be found no error will be reported.
+	// in short use carefully
+	void setUserData(const uint8_t*, int16_t);
+	void setUserDataByIndex(uint8_t, int16_t);
+	int16_t getUserData(const uint8_t*);
+	int16_t getUserDataByIndex(uint8_t);
+
+	// convert from Celsius to Fahrenheit
+	static float toFahrenheit(float);
+
+	// convert from Fahrenheit to Celsius
+	static float toCelsius(float);
+
+	// convert from raw to Celsius
+	static float rawToCelsius(int16_t);
+
+	// convert from raw to Fahrenheit
+	static float rawToFahrenheit(int16_t);
+
+#if REQUIRESNEW
+
+	// initialize memory area
+	void* operator new (unsigned int);
+
+	// delete memory reference
+	void operator delete(void*);
+
+#endif
+
+private:
+	typedef uint8_t ScratchPad[9];
+
+	// parasite power on or off
+	bool parasite;
+
+	// external pullup
+	bool useExternalPullup;
+	uint8_t pullupPin;
+
+	// used to determine the delay amount needed to allow for the
+	// temperature conversion to take place
+	uint8_t bitResolution;
+
+	// used to requestTemperature with or without delay
+	bool waitForConversion;
+
+	// used to requestTemperature to dynamically check if a conversion is complete
+	bool checkForConversion;
+
+  // used to determine if values will be saved from scratchpad to EEPROM on every scratchpad write
+  bool autoSaveScratchPad;
+
+	// count of devices on the bus
+	uint8_t devices;
+
+	// count of DS18xxx Family devices on bus
+	uint8_t ds18Count;
+
+	// Take a pointer to one wire instance
+	OneWire* _wire;
+
+	// reads scratchpad and returns the raw temperature
+	int16_t calculateTemperature(const uint8_t*, uint8_t*);
+
+	void blockTillConversionComplete(uint8_t);
+
+	// Returns true if all bytes of scratchPad are '\0'
+	bool isAllZeros(const uint8_t* const scratchPad, const size_t length = 9);
+
+    // External pullup control
+    void activateExternalPullup(void);
+    void deactivateExternalPullup(void);
+
+#if REQUIRESALARMS
+
+	// required for alarmSearch
+	uint8_t alarmSearchAddress[8];
+	int8_t alarmSearchJunction;
+	uint8_t alarmSearchExhausted;
+
+	// the alarm handler function pointer
+	AlarmHandler *_AlarmHandler;
+
+#endif
+
+};
+#endif

+ 72 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/README.md

@@ -0,0 +1,72 @@
+# Arduino Library for Maxim Temperature Integrated Circuits
+
+## Usage
+
+This library supports the following devices :
+
+
+* DS18B20
+* DS18S20 - Please note there appears to be an issue with this series.
+* DS1822
+* DS1820
+* MAX31820
+
+
+You will need a pull-up resistor of about 5 KOhm between the 1-Wire data line
+and your 5V power. If you are using the DS18B20, ground pins 1 and 3. The
+centre pin is the data line '1-wire'.
+
+In case of temperature conversion problems (result is `-85`), strong pull-up setup may be necessary. See section 
+_Powering the DS18B20_ in 
+[DS18B20 datasheet](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf) (page 7)
+and use `DallasTemperature(OneWire*, uint8_t)` constructor.
+
+We have included a "REQUIRESNEW" and "REQUIRESALARMS" definition. If you 
+want to slim down the code feel free to use either of these by including
+
+
+
+	#define REQUIRESNEW 
+
+or 
+
+	#define REQUIRESALARMS
+
+
+at the top of DallasTemperature.h
+
+Finally, please include OneWire from Paul Stoffregen in the library manager before you begin.
+
+## Credits
+
+The OneWire code has been derived from
+http://www.arduino.cc/playground/Learning/OneWire.
+Miles Burton <miles@mnetcs.com> originally developed this library.
+Tim Newsome <nuisance@casualhacker.net> added support for multiple sensors on
+the same bus.
+Guil Barros [gfbarros@bappos.com] added getTempByAddress (v3.5)
+   Note: these are implemented as getTempC(address) and getTempF(address)
+Rob Tillaart [rob.tillaart@gmail.com] added async modus (v3.7.0)
+
+
+## Website
+
+
+Additional documentation may be found here
+https://www.milesburton.com/Dallas_Temperature_Control_Library
+
+# License
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

+ 162 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Alarm/Alarm.ino

@@ -0,0 +1,162 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+// arrays to hold device addresses
+DeviceAddress insideThermometer, outsideThermometer;
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+  
+  // locate devices on the bus
+  Serial.print("Found ");
+  Serial.print(sensors.getDeviceCount(), DEC);
+  Serial.println(" devices.");
+
+  // search for devices on the bus and assign based on an index.
+  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
+  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 
+
+  // show the addresses we found on the bus
+  Serial.print("Device 0 Address: ");
+  printAddress(insideThermometer);
+  Serial.println();
+
+  Serial.print("Device 0 Alarms: ");
+  printAlarms(insideThermometer);
+  Serial.println();
+  
+  Serial.print("Device 1 Address: ");
+  printAddress(outsideThermometer);
+  Serial.println();
+
+  Serial.print("Device 1 Alarms: ");
+  printAlarms(outsideThermometer);
+  Serial.println();
+  
+  Serial.println("Setting alarm temps...");
+
+  // alarm when temp is higher than 30C
+  sensors.setHighAlarmTemp(insideThermometer, 30);
+  
+  // alarm when temp is lower than -10C
+  sensors.setLowAlarmTemp(insideThermometer, -10);
+  
+  // alarm when temp is higher than 31C
+  sensors.setHighAlarmTemp(outsideThermometer, 31);
+  
+  // alarn when temp is lower than 27C
+  sensors.setLowAlarmTemp(outsideThermometer, 27);
+  
+  Serial.print("New Device 0 Alarms: ");
+  printAlarms(insideThermometer);
+  Serial.println();
+  
+  Serial.print("New Device 1 Alarms: ");
+  printAlarms(outsideThermometer);
+  Serial.println();
+}
+
+// function to print a device address
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}
+
+// function to print the temperature for a device
+void printTemperature(DeviceAddress deviceAddress)
+{
+  float tempC = sensors.getTempC(deviceAddress);
+  Serial.print("Temp C: ");
+  Serial.print(tempC);
+  Serial.print(" Temp F: ");
+  Serial.print(DallasTemperature::toFahrenheit(tempC));
+}
+
+void printAlarms(uint8_t deviceAddress[])
+{
+  char temp;
+  temp = sensors.getHighAlarmTemp(deviceAddress);
+  Serial.print("High Alarm: ");
+  Serial.print(temp, DEC);
+  Serial.print("C/");
+  Serial.print(DallasTemperature::toFahrenheit(temp));
+  Serial.print("F | Low Alarm: ");
+  temp = sensors.getLowAlarmTemp(deviceAddress);
+  Serial.print(temp, DEC);
+  Serial.print("C/");
+  Serial.print(DallasTemperature::toFahrenheit(temp));
+  Serial.print("F");
+}
+
+// main function to print information about a device
+void printData(DeviceAddress deviceAddress)
+{
+  Serial.print("Device Address: ");
+  printAddress(deviceAddress);
+  Serial.print(" ");
+  printTemperature(deviceAddress);
+  Serial.println();
+}
+
+void checkAlarm(DeviceAddress deviceAddress)
+{
+  if (sensors.hasAlarm(deviceAddress))
+  {
+    Serial.print("ALARM: ");
+    printData(deviceAddress);
+  }
+}
+
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures();
+  Serial.println("DONE");
+
+  // Method 1:
+  // check each address individually for an alarm condition
+  checkAlarm(insideThermometer);
+  checkAlarm(outsideThermometer);
+/*
+  // Alternate method:
+  // Search the bus and iterate through addresses of devices with alarms
+  
+  // space for the alarm device's address
+  DeviceAddress alarmAddr;
+
+  Serial.println("Searching for alarms...");
+  
+  // resetAlarmSearch() must be called before calling alarmSearch()
+  sensors.resetAlarmSearch();
+  
+  // alarmSearch() returns 0 when there are no devices with alarms
+  while (sensors.alarmSearch(alarmAddr))
+  {
+    Serial.print("ALARM: ");
+    printData(alarmAddr);
+  }
+*/
+
+}
+

+ 144 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/AlarmHandler/AlarmHandler.ino

@@ -0,0 +1,144 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+// arrays to hold device addresses
+DeviceAddress insideThermometer, outsideThermometer;
+
+// function that will be called when an alarm condition exists during DallasTemperatures::processAlarms();
+void newAlarmHandler(const uint8_t* deviceAddress)
+{
+  Serial.println("Alarm Handler Start"); 
+  printAlarmInfo(deviceAddress);
+  printTemp(deviceAddress);
+  Serial.println();
+  Serial.println("Alarm Handler Finish");
+}
+
+void printCurrentTemp(DeviceAddress deviceAddress)
+{
+  printAddress(deviceAddress);
+  printTemp(deviceAddress);
+  Serial.println();
+}
+
+void printAddress(const DeviceAddress deviceAddress)
+{
+  Serial.print("Address: ");
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+  Serial.print(" ");
+}
+
+void printTemp(const DeviceAddress deviceAddress)
+{
+  float tempC = sensors.getTempC(deviceAddress);
+  if (tempC != DEVICE_DISCONNECTED_C)
+  {
+    Serial.print("Current Temp C: ");
+    Serial.print(tempC);
+  }
+  else Serial.print("DEVICE DISCONNECTED");
+  Serial.print(" ");
+}
+
+void printAlarmInfo(const DeviceAddress deviceAddress)
+{
+  char temp;
+  printAddress(deviceAddress);
+  temp = sensors.getHighAlarmTemp(deviceAddress);
+  Serial.print("High Alarm: ");
+  Serial.print(temp, DEC);
+  Serial.print("C");
+  Serial.print(" Low Alarm: ");
+  temp = sensors.getLowAlarmTemp(deviceAddress);
+  Serial.print(temp, DEC);
+  Serial.print("C");
+  Serial.print(" ");
+}
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+  
+  // locate devices on the bus
+  Serial.print("Found ");
+  Serial.print(sensors.getDeviceCount(), DEC);
+  Serial.println(" devices.");
+
+  // search for devices on the bus and assign based on an index
+  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
+  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); 
+
+  Serial.print("Device insideThermometer ");
+  printAlarmInfo(insideThermometer);
+  Serial.println();
+  
+  Serial.print("Device outsideThermometer ");
+  printAlarmInfo(outsideThermometer);
+  Serial.println();
+  
+  // set alarm ranges
+  Serial.println("Setting alarm temps...");
+  sensors.setHighAlarmTemp(insideThermometer, 26);
+  sensors.setLowAlarmTemp(insideThermometer, 22);
+  sensors.setHighAlarmTemp(outsideThermometer, 25);
+  sensors.setLowAlarmTemp(outsideThermometer, 21);
+  
+  Serial.print("New insideThermometer ");
+  printAlarmInfo(insideThermometer);
+  Serial.println();
+  
+  Serial.print("New outsideThermometer ");
+  printAlarmInfo(outsideThermometer);
+  Serial.println();
+
+  // attach alarm handler
+  sensors.setAlarmHandler(&newAlarmHandler);
+
+}
+
+void loop(void)
+{ 
+  // ask the devices to measure the temperature
+  sensors.requestTemperatures();
+  
+  // if an alarm condition exists as a result of the most recent 
+  // requestTemperatures() request, it exists until the next time 
+  // requestTemperatures() is called AND there isn't an alarm condition
+  // on the device
+  if (sensors.hasAlarm())
+  {
+    Serial.println("Oh noes!  There is at least one alarm on the bus.");
+  }
+
+  // call alarm handler function defined by sensors.setAlarmHandler
+  // for each device reporting an alarm
+  sensors.processAlarms();
+
+  if (!sensors.hasAlarm())
+  {
+    // just print out the current temperature
+    printCurrentTemp(insideThermometer);
+    printCurrentTemp(outsideThermometer);
+  }
+  
+  delay(1000);
+}
+

+ 35 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/ExternalPullup/ExternalPullup.ino

@@ -0,0 +1,35 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino, while external pullup P-MOSFET gate into port 3
+#define ONE_WIRE_BUS    2
+#define ONE_WIRE_PULLUP 3
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire, ONE_WIRE_PULLUP);
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+}
+
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures(); // Send the command to get temperatures
+  Serial.println("DONE");
+  
+ for(int i=0;i<sensors.getDeviceCount();i++) {
+   Serial.println("Temperature for Device "+String(i)+" is: " + String(sensors.getTempCByIndex(i)));
+ } 
+}

+ 43 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Multibus_simple/Multibus_simple.ino

@@ -0,0 +1,43 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+OneWire ds18x20[] = { 3, 7 };
+const int oneWireCount = sizeof(ds18x20)/sizeof(OneWire);
+DallasTemperature sensor[oneWireCount];
+
+void setup(void) {
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature Multiple Bus Control Library Simple Demo");
+  Serial.print("============Ready with ");
+  Serial.print(oneWireCount);
+  Serial.println(" Sensors================");
+  
+  // Start up the library on all defined bus-wires
+  DeviceAddress deviceAddress;
+  for (int i = 0; i < oneWireCount; i++) {;
+    sensor[i].setOneWire(&ds18x20[i]);
+    sensor[i].begin();
+    if (sensor[i].getAddress(deviceAddress, 0)) sensor[i].setResolution(deviceAddress, 12);
+  }
+}
+
+void loop(void) {
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  for (int i = 0; i < oneWireCount; i++) {
+    sensor[i].requestTemperatures();
+  }
+  Serial.println("DONE");
+  
+  delay(1000);
+  for (int i = 0; i < oneWireCount; i++) {
+    float temperature = sensor[i].getTempCByIndex(0);
+    Serial.print("Temperature for the sensor ");
+    Serial.print(i);
+    Serial.print(" is ");
+    Serial.println(temperature);
+  }
+  Serial.println();
+}

+ 148 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Multiple/Multiple.ino

@@ -0,0 +1,148 @@
+// Include the libraries we need
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+#define TEMPERATURE_PRECISION 9
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature.
+DallasTemperature sensors(&oneWire);
+
+// arrays to hold device addresses
+DeviceAddress insideThermometer, outsideThermometer;
+
+// Assign address manually. The addresses below will need to be changed
+// to valid device addresses on your bus. Device address can be retrieved
+// by using either oneWire.search(deviceAddress) or individually via
+// sensors.getAddress(deviceAddress, index)
+// DeviceAddress insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
+// DeviceAddress outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+
+  // locate devices on the bus
+  Serial.print("Locating devices...");
+  Serial.print("Found ");
+  Serial.print(sensors.getDeviceCount(), DEC);
+  Serial.println(" devices.");
+
+  // report parasite power requirements
+  Serial.print("Parasite power is: ");
+  if (sensors.isParasitePowerMode()) Serial.println("ON");
+  else Serial.println("OFF");
+
+  // Search for devices on the bus and assign based on an index. Ideally,
+  // you would do this to initially discover addresses on the bus and then
+  // use those addresses and manually assign them (see above) once you know
+  // the devices on your bus (and assuming they don't change).
+  //
+  // method 1: by index
+  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
+  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
+
+  // method 2: search()
+  // search() looks for the next device. Returns 1 if a new address has been
+  // returned. A zero might mean that the bus is shorted, there are no devices,
+  // or you have already retrieved all of them. It might be a good idea to
+  // check the CRC to make sure you didn't get garbage. The order is
+  // deterministic. You will always get the same devices in the same order
+  //
+  // Must be called before search()
+  //oneWire.reset_search();
+  // assigns the first address found to insideThermometer
+  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
+  // assigns the seconds address found to outsideThermometer
+  //if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer");
+
+  // show the addresses we found on the bus
+  Serial.print("Device 0 Address: ");
+  printAddress(insideThermometer);
+  Serial.println();
+
+  Serial.print("Device 1 Address: ");
+  printAddress(outsideThermometer);
+  Serial.println();
+
+  // set the resolution to 9 bit per device
+  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
+  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);
+
+  Serial.print("Device 0 Resolution: ");
+  Serial.print(sensors.getResolution(insideThermometer), DEC);
+  Serial.println();
+
+  Serial.print("Device 1 Resolution: ");
+  Serial.print(sensors.getResolution(outsideThermometer), DEC);
+  Serial.println();
+}
+
+// function to print a device address
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    // zero pad the address if necessary
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}
+
+// function to print the temperature for a device
+void printTemperature(DeviceAddress deviceAddress)
+{
+  float tempC = sensors.getTempC(deviceAddress);
+  if(tempC == DEVICE_DISCONNECTED_C) 
+  {
+    Serial.println("Error: Could not read temperature data");
+    return;
+  }
+  Serial.print("Temp C: ");
+  Serial.print(tempC);
+  Serial.print(" Temp F: ");
+  Serial.print(DallasTemperature::toFahrenheit(tempC));
+}
+
+// function to print a device's resolution
+void printResolution(DeviceAddress deviceAddress)
+{
+  Serial.print("Resolution: ");
+  Serial.print(sensors.getResolution(deviceAddress));
+  Serial.println();
+}
+
+// main function to print information about a device
+void printData(DeviceAddress deviceAddress)
+{
+  Serial.print("Device Address: ");
+  printAddress(deviceAddress);
+  Serial.print(" ");
+  printTemperature(deviceAddress);
+  Serial.println();
+}
+
+/*
+   Main function, calls the temperatures in a loop.
+*/
+void loop(void)
+{
+  // call sensors.requestTemperatures() to issue a global temperature
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures();
+  Serial.println("DONE");
+
+  // print the device information
+  printData(insideThermometer);
+  printData(outsideThermometer);
+}

+ 106 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/SaveRecallScratchPad/SaveRecallScratchPad.ino

@@ -0,0 +1,106 @@
+//
+//    FILE: SaveRecallScratchPad.ino
+//  AUTHOR: GitKomodo
+// VERSION: 0.0.1
+// PURPOSE: Show DallasTemperature lib functionality to
+//          save/recall ScratchPad values to/from EEPROM
+//
+// HISTORY:
+// 0.0.1 = 2020-02-18 initial version
+//
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+#define ONE_WIRE_BUS 2
+
+OneWire oneWire(ONE_WIRE_BUS);
+DallasTemperature sensors(&oneWire);
+DeviceAddress deviceAddress;
+
+void setup()
+{
+  Serial.begin(9600);
+  Serial.println(__FILE__);
+  Serial.println("Dallas Temperature Demo");
+  
+  sensors.begin();
+  
+  // Get ID of first sensor (at index 0)
+  sensors.getAddress(deviceAddress,0);
+
+  // By default configuration and alarm/userdata registers are also saved to EEPROM
+  // when they're changed. Sensors recall these values automatically when powered up.
+  
+  // Turn OFF automatic saving of configuration and alarm/userdata registers to EEPROM
+  sensors.setAutoSaveScratchPad(false);
+  
+  // Change configuration and alarm/userdata registers on the scratchpad
+  int8_t resolution = 12;
+  sensors.setResolution(deviceAddress,resolution);
+  int16_t userdata = 24680;
+  sensors.setUserData(deviceAddress,userdata);
+
+  // Save configuration and alarm/userdata registers to EEPROM
+  sensors.saveScratchPad(deviceAddress);
+
+  // saveScratchPad can also be used without a parameter to save the configuration
+  // and alarm/userdata registers of ALL connected sensors to EEPROM:
+  //
+  //   sensors.saveScratchPad();
+  //
+  // Or the configuration and alarm/userdata registers of a sensor can be saved to
+  // EEPROM by index:
+  //
+  //   sensors.saveScratchPadByIndex(0);
+  
+  // Print current values on the scratchpad (resolution = 12, userdata = 24680)
+  printValues();
+  
+}
+
+void loop(){
+  
+  // Change configuration and alarm/userdata registers on the scratchpad
+  int8_t resolution = 10;
+  sensors.setResolution(deviceAddress,resolution);
+  int16_t userdata = 12345;
+  sensors.setUserData(deviceAddress,userdata);
+  
+  // Print current values on the scratchpad (resolution = 10, userdata = 12345)
+  printValues();
+  
+  delay(2000);
+  
+  // Recall configuration and alarm/userdata registers from EEPROM
+  sensors.recallScratchPad(deviceAddress);
+  
+  // recallScratchPad can also be used without a parameter to recall the configuration
+  // and alarm/userdata registers of ALL connected sensors from EEPROM:
+  //
+  //   sensors.recallScratchPad();
+  //
+  // Or the configuration and alarm/userdata registers of a sensor can be recalled
+  // from EEPROM by index:
+  //
+  //   sensors.recallScratchPadByIndex(0);
+  
+  // Print current values on the scratchpad (resolution = 12, userdata = 24680)
+  printValues();
+  
+  delay(2000);
+  
+}
+
+void printValues() {
+  
+  Serial.println();
+  Serial.println("Current values on the scratchpad:");
+  
+  Serial.print("Resolution:\t");
+  Serial.println(sensors.getResolution(deviceAddress));
+  
+  Serial.print("User data:\t");
+  Serial.println(sensors.getUserData(deviceAddress));
+  
+}

+ 47 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/SetUserData/SetUserData.ino

@@ -0,0 +1,47 @@
+//
+// This sketch does not use the ALARM registers and uses those 2 bytes as a counter
+// these 2 bytes can be used for other purposes as well e.g. last temperature or
+// a specific ID.
+// 
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+int count = 0;
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+  
+}
+
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures(); // Send the command to get temperatures
+  Serial.println("DONE");
+  
+  Serial.print("Temperature for the device 1 (index 0) is: ");
+  Serial.println(sensors.getTempCByIndex(0));  
+  
+  count++;
+  sensors.setUserDataByIndex(0, count);
+  int x = sensors.getUserDataByIndex(0);
+  Serial.println(count);
+}

+ 51 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Simple/Simple.ino

@@ -0,0 +1,51 @@
+// Include the libraries we need
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+/*
+ * The setup function. We only start the sensors here
+ */
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+}
+
+/*
+ * Main function, get and show the temperature
+ */
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures(); // Send the command to get temperatures
+  Serial.println("DONE");
+  // After we got the temperatures, we can print them here.
+  // We use the function ByIndex, and as an example get the temperature from the first sensor only.
+  float tempC = sensors.getTempCByIndex(0);
+
+  // Check if reading was successful
+  if(tempC != DEVICE_DISCONNECTED_C) 
+  {
+    Serial.print("Temperature for the device 1 (index 0) is: ");
+    Serial.println(tempC);
+  } 
+  else
+  {
+    Serial.println("Error: Could not read temperature data");
+  }
+}

+ 121 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Single/Single.ino

@@ -0,0 +1,121 @@
+// Include the libraries we need
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+// arrays to hold device address
+DeviceAddress insideThermometer;
+
+/*
+ * Setup function. Here we do the basics
+ */
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // locate devices on the bus
+  Serial.print("Locating devices...");
+  sensors.begin();
+  Serial.print("Found ");
+  Serial.print(sensors.getDeviceCount(), DEC);
+  Serial.println(" devices.");
+
+  // report parasite power requirements
+  Serial.print("Parasite power is: "); 
+  if (sensors.isParasitePowerMode()) Serial.println("ON");
+  else Serial.println("OFF");
+  
+  // Assign address manually. The addresses below will beed to be changed
+  // to valid device addresses on your bus. Device address can be retrieved
+  // by using either oneWire.search(deviceAddress) or individually via
+  // sensors.getAddress(deviceAddress, index)
+  // Note that you will need to use your specific address here
+  //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
+
+  // Method 1:
+  // Search for devices on the bus and assign based on an index. Ideally,
+  // you would do this to initially discover addresses on the bus and then 
+  // use those addresses and manually assign them (see above) once you know 
+  // the devices on your bus (and assuming they don't change).
+  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); 
+  
+  // method 2: search()
+  // search() looks for the next device. Returns 1 if a new address has been
+  // returned. A zero might mean that the bus is shorted, there are no devices, 
+  // or you have already retrieved all of them. It might be a good idea to 
+  // check the CRC to make sure you didn't get garbage. The order is 
+  // deterministic. You will always get the same devices in the same order
+  //
+  // Must be called before search()
+  //oneWire.reset_search();
+  // assigns the first address found to insideThermometer
+  //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
+
+  // show the addresses we found on the bus
+  Serial.print("Device 0 Address: ");
+  printAddress(insideThermometer);
+  Serial.println();
+
+  // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
+  sensors.setResolution(insideThermometer, 9);
+ 
+  Serial.print("Device 0 Resolution: ");
+  Serial.print(sensors.getResolution(insideThermometer), DEC); 
+  Serial.println();
+}
+
+// function to print the temperature for a device
+void printTemperature(DeviceAddress deviceAddress)
+{
+  // method 1 - slower
+  //Serial.print("Temp C: ");
+  //Serial.print(sensors.getTempC(deviceAddress));
+  //Serial.print(" Temp F: ");
+  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
+
+  // method 2 - faster
+  float tempC = sensors.getTempC(deviceAddress);
+  if(tempC == DEVICE_DISCONNECTED_C) 
+  {
+    Serial.println("Error: Could not read temperature data");
+    return;
+  }
+  Serial.print("Temp C: ");
+  Serial.print(tempC);
+  Serial.print(" Temp F: ");
+  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
+}
+/*
+ * Main function. It will request the tempC from the sensors and display on Serial.
+ */
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures(); // Send the command to get temperatures
+  Serial.println("DONE");
+  
+  // It responds almost immediately. Let's print out the data
+  printTemperature(insideThermometer); // Use a simple function to print out the data
+}
+
+// function to print a device address
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}

+ 129 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Tester/Tester.ino

@@ -0,0 +1,129 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+#define TEMPERATURE_PRECISION 9 // Lower resolution
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+int numberOfDevices; // Number of temperature devices found
+
+DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(9600);
+  Serial.println("Dallas Temperature IC Control Library Demo");
+
+  // Start up the library
+  sensors.begin();
+  
+  // Grab a count of devices on the wire
+  numberOfDevices = sensors.getDeviceCount();
+  
+  // locate devices on the bus
+  Serial.print("Locating devices...");
+  
+  Serial.print("Found ");
+  Serial.print(numberOfDevices, DEC);
+  Serial.println(" devices.");
+
+  // report parasite power requirements
+  Serial.print("Parasite power is: "); 
+  if (sensors.isParasitePowerMode()) Serial.println("ON");
+  else Serial.println("OFF");
+  
+  // Loop through each device, print out address
+  for(int i=0;i<numberOfDevices; i++)
+  {
+    // Search the wire for address
+    if(sensors.getAddress(tempDeviceAddress, i))
+	{
+		Serial.print("Found device ");
+		Serial.print(i, DEC);
+		Serial.print(" with address: ");
+		printAddress(tempDeviceAddress);
+		Serial.println();
+		
+		Serial.print("Setting resolution to ");
+		Serial.println(TEMPERATURE_PRECISION, DEC);
+		
+		// set the resolution to TEMPERATURE_PRECISION bit (Each Dallas/Maxim device is capable of several different resolutions)
+		sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
+		
+		Serial.print("Resolution actually set to: ");
+		Serial.print(sensors.getResolution(tempDeviceAddress), DEC); 
+		Serial.println();
+	}else{
+		Serial.print("Found ghost device at ");
+		Serial.print(i, DEC);
+		Serial.print(" but could not detect address. Check power and cabling");
+	}
+  }
+
+}
+
+// function to print the temperature for a device
+void printTemperature(DeviceAddress deviceAddress)
+{
+  // method 1 - slower
+  //Serial.print("Temp C: ");
+  //Serial.print(sensors.getTempC(deviceAddress));
+  //Serial.print(" Temp F: ");
+  //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
+
+  // method 2 - faster
+  float tempC = sensors.getTempC(deviceAddress);
+  if(tempC == DEVICE_DISCONNECTED_C) 
+  {
+    Serial.println("Error: Could not read temperature data");
+    return;
+  }
+  Serial.print("Temp C: ");
+  Serial.print(tempC);
+  Serial.print(" Temp F: ");
+  Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
+}
+
+void loop(void)
+{ 
+  // call sensors.requestTemperatures() to issue a global temperature 
+  // request to all devices on the bus
+  Serial.print("Requesting temperatures...");
+  sensors.requestTemperatures(); // Send the command to get temperatures
+  Serial.println("DONE");
+  
+  
+  // Loop through each device, print out temperature data
+  for(int i=0;i<numberOfDevices; i++)
+  {
+    // Search the wire for address
+    if(sensors.getAddress(tempDeviceAddress, i))
+	{
+		// Output the device ID
+		Serial.print("Temperature for device: ");
+		Serial.println(i,DEC);
+		
+		// It responds almost immediately. Let's print out the data
+		printTemperature(tempDeviceAddress); // Use a simple function to print out the data
+	} 
+	//else ghost device! Check your power requirements and cabling
+	
+  }
+}
+
+// function to print a device address
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}

+ 77 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/Timing/Timing.ino

@@ -0,0 +1,77 @@
+//
+//    FILE: Timing.ino
+//  AUTHOR: Rob Tillaart
+// VERSION: 0.0.3
+// PURPOSE: show performance of DallasTemperature lib 
+//          compared to datasheet times per resolution
+//
+// HISTORY:
+// 0.0.1    2017-07-25 initial version
+// 0.0.2    2020-02-13 updates to work with current lib version
+// 0.0.3    2020-02-20 added timing measurement of setResolution
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+#define ONE_WIRE_BUS 2
+
+OneWire oneWire(ONE_WIRE_BUS);
+DallasTemperature sensor(&oneWire);
+
+uint32_t start, stop;
+
+
+void setup()
+{
+  Serial.begin(9600);
+  Serial.println(__FILE__);
+  Serial.print("DallasTemperature Library version: ");
+  Serial.println(DALLASTEMPLIBVERSION);
+
+  sensor.begin();
+}
+
+void loop()
+{
+  float ti[4] = { 94, 188, 375, 750 };
+
+  Serial.println();
+  Serial.println("Test takes about 30 seconds for 4 resolutions");
+  Serial.println("RES\tTIME\tACTUAL\tGAIN");
+  for (int r = 9; r < 13; r++)
+  {
+    start = micros();
+    sensor.setResolution(r);
+    Serial.println(micros() - start);
+
+    start = micros();
+    sensor.setResolution(r);
+    Serial.println(micros() - start);
+
+    uint32_t duration = run(20);
+    float avgDuration = duration / 20.0;
+
+    Serial.print(r);
+    Serial.print("\t");
+    Serial.print(ti[r - 9]);
+    Serial.print("\t");
+    Serial.print(avgDuration, 2);
+    Serial.print("\t");
+    Serial.print(avgDuration * 100 / ti[r - 9], 1);
+    Serial.println("%");
+  }
+  delay(1000);
+}
+
+uint32_t run(int runs)
+{
+  float t;
+  start = millis();
+  for (int i = 0; i < runs; i++)
+  {
+    sensor.requestTemperatures();
+    t = sensor.getTempCByIndex(0);
+  }
+  stop = millis();
+  return stop - start;
+}

+ 45 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/TwoPin_DS18B20/TwoPin_DS18B20.ino

@@ -0,0 +1,45 @@
+//
+// FILE: TwoPin_DS18B20.ino
+// AUTHOR: Rob Tillaart
+// VERSION: 0.1.00
+// PURPOSE: two pins for two sensors demo
+// DATE: 2014-06-13
+// URL: http://forum.arduino.cc/index.php?topic=216835.msg1764333#msg1764333
+//
+// Released to the public domain
+//
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+#define ONE_WIRE_BUS_1 2
+#define ONE_WIRE_BUS_2 4
+
+OneWire oneWire_in(ONE_WIRE_BUS_1);
+OneWire oneWire_out(ONE_WIRE_BUS_2);
+
+DallasTemperature sensor_inhouse(&oneWire_in);
+DallasTemperature sensor_outhouse(&oneWire_out);
+
+void setup(void)
+{
+    Serial.begin(9600);
+    Serial.println("Dallas Temperature Control Library Demo - TwoPin_DS18B20");
+
+    sensor_inhouse.begin();
+    sensor_outhouse.begin();
+}
+
+void loop(void)
+{
+    Serial.print("Requesting temperatures...");
+    sensor_inhouse.requestTemperatures();
+    sensor_outhouse.requestTemperatures();
+    Serial.println(" done");
+
+    Serial.print("Inhouse: ");
+    Serial.println(sensor_inhouse.getTempCByIndex(0));
+
+    Serial.print("Outhouse: ");
+    Serial.println(sensor_outhouse.getTempCByIndex(0));
+}

+ 115 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/UserDataDemo/UserDataDemo.ino

@@ -0,0 +1,115 @@
+//
+// FILE: UserDataDemo.ino
+// AUTHOR: Rob Tillaart
+// VERSION: 0.1.0
+// PURPOSE: use of alarm field as user identification demo
+// DATE: 2019-12-23
+// URL:
+//
+// Released to the public domain
+//
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+#define ONE_WIRE_BUS      2
+
+OneWire oneWire(ONE_WIRE_BUS);
+DallasTemperature sensors(&oneWire);
+
+uint8_t deviceCount = 0;
+
+// Add 4 prepared sensors to the bus
+// use the UserDataWriteBatch demo to prepare 4 different labeled sensors
+struct
+{
+  int id;
+  DeviceAddress addr;
+} T[4];
+
+float getTempByID(int id)
+{
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    if (T[index].id == id)
+    {
+      return sensors.getTempC(T[index].addr);
+    }
+  }
+  return -999;
+}
+
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    // zero pad the address if necessary
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}
+
+void setup(void)
+{
+  Serial.begin(115200);
+  Serial.println(__FILE__);
+  Serial.println("Dallas Temperature Demo");
+
+  sensors.begin();
+  
+  // count devices
+  deviceCount = sensors.getDeviceCount();
+  Serial.print("#devices: ");
+  Serial.println(deviceCount);
+
+  // Read ID's per sensor
+  // and put them in T array
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    // go through sensors
+    sensors.getAddress(T[index].addr, index);
+    T[index].id = sensors.getUserData(T[index].addr);
+  }
+
+  // Check all 4 sensors are set
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    Serial.println();
+    Serial.println(T[index].id);
+    printAddress(T[index].addr);
+    Serial.println();
+  }
+  Serial.println();
+
+}
+
+
+void loop(void)
+{
+  Serial.println();
+  Serial.print(millis());
+  Serial.println("\treq temp");
+  sensors.requestTemperatures();
+
+  Serial.print(millis());
+  Serial.println("\tGet temp by address");
+  for (int i = 0; i < 4; i++)
+  {
+    Serial.print(millis());
+    Serial.print("\t temp:\t");
+    Serial.println(sensors.getTempC(T[i].addr));
+  }
+
+  Serial.print(millis());
+  Serial.println("\tGet temp by ID");  // assume ID = 0, 1, 2, 3
+  for (int id = 0; id < 4; id++)
+  {
+    Serial.print(millis());
+    Serial.print("\t temp:\t");
+    Serial.println(getTempByID(id));
+  }
+
+  delay(1000);
+}
+
+// END OF FILE

+ 107 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/UserDataWriteBatch/UserDataWriteBatch.ino

@@ -0,0 +1,107 @@
+//
+// FILE: UserDataWriteBatch.ino
+// AUTHOR: Rob Tillaart
+// VERSION: 0.1.0
+// PURPOSE: use of alarm field as user identification demo
+// DATE: 2019-12-23
+// URL:
+//
+// Released to the public domain
+//
+
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+#define ONE_WIRE_BUS      2
+
+OneWire oneWire(ONE_WIRE_BUS);
+DallasTemperature sensors(&oneWire);
+
+uint8_t deviceCount = 0;
+
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    // zero pad the address if necessary
+    if (deviceAddress[i] < 16) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}
+
+
+
+void setup(void)
+{
+  Serial.begin(115200);
+  Serial.println(__FILE__);
+  Serial.println("Write user ID to DS18B20\n");
+
+  sensors.begin();
+
+  // count devices
+  deviceCount = sensors.getDeviceCount();
+  Serial.print("#devices: ");
+  Serial.println(deviceCount);
+  
+  Serial.println();
+  Serial.println("current ID's");
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    DeviceAddress t;
+    sensors.getAddress(t, index);
+    printAddress(t);
+    Serial.print("\t\tID: ");
+    int id = sensors.getUserData(t);
+    Serial.println(id);
+  }
+  
+  Serial.println();
+  Serial.print("Enter ID for batch: ");
+  int c = 0;
+  int id = 0;
+  while (c != '\n' && c != '\r')
+  {
+    c = Serial.read();
+    switch(c)
+    {
+    case '0'...'9':
+      id *= 10;
+      id += (c - '0');
+      break;
+    default:
+      break;
+    }
+  }
+  Serial.println();
+  Serial.println(id);
+  Serial.println();
+
+  Serial.println("Start labeling ...");
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    Serial.print(".");
+    DeviceAddress t;
+    sensors.getAddress(t, index);
+    sensors.setUserData(t, id);
+  }
+  Serial.println();
+
+  Serial.println();
+  Serial.println("Show results ...");
+  for (uint8_t index = 0; index < deviceCount; index++)
+  {
+    DeviceAddress t;
+    sensors.getAddress(t, index);
+    printAddress(t);
+    Serial.print("\t\tID: ");
+    int id = sensors.getUserData(t);
+    Serial.println(id);
+  }
+  Serial.println("Done ...");
+
+}
+
+void loop(void) {}
+
+// END OF FILE

+ 66 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/WaitForConversion/WaitForConversion.ino

@@ -0,0 +1,66 @@
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+void setup(void)
+{
+  // start serial port
+  Serial.begin(115200);
+  Serial.println("Dallas Temperature Control Library - Async Demo");
+  Serial.println("\nDemo shows the difference in length of the call\n\n");
+
+  // Start up the library
+  sensors.begin();
+}
+
+void loop(void)
+{ 
+  // Request temperature conversion (traditional)
+  Serial.println("Before blocking requestForConversion");
+  unsigned long start = millis();    
+
+  sensors.requestTemperatures();
+
+  unsigned long stop = millis();
+  Serial.println("After blocking requestForConversion");
+  Serial.print("Time used: ");
+  Serial.println(stop - start);
+  
+  // get temperature
+  Serial.print("Temperature: ");
+  Serial.println(sensors.getTempCByIndex(0));  
+  Serial.println("\n");
+  
+  // Request temperature conversion - non-blocking / async
+  Serial.println("Before NON-blocking/async requestForConversion");
+  start = millis();       
+  sensors.setWaitForConversion(false);  // makes it async
+  sensors.requestTemperatures();
+  sensors.setWaitForConversion(true);
+  stop = millis();
+  Serial.println("After NON-blocking/async requestForConversion");
+  Serial.print("Time used: ");
+  Serial.println(stop - start); 
+  
+  
+  // 9 bit resolution by default 
+  // Note the programmer is responsible for the right delay
+  // we could do something usefull here instead of the delay
+  int resolution = 9;
+  delay(750/ (1 << (12-resolution)));
+  
+  // get temperature
+  Serial.print("Temperature: ");
+  Serial.println(sensors.getTempCByIndex(0));  
+  Serial.println("\n\n\n\n");  
+  
+  delay(5000);
+}

+ 80 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/WaitForConversion2/WaitForConversion2.ino

@@ -0,0 +1,80 @@
+//
+// Sample of using Async reading of Dallas Temperature Sensors
+// 
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+DeviceAddress tempDeviceAddress;
+
+int  resolution = 12;
+unsigned long lastTempRequest = 0;
+int  delayInMillis = 0;
+float temperature = 0.0;
+int  idle = 0;
+//
+// SETUP
+//
+void setup(void)
+{
+  Serial.begin(115200);
+  Serial.println("Dallas Temperature Control Library - Async Demo");
+  Serial.print("Library Version: ");
+  Serial.println(DALLASTEMPLIBVERSION);
+  Serial.println("\n");
+
+  sensors.begin();
+  sensors.getAddress(tempDeviceAddress, 0);
+  sensors.setResolution(tempDeviceAddress, resolution);
+  
+  sensors.setWaitForConversion(false);
+  sensors.requestTemperatures();
+  delayInMillis = 750 / (1 << (12 - resolution)); 
+  lastTempRequest = millis(); 
+  
+  pinMode(13, OUTPUT); 
+}
+
+void loop(void)
+{ 
+  
+  if (millis() - lastTempRequest >= delayInMillis) // waited long enough??
+  {
+    digitalWrite(13, LOW);
+    Serial.print(" Temperature: ");
+    temperature = sensors.getTempCByIndex(0);
+    Serial.println(temperature, resolution - 8); 
+    Serial.print("  Resolution: ");
+    Serial.println(resolution); 
+    Serial.print("Idle counter: ");
+    Serial.println(idle);     
+    Serial.println(); 
+    
+    idle = 0; 
+        
+    // immediately after fetching the temperature we request a new sample 
+	// in the async modus
+    // for the demo we let the resolution change to show differences
+    resolution++;
+    if (resolution > 12) resolution = 9;
+    
+    sensors.setResolution(tempDeviceAddress, resolution);
+    sensors.requestTemperatures(); 
+    delayInMillis = 750 / (1 << (12 - resolution));
+    lastTempRequest = millis(); 
+  }
+  
+  digitalWrite(13, HIGH);
+  // we can do usefull things here 
+  // for the demo we just count the idle time in millis
+  delay(1);
+  idle++;
+}

+ 67 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/oneWireSearch/oneWireSearch.ino

@@ -0,0 +1,67 @@
+//
+//    FILE: oneWireSearch.ino
+//  AUTHOR: Rob Tillaart
+// VERSION: 0.1.02
+// PURPOSE: scan for 1-Wire devices + code snippet generator
+//    DATE: 2015-june-30
+//     URL: http://forum.arduino.cc/index.php?topic=333923
+//
+// inspired by http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html
+//
+// Released to the public domain
+//
+// 0.1.00 initial version
+// 0.1.01 first published version
+// 0.1.02 small output changes
+
+#include <OneWire.h>
+
+void setup()
+{
+  Serial.begin(115200);
+  Serial.println("//\n// Start oneWireSearch.ino \n//");
+
+  for (uint8_t pin = 2; pin < 13; pin++)
+  {
+    findDevices(pin);
+  }
+  Serial.println("\n//\n// End oneWireSearch.ino \n//");
+}
+
+void loop()
+{
+}
+
+uint8_t findDevices(int pin)
+{
+  OneWire ow(pin);
+
+  uint8_t address[8];
+  uint8_t count = 0;
+
+
+  if (ow.search(address))
+  {
+    Serial.print("\nuint8_t pin");
+    Serial.print(pin, DEC);
+    Serial.println("[][8] = {");
+    do {
+      count++;
+      Serial.println("  {");
+      for (uint8_t i = 0; i < 8; i++)
+      {
+        Serial.print("0x");
+        if (address[i] < 0x10) Serial.print("0");
+        Serial.print(address[i], HEX);
+        if (i < 7) Serial.print(", ");
+      }
+      Serial.println("  },");
+    } while (ow.search(address));
+
+    Serial.println("};");
+    Serial.print("// nr devices found: ");
+    Serial.println(count);
+  }
+
+  return count;
+}

+ 92 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/examples/readPowerSupply/readPowerSupply.ino

@@ -0,0 +1,92 @@
+//
+// FILE: readPowerSupply.ino
+// AUTHOR: Rob Tillaart
+// VERSION: 0.1.0
+// PURPOSE: demo
+// DATE: 2020-02-10
+//
+// Released to the public domain
+//
+
+// Include the libraries we need
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+// Data wire is plugged into port 2 on the Arduino
+#define ONE_WIRE_BUS 2
+
+// Setup a oneWire instance to communicate with any OneWire devices
+OneWire oneWire(ONE_WIRE_BUS);
+
+// Pass our oneWire reference to Dallas Temperature. 
+DallasTemperature sensors(&oneWire);
+
+// arrays to hold device addresses
+DeviceAddress insideThermometer, outsideThermometer;
+// Assign address manually. The addresses below will beed to be changed
+// to valid device addresses on your bus. Device address can be retrieved
+// by using either oneWire.search(deviceAddress) or individually via
+// sensors.getAddress(deviceAddress, index)
+// DeviceAddress insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
+// DeviceAddress outsideThermometer   = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 };
+
+int devCount = 0;
+
+/*
+ * The setup function. We only start the sensors here
+ */
+void setup(void)
+{
+  Serial.begin(115200);
+  Serial.println("Arduino Temperature Control Library Demo - readPowerSupply");
+
+  sensors.begin();
+
+  devCount = sensors.getDeviceCount();
+  Serial.print("#devices: ");
+  Serial.println(devCount);
+
+  // report parasite power requirements
+  Serial.print("Parasite power is: ");
+  if (sensors.readPowerSupply()) Serial.println("ON");  // no address means "scan all devices for parasite mode"
+  else Serial.println("OFF");
+
+  // Search for devices on the bus and assign based on an index.
+  if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
+  if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1");
+
+  // show the addresses we found on the bus
+  Serial.print("Device 0 Address: ");
+  printAddress(insideThermometer);
+  Serial.println();
+  Serial.print("Power = parasite: ");
+  Serial.println(sensors.readPowerSupply(insideThermometer));
+  Serial.println();
+  Serial.println();
+
+  Serial.print("Device 1 Address: ");
+  printAddress(outsideThermometer);
+  Serial.println();
+  Serial.print("Power = parasite: ");
+  Serial.println(sensors.readPowerSupply(outsideThermometer));
+  Serial.println();
+  Serial.println();
+}
+
+// function to print a device address
+void printAddress(DeviceAddress deviceAddress)
+{
+  for (uint8_t i = 0; i < 8; i++)
+  {
+    // zero pad the address if necessary
+    if (deviceAddress[i] < 0x10) Serial.print("0");
+    Serial.print(deviceAddress[i], HEX);
+  }
+}
+
+// empty on purpose
+void loop(void)
+{
+}
+
+// END OF FILE

+ 78 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/keywords.txt

@@ -0,0 +1,78 @@
+#######################################
+# Syntax Coloring Map For DallasTemperature
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+DallasTemperature	KEYWORD1
+OneWire	KEYWORD1
+AlarmHandler	KEYWORD1
+DeviceAddress	KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+setOneWire	KEYWORD2
+setPullupPin	KEYWORD2
+setResolution	KEYWORD2
+getResolution	KEYWORD2
+getTemp	KEYWORD2
+getTempC	KEYWORD2
+toFahrenheit	KEYWORD2
+getTempF	KEYWORD2
+getTempCByIndex	KEYWORD2
+getTempFByIndex	KEYWORD2
+rawToCelsius	KEYWORD2
+rawToFahrenheit	KEYWORD2
+setWaitForConversion	KEYWORD2
+getWaitForConversion	KEYWORD2
+requestTemperatures	KEYWORD2
+requestTemperaturesByAddress	KEYWORD2
+requestTemperaturesByIndex	KEYWORD2
+setCheckForConversion	KEYWORD2
+getCheckForConversion	KEYWORD2
+isConversionComplete	KEYWORD2
+millisToWaitForConversion	KEYWORD2
+isParasitePowerMode	KEYWORD2
+begin	KEYWORD2
+getDeviceCount	KEYWORD2
+getDS18Count	KEYWORD2
+getAddress	KEYWORD2
+validAddress	KEYWORD2
+validFamily	KEYWORD2
+isConnected	KEYWORD2
+readScratchPad	KEYWORD2
+writeScratchPad	KEYWORD2
+readPowerSupply	KEYWORD2
+saveScratchPadByIndex	KEYWORD2
+saveScratchPad	KEYWORD2
+recallScratchPadByIndex	KEYWORD2
+recallScratchPad	KEYWORD2
+setAutoSaveScratchPad	KEYWORD2
+getAutoSaveScratchPad	KEYWORD2
+setHighAlarmTemp	KEYWORD2
+setLowAlarmTemp	KEYWORD2
+getHighAlarmTemp	KEYWORD2
+getLowAlarmTemp	KEYWORD2
+resetAlarmSearch	KEYWORD2
+alarmSearch	KEYWORD2
+hasAlarm	KEYWORD2
+toCelsius	KEYWORD2
+processAlarms	KEYWORD2
+setAlarmHandler	KEYWORD2
+hasAlarmHandler	KEYWORD2
+setUserData	KEYWORD2
+setUserDataByIndex	KEYWORD2
+getUserData	KEYWORD2
+getUserDataByIndex	KEYWORD2
+calculateTemperature	KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
+
+DEVICE_DISCONNECTED_C	LITERAL1
+DEVICE_DISCONNECTED_F	LITERAL1
+DEVICE_DISCONNECTED_RAW	LITERAL1

+ 38 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/library.json

@@ -0,0 +1,38 @@
+{
+  "name": "DallasTemperature",
+  "keywords": "onewire, 1-wire, bus, sensor, temperature",
+  "description": "Arduino Library for Dallas Temperature ICs (DS18B20, DS18S20, DS1822, DS1820)",
+  "repository":
+  {
+    "type": "git",
+    "url": "https://github.com/milesburton/Arduino-Temperature-Control-Library.git"
+  },
+  "authors": 
+  [
+    {
+      "name": "Miles Burton",
+      "email": "miles@mnetcs.com",
+      "url": "http://www.milesburton.com",
+      "maintainer": true
+    },
+    {
+      "name": "Tim Newsome",
+      "email": "nuisance@casualhacker.net"
+    },
+    {
+      "name": "Guil Barros",
+      "email": "gfbarros@bappos.com"
+    },
+    {
+      "name": "Rob Tillaart",
+      "email": "rob.tillaart@gmail.com"
+    }
+  ],
+  "dependencies":
+  {
+    "paulstoffregen/OneWire": "^2.3.5"
+  },
+  "version": "3.9.1",
+  "frameworks": "arduino",
+  "platforms": "*"
+}

+ 10 - 0
lib/Arduino-Temperature-Control-Library-3.9.1/library.properties

@@ -0,0 +1,10 @@
+name=DallasTemperature
+version=3.9.0
+author=Miles Burton <miles@mnetcs.com>, Tim Newsome <nuisance@casualhacker.net>, Guil Barros <gfbarros@bappos.com>, Rob Tillaart <rob.tillaart@gmail.com>
+maintainer=Miles Burton <miles@mnetcs.com>
+sentence=Arduino Library for Dallas Temperature ICs
+paragraph=Supports DS18B20, DS18S20, DS1822, DS1820
+category=Sensors
+url=https://github.com/milesburton/Arduino-Temperature-Control-Library
+architectures=*
+depends=OneWire

+ 12 - 0
lib/ArduinoJson-6.20.1/.clang-format

@@ -0,0 +1,12 @@
+# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+
+BasedOnStyle: Google
+Standard: Cpp03
+AllowShortFunctionsOnASingleLine: Empty
+IncludeBlocks: Preserve
+IndentPPDirectives: AfterHash
+DerivePointerAlignment: false
+
+# Always break after if to get accurate coverage
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false

+ 1 - 0
lib/ArduinoJson-6.20.1/.gitattributes

@@ -0,0 +1 @@
+*.sh text eol=lf

+ 4 - 0
lib/ArduinoJson-6.20.1/.github/FUNDING.yml

@@ -0,0 +1,4 @@
+github: bblanchon
+custom:
+  - https://arduinojson.org/book/
+  - https://donate.benoitblanchon.fr/

+ 54 - 0
lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,54 @@
+---
+name: 🐛 Bug report
+about: Report a bug in ArduinoJson
+title: ''
+labels: 'bug'
+assignees: ''
+---
+
+<!-- ⚠️ IMPORTANT ⚠️
+Before opening a bug report, please use the ArduinoJson Troubleshooter as it may find a solution to your issue; if not, please include the  Troubleshooter's report in the description.
+-->
+
+**Describe the bug**  
+A clear and concise description of what the bug is.
+
+**Troubleshooter report**  
+Here is the report generated by the [ArduinoJson Troubleshooter](https://arduinojson.org/v6/troubleshooter/):  
+[Paste the report here]
+
+**Environment**  
+Here is the environment that I used:
+* Microcontroller: [e.g. ESP8266]
+* Core/runtime: [e.g. ESP8266 core for Arduino v3.0.2]
+* IDE: [e.g. Arduino IDE 1.8.16]
+
+**Reproduction**  
+Here is a small snippet that reproduces the issue.
+
+```c++
+DynamicJsonDocument doc(1024);
+
+DeserializationError error = deserializeJson(doc, "{\"hello\":\"world\"}");
+
+[insert repro code here]
+```
+
+**Compiler output**    
+If relevant, include the complete compiler output (i.e. not just the line that contains the error.)
+
+
+**Program output**  
+If relevant, include the repro program output.
+
+Expected output:
+
+```
+[insert expected output here]
+```
+
+Actual output:
+
+```
+[insert actual output here]
+```

+ 8 - 0
lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/config.yml

@@ -0,0 +1,8 @@
+blank_issues_enabled: true
+contact_links:
+  - name: 👨‍🏫 ArduinoJson Assistant
+    url: https://arduinojson.org/v6/assistant/
+    about: An online tool that computes memory requirements and generates scaffolding code for your project.
+  - name: 👨‍⚕️ ArduinoJson Troubleshooter
+    url: https://arduinojson.org/v6/troubleshooter/
+    about: An online tool that helps you diagnose the most common issues with ArduinoJson.

+ 19 - 0
lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,19 @@
+---
+name: 💡 Feature request
+about: Suggest an idea for ArduinoJson
+title: ''
+labels: enhancement
+assignees: ''
+---
+
+**Is your feature request related to a problem? Please describe.**  
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**  
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**  
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**  
+Add any other context or screenshots about the feature request here.

+ 51 - 0
lib/ArduinoJson-6.20.1/.github/ISSUE_TEMPLATE/help.md

@@ -0,0 +1,51 @@
+---
+name: 😭 Help!
+about: Ask for help
+title: ''
+labels: 'question'
+assignees: ''
+---
+
+<!-- ⚠️ IMPORTANT ⚠️
+Before asking for help, please use the ArduinoJson Troubleshooter as it may find a solution to your issue; if not, please include the  Troubleshooter's report in the description.
+-->
+
+**Describe the issue**  
+A clear and concise description of what you're trying to do.
+You don't need to explain every aspect of your project: focus on the problem you're having.
+
+**Troubleshooter report**  
+Here is the report generated by the [ArduinoJson Troubleshooter](https://arduinojson.org/v6/troubleshooter/):  
+[Paste the report here]
+
+**Environment**  
+Here is the environment that I'm using':
+* Microconroller: [e.g. ESP8266]
+* Core/runtime: [e.g. ESP8266 core for Arduino v3.0.2]
+* IDE: [e.g. Arduino IDE 1.8.16]
+
+**Reproduction**  
+Here is a small snippet that demonstrate the problem.
+
+```c++
+DynamicJsonDocument doc(1024);
+
+DeserializationError error = deserializeJson(doc, "{\"hello\":\"world\"}");
+
+// insert code here
+```
+
+**Program output**  
+If relevant, include the program output.
+
+Expected output:
+
+```
+[insert expected output here]
+```
+
+Actual output:
+
+```
+[insert actual output here]
+```

+ 602 - 0
lib/ArduinoJson-6.20.1/.github/workflows/ci.yml

@@ -0,0 +1,602 @@
+name: Continuous Integration
+
+on: [push, pull_request]
+
+jobs:
+  lint:
+    name: Lint
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: sudo apt-get install -y clang-format
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Symlinks
+        run: find * -type l -printf "::error::%p is a symlink. This is forbidden by the Arduino Library Specification." -exec false {} +
+      - name: Clang-format
+        run: |
+          find src/ extras/ -name '*.[ch]pp' | xargs clang-format -i --verbose --style=file
+          git diff --exit-code
+      - name: Check URLs
+        run: |
+          grep -hREo "(http|https)://[a-zA-Z0-9./?=_%:-]*" src/ | sort -u | while read -r URL
+          do
+            STATUS=$(curl -s -o /dev/null -I -w "%{http_code}" "$URL")
+            [ "$STATUS" -ge 400 ] && echo "::warning title=HTTP $STATUS::$URL returned $STATUS"
+          done || true
+
+  gcc:
+    name: GCC
+    needs: lint
+    runs-on: ubuntu-22.04
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - gcc: "4.4"
+          - gcc: "4.6"
+          - gcc: "4.7"
+          - gcc: "4.8"
+          - gcc: "4.9"
+          - gcc: "5"
+          - gcc: "6"
+          - gcc: "7"
+            cxxflags: -fsanitize=leak -fno-sanitize-recover=all
+          - gcc: "8"
+            cxxflags: -fsanitize=undefined -fno-sanitize-recover=all
+          - gcc: "9"
+            cxxflags: -fsanitize=address -fno-sanitize-recover=all
+          - gcc: "10"
+            cxxflags: -funsigned-char # Issue #1715
+          - gcc: "11"
+    steps:
+      - name: Install
+        run: |
+          sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 3B4FE6ACC0B21F32
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ trusty main universe'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ xenial main universe'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ bionic main universe'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ focal main universe'
+          sudo apt-get update
+          sudo apt-get install -y gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }}
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake -DCMAKE_BUILD_TYPE=Debug .
+        env:
+          CC: gcc-${{ matrix.gcc }}
+          CXX: g++-${{ matrix.gcc }}
+          CXXFLAGS: ${{ matrix.cxxflags }}
+      - name: Build
+        run: cmake --build .
+      - name: Test
+        run: |
+          echo "## CTest output" >> $GITHUB_STEP_SUMMARY
+          echo '```' >> $GITHUB_STEP_SUMMARY
+          ctest --output-on-failure -C Debug . | tee -a $GITHUB_STEP_SUMMARY
+          echo '```' >> $GITHUB_STEP_SUMMARY
+        env:
+          UBSAN_OPTIONS: print_stacktrace=1
+
+  clang:
+    name: Clang
+    needs: lint
+    runs-on: ubuntu-20.04
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - clang: "3.5"
+            cxxflags: "-stdlib=libc++"
+          - clang: "3.6"
+            cxxflags: "-stdlib=libc++"
+          - clang: "3.7"
+            cxxflags: "-stdlib=libc++"
+          - clang: "3.8"
+            cxxflags: "-stdlib=libc++"
+          - clang: "3.9"
+            cxxflags: "-stdlib=libc++"
+          - clang: "4.0"
+            cxxflags: "-stdlib=libc++"
+          - clang: "5.0"
+          - clang: "6.0"
+          - clang: "7"
+          - clang: "8"
+            cxxflags: -fsanitize=leak -fno-sanitize-recover=all
+          - clang: "9"
+            cxxflags: -fsanitize=undefined -fno-sanitize-recover=all
+          - clang: "10"
+            cxxflags: -fsanitize=address -fno-sanitize-recover=all
+    steps:
+      - name: Install
+        run: |
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ trusty main'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ trusty universe'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ xenial main'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ xenial universe'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ bionic main'
+          sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ bionic universe'
+          sudo apt-get update
+          sudo apt-get install -y clang-${{ matrix.clang }}
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake -DCMAKE_BUILD_TYPE=Debug .
+        env:
+          CC: clang-${{ matrix.clang }}
+          CXX: clang++-${{ matrix.clang }}
+          CXXFLAGS: >-
+            ${{ matrix.cxxflags }}
+            ${{ contains(matrix.cxxflags, 'libc++') && '-I/usr/lib/llvm-10/include/c++/v1/' || '' }}
+      - name: Build
+        run: cmake --build .
+      - name: Test
+        run: |
+          echo "## CTest output" >> $GITHUB_STEP_SUMMARY
+          echo '```' >> $GITHUB_STEP_SUMMARY
+          ctest --output-on-failure -C Debug . | tee -a $GITHUB_STEP_SUMMARY
+          echo '```' >> $GITHUB_STEP_SUMMARY
+        env:
+          UBSAN_OPTIONS: print_stacktrace=1
+
+  conf_test:
+    name: Test configuration on Linux
+    needs: [gcc, clang]
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y g++-multilib
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: GCC 32-bit
+        run: g++ -std=c++11 -m32 -Isrc extras/conf_test/x86.cpp
+      - name: GCC 64-bit
+        run: g++ -std=c++11 -m64 -Isrc extras/conf_test/x64.cpp
+      - name: Clang 32-bit
+        run: clang++ -std=c++11 -m32 -Isrc extras/conf_test/x86.cpp
+      - name: Clang 64-bit
+        run: clang++ -std=c++11 -m64 -Isrc extras/conf_test/x64.cpp
+
+  conf_test_windows:
+    name: Test configuration on Windows
+    runs-on: windows-2019
+    needs: [gcc, clang]
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: 32-bit
+        run: |
+          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars32.bat"
+          cl /Isrc extras/conf_test/x86.cpp
+        shell: cmd
+      - name: 64-bit
+        run: |
+          call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+          cl /Isrc extras/conf_test/x64.cpp
+        shell: cmd
+
+  xcode:
+    name: XCode
+    needs: clang
+    runs-on: macos-11
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - xcode: "11.7"
+          - xcode: "12.4"
+          - xcode: "13.2.1"
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Select XCode version
+        run: sudo xcode-select --switch /Applications/Xcode_${{ matrix.xcode }}.app
+      - name: Configure
+        run: cmake -DCMAKE_BUILD_TYPE=Debug .
+      - name: Build
+        run: cmake --build .
+      - name: Test
+        run: ctest --output-on-failure -C Debug .
+
+  # DISABLED: Running on AppVeyor instead because it supports older versions of the compiler
+  # msvc:
+  #   name: Visual Studio
+  #   strategy:
+  #     fail-fast: false
+  #     matrix:
+  #       include:
+  #         - os: windows-2016
+  #         - os: windows-2019
+  #   runs-on: ${{ matrix.os }}
+  #   steps:
+  #     - name: Checkout
+  #       uses: actions/checkout@v3
+  #     - name: Configure
+  #       run: cmake -DCMAKE_BUILD_TYPE=Debug .
+  #     - name: Build
+  #       run: cmake --build .
+  #     - name: Test
+  #       run: ctest --output-on-failure -C Debug .
+
+  arduino:
+    name: Arduino
+    needs: gcc
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - core: arduino:avr
+            board: arduino:avr:uno
+          - core: arduino:samd
+            board: arduino:samd:mkr1000
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Install arduino-cli
+        run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh
+      - name: Install core
+        run: arduino-cli core install ${{ matrix.core }}
+      - name: Install libraries
+        run: arduino-cli lib install SD Ethernet
+      - name: Build JsonConfigFile
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonConfigFile/JsonConfigFile.ino"
+      - name: Build JsonFilterExample
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonFilterExample/JsonFilterExample.ino"
+      - name: Build JsonGeneratorExample
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonGeneratorExample/JsonGeneratorExample.ino"
+      - name: Build JsonHttpClient
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonHttpClient/JsonHttpClient.ino"
+      - name: Build JsonParserExample
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonParserExample/JsonParserExample.ino"
+      - name: Build JsonServer
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonServer/JsonServer.ino"
+      - name: Build JsonUdpBeacon
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonUdpBeacon/JsonUdpBeacon.ino"
+      - name: Build MsgPackParser
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/MsgPackParser/MsgPackParser.ino"
+      - name: Build ProgmemExample
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/ProgmemExample/ProgmemExample.ino"
+      - name: Build StringExample
+        run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/StringExample/StringExample.ino"
+
+  platformio:
+    name: PlatformIO
+    needs: gcc
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - platform: atmelavr
+            board: leonardo
+            libraries:
+              - SD
+              - Ethernet
+            conf_test: avr
+          - platform: espressif8266
+            board: huzzah
+            conf_test: esp8266
+          - platform: espressif32
+            board: esp32dev
+            libraries:
+              - Ethernet
+            conf_test: esp8266
+          - platform: atmelsam
+            board: mkr1000USB
+            libraries:
+              - SD
+              - Ethernet
+            conf_test: esp8266
+          - platform: teensy
+            board: teensy31
+            conf_test: esp8266
+          - platform: ststm32
+            board: adafruit_feather_f405
+            libraries:
+              - SD
+              - Ethernet
+            conf_test: esp8266
+          - platform: nordicnrf52
+            board: adafruit_feather_nrf52840
+            libraries:
+              - SD
+              - Ethernet
+            conf_test: esp8266
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Set up cache for pip
+        uses: actions/cache@v3
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip
+      - name: Set up Python 3.x
+        uses: actions/setup-python@v4
+        with:
+          python-version: "3.x"
+      - name: Install PlatformIO
+        run: pip install platformio
+      - name: Install adafruit-nrfutil
+        if: ${{ matrix.platform == 'nordicnrf52' }}
+        run: pip install adafruit-nrfutil
+      - name: Include Adafruit_TinyUSB.h # https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/653
+        if: ${{ matrix.platform == 'nordicnrf52' }}
+        run: find examples/ -name '*.ino' -exec sed -i 's/\(#include <ArduinoJson.h>\)/\1\n#include <Adafruit_TinyUSB.h>/' {} +
+      - name: Set up cache for platformio
+        uses: actions/cache@v3
+        with:
+          path: ~/.platformio
+          key: ${{ runner.os }}-platformio-${{ matrix.platform }}
+      - name: Install platform "${{ matrix.platform }}"
+        run: platformio platform install ${{ matrix.platform }}
+      - name: Install libraries
+        if: ${{ matrix.libraries }}
+        run: platformio lib install arduino-libraries/${{ join(matrix.libraries, ' arduino-libraries/') }}
+      - name: Test configuration
+        run: platformio ci "extras/conf_test/${{ matrix.conf_test }}.cpp" -l '.' -b ${{ matrix.board }}
+        if: ${{ matrix.conf_test }}
+      - name: Build JsonConfigFile
+        run: platformio ci "examples/JsonConfigFile/JsonConfigFile.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonFilterExample
+        run: platformio ci "examples/JsonFilterExample/JsonFilterExample.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonGeneratorExample
+        run: platformio ci "examples/JsonGeneratorExample/JsonGeneratorExample.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonHttpClient
+        run: platformio ci "examples/JsonHttpClient/JsonHttpClient.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonParserExample
+        run: platformio ci "examples/JsonParserExample/JsonParserExample.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonServer
+        if: ${{ matrix.platform != 'espressif32' }}
+        run: platformio ci "examples/JsonServer/JsonServer.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build JsonUdpBeacon
+        run: platformio ci "examples/JsonUdpBeacon/JsonUdpBeacon.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build MsgPackParser
+        run: platformio ci "examples/MsgPackParser/MsgPackParser.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build ProgmemExample
+        run: platformio ci "examples/ProgmemExample/ProgmemExample.ino" -l '.' -b ${{ matrix.board }}
+      - name: Build StringExample
+        run: platformio ci "examples/StringExample/StringExample.ino" -l '.' -b ${{ matrix.board }}
+      - name: PlatformIO prune
+        if: ${{ always() }}
+        run: platformio system prune -f
+
+  particle:
+    name: Particle
+    needs: gcc
+    runs-on: ubuntu-latest
+    if: github.event_name == 'push'
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - board: argon
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Install Particle CLI
+        run: sudo npm install -g particle-cli
+      - name: Login to Particle
+        run: particle login -t "${{ secrets.PARTICLE_TOKEN }}"
+      - name: Compile
+        run: extras/ci/particle.sh ${{ matrix.board }}
+
+  arm:
+    name: GCC for ARM processor
+    needs: gcc
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y g++-arm-linux-gnueabihf
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake .
+        env:
+          CC: arm-linux-gnueabihf-gcc
+          CXX: arm-linux-gnueabihf-g++
+      - name: Build
+        run: cmake --build .
+
+  coverage:
+    needs: gcc
+    name: Coverage
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: sudo apt-get install -y lcov ninja-build
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake -G Ninja -DCOVERAGE=true .
+      - name: Build
+        run: ninja
+      - name: Test
+        run: ctest -LE 'WillFail|Fuzzing' -T test
+      - name: lcov --capture
+        run: lcov --capture --no-external --directory . --output-file coverage.info
+      - name: lcov --remove
+        run: lcov --remove coverage.info "$(pwd)/extras/*" --output-file coverage_filtered.info
+      - name: genhtml
+        run: mkdir coverage && genhtml coverage_filtered.info -o coverage -t ArduinoJson
+      - name: Upload HTML report
+        uses: actions/upload-artifact@v3
+        with:
+          name: Coverage report
+          path: coverage
+      - name: Upload to Coveralls
+        uses: coverallsapp/github-action@master
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          path-to-lcov: coverage_filtered.info
+
+  valgrind:
+    needs: gcc
+    name: Valgrind
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y valgrind ninja-build
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake -G Ninja -D MEMORYCHECK_COMMAND_OPTIONS="--error-exitcode=1 --leak-check=full"  .
+      - name: Build
+        run: ninja
+      - name: Memcheck
+        run: ctest -LE WillFail -T memcheck
+        id: memcheck
+      - name: MemoryChecker.*.log
+        run: cat Testing/Temporary/MemoryChecker.*.log
+        if: failure()
+
+  clang-tidy:
+    needs: clang
+    name: Clang-Tidy
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: sudo apt-get install -y clang-tidy cmake ninja-build
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Configure
+        run: cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY="clang-tidy-10;--warnings-as-errors=*" -DCMAKE_BUILD_TYPE=Debug .
+        env:
+          CC: clang-10
+          CXX: clang++-10
+      - name: Check
+        run: cmake --build . -- -k 0
+
+  amalgamate-h:
+    needs: gcc
+    name: Amalgamate ArduinoJson.h
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Amalgamate
+        id: amalgamate
+        run: |
+          if [[ $GITHUB_REF == refs/tags/* ]]; then
+            VERSION=${GITHUB_REF#refs/tags/}
+          else
+            VERSION=${GITHUB_SHA::7}
+          fi
+          INPUT=src/ArduinoJson.h
+          OUTPUT=ArduinoJson-$VERSION.h
+          extras/scripts/build-single-header.sh "$INPUT" "$OUTPUT"
+          echo "filename=${OUTPUT}" >> $GITHUB_OUTPUT
+      - name: Smoke test
+        run: |
+          g++ -x c++ - <<END
+          #include "${{ steps.amalgamate.outputs.filename }}"
+          int main() {
+            StaticJsonDocument<300> doc;
+            deserializeJson(doc, "{}");
+          }
+          END
+      - name: Upload artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: Single headers
+          path: ${{ steps.amalgamate.outputs.filename }}
+
+  amalgamate-hpp:
+    needs: gcc
+    name: Amalgamate ArduinoJson.hpp
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Amalgamate
+        id: amalgamate
+        run: |
+          if [[ $GITHUB_REF == refs/tags/* ]]; then
+            VERSION=${GITHUB_REF#refs/tags/}
+          else
+            VERSION=${GITHUB_SHA::7}
+          fi
+          INPUT=src/ArduinoJson.hpp
+          OUTPUT=ArduinoJson-$VERSION.hpp
+          extras/scripts/build-single-header.sh "$INPUT" "$OUTPUT"
+          echo "filename=${OUTPUT}" >> $GITHUB_OUTPUT
+      - name: Smoke test
+        run: |
+          g++ -x c++ - <<END
+          #include "${{ steps.amalgamate.outputs.filename }}"
+          int main() {
+            ArduinoJson::StaticJsonDocument<300> doc;
+            deserializeJson(doc, "{}");
+          }
+          END
+      - name: Upload artifact
+        uses: actions/upload-artifact@v3
+        with:
+          name: Single headers
+          path: ${{ steps.amalgamate.outputs.filename }}
+
+  esp-idf:
+    needs: gcc
+    name: ESP-IDF
+    runs-on: ubuntu-latest
+    steps:
+      - name: Setup cache
+        uses: actions/cache@v3
+        with:
+          path: ~/.espressif
+          key: ${{ runner.os }}-esp-idf
+      - name: Checkout ArduinoJson
+        uses: actions/checkout@v3
+      - name: Checkout ESP-IDF
+        uses: actions/checkout@v3
+        with:
+          repository: espressif/esp-idf
+          path: esp-idf
+          submodules: true
+      - name: Install ESP-IDF
+        run: ./esp-idf/install.sh
+      - name: Add component
+        # NOTE: we cannot commit the symlink because the Arduino Library Specification forbids it.
+        run: |
+          mkdir -p extras/ci/espidf/components
+          ln -s $PWD extras/ci/espidf/components/ArduinoJson
+      - name: Build example
+        run: |
+          source esp-idf/export.sh
+          cd extras/ci/espidf
+          idf.py build
+
+  codeql:
+    name: CodeQL
+    runs-on: ubuntu-20.04
+    needs: gcc
+
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v3
+
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v2
+      with:
+        languages: cpp
+
+    - name: Build
+      run: |
+        cmake -DCMAKE_BUILD_TYPE=Debug .
+        cmake --build .
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v2
+      with:
+        category: "/language:cpp"

+ 14 - 0
lib/ArduinoJson-6.20.1/.github/workflows/lock.yml

@@ -0,0 +1,14 @@
+name: Lock Threads
+
+on:
+  schedule:
+    - cron: '0 0 * * *'
+
+jobs:
+  lock:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: dessant/lock-threads@v4
+        with:
+          github-token: ${{ github.token }}
+          issue-inactive-days: 30

+ 74 - 0
lib/ArduinoJson-6.20.1/.github/workflows/release.yml

@@ -0,0 +1,74 @@
+name: Release
+
+on:
+  push:
+    tags:
+      - v*.*.*
+
+jobs:
+  release:
+    name: Create release
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Set variables
+        id: init
+        run: |
+          echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
+          echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Write release body
+        id: body
+        run: |
+          FILENAME=RELEASE.md
+          extras/scripts/get-release-body.sh ${{ steps.init.outputs.tag }} CHANGELOG.md | tee $FILENAME
+          echo "filename=$FILENAME" >> $GITHUB_OUTPUT
+      - name: Amalgamate ArduinoJson.h
+        id: amalgamate_h
+        run: |
+          FILENAME=ArduinoJson-${{ steps.init.outputs.tag }}.h
+          extras/scripts/build-single-header.sh src/ArduinoJson.h "$FILENAME"
+          echo "filename=$FILENAME" >> $GITHUB_OUTPUT
+      - name: Amalgamate ArduinoJson.hpp
+        id: amalgamate_hpp
+        run: |
+          FILENAME=ArduinoJson-${{ steps.init.outputs.tag }}.hpp
+          extras/scripts/build-single-header.sh src/ArduinoJson.hpp "$FILENAME"
+          echo "filename=$FILENAME" >> $GITHUB_OUTPUT
+      - name: Create Arduino package
+        id: arduino
+        run: |
+          FILENAME=ArduinoJson-${{ steps.init.outputs.tag }}.zip
+          extras/scripts/build-arduino-package.sh . "$FILENAME"
+          echo "filename=$FILENAME" >> $GITHUB_OUTPUT
+      - name: Create release
+        uses: ncipollo/release-action@v1
+        with:
+          bodyFile: ${{ steps.body.outputs.filename }}
+          name: ArduinoJson ${{ steps.init.outputs.version }}
+          artifacts: ${{ steps.amalgamate_h.outputs.filename }},${{ steps.amalgamate_hpp.outputs.filename }},${{ steps.arduino.outputs.filename }}
+          token: ${{ secrets.GITHUB_TOKEN }}
+
+  idf:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Upload component to the component registry
+        uses: espressif/upload-components-ci-action@v1
+        with:
+          name: ArduinoJson
+          namespace: bblanchon
+          api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
+
+  particle:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Install
+        run: npm install -g particle-cli
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Login
+        run: particle login --token ${{ secrets.PARTICLE_TOKEN }}
+      - name: Publish
+        run: extras/scripts/publish-particle-library.sh

+ 20 - 0
lib/ArduinoJson-6.20.1/.gitignore

@@ -0,0 +1,20 @@
+.DS_Store
+/.idea
+/build
+/bin
+/lib
+/sftp-config.json
+.tags
+.tags_sorted_by_file
+/extras/fuzzing/*_fuzzer
+/extras/fuzzing/*_fuzzer.options
+/extras/fuzzing/*_fuzzer_seed_corpus.zip
+.vs/
+/out/
+
+# Used by CI for Particle
+/src/*.ino
+/project.properties
+
+# Used by IDF
+/dist/

+ 3 - 0
lib/ArduinoJson-6.20.1/.mbedignore

@@ -0,0 +1,3 @@
+.github/
+examples/
+extras/

+ 1 - 0
lib/ArduinoJson-6.20.1/.prettierignore

@@ -0,0 +1 @@
+*.md

+ 14 - 0
lib/ArduinoJson-6.20.1/.vscode/settings.json

@@ -0,0 +1,14 @@
+{
+  "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
+  "cmake.generator": "Ninja",
+  "git.inputValidationLength": 80,
+  "git.inputValidationSubjectLength": 72,
+  "files.insertFinalNewline": true,
+  "files.trimFinalNewlines": true,
+  "search.exclude": {
+    "/extras/tests/catch/*": true
+  },
+  "C_Cpp.default.includePath": [
+    "/src"
+  ]
+}

+ 5 - 0
lib/ArduinoJson-6.20.1/ArduinoJson.h

@@ -0,0 +1,5 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+
+#include "src/ArduinoJson.h"

+ 825 - 0
lib/ArduinoJson-6.20.1/CHANGELOG.md

@@ -0,0 +1,825 @@
+ArduinoJson: change log
+=======================
+
+v6.20.1 (2023-02-08)
+-------
+
+* Remove explicit exclusion of `as<char*>()` and `as<char>()` (issue #1860)
+  If you try to call them, you'll now get the same error message as any unsupported type.
+  You could also add a custom converter for `char*` and `char`.
+
+v6.20.0 (2022-12-26)
+-------
+
+* Add `JsonVariant::shallowCopy()` (issue #1343)
+* Fix `9.22337e+18 is outside the range of representable values of type 'long'`
+* Fix comparison operators for `JsonArray`, `JsonArrayConst`, `JsonObject`, and `JsonObjectConst`
+* Fix lax parsing of `true`, `false`, and `null` (issue #1781)
+* Remove undocumented `accept()` functions
+* Rename `addElement()` to `add()`
+* Remove `getElement()`, `getOrAddElement()`, `getMember()`, and `getOrAddMember()`
+* Remove undocumented `JsonDocument::data()` and `JsonDocument::memoryPool()`
+* Remove undocumented `JsonArrayIterator::internal()` and `JsonObjectIterator::internal()`
+* Rename things in `ARDUINOJSON_NAMESPACE` to match the public names
+* Add documentation to most public symbols
+* Remove support for naked `char` (was deprecated since 6.18.0)
+
+> ### BREAKING CHANGES
+>
+> This release hides `JsonVariant`'s functions that were only intended for internal use.
+> If you were using them in your programs, you must replace with `operator[]` and `to<JsonVariant>()`, like so:
+>
+> ```c++
+> // before
+> JsonVariant a = variant.getElement(idx);
+> JsonVariant b = variant.getOrAddElement(idx);
+> JsonVariant c = variant.getMember(key);
+> JsonVariant d = variant.getOrAddMember(key);
+>
+> // after
+> JsonVariant a = variant[idx];
+> JsonVariant b = idx < variant.size() ? variant[idx] : variant[idx].to<JsonVariant>();
+> JsonVariant c = variant[key];
+> JsonVariant d = variant.containsKey(key) ? variant[key] : variant[key].to<JsonVariant>();
+> ```
+
+v6.19.4 (2022-04-05)
+-------
+
+* Add `ElementProxy::memoryUsage()`
+* Add `MemberProxy::memoryUsage()` (issue #1730)
+* Add implicit conversion from `JsonDocument` to `JsonVariant`
+* Fix comparisons operators with `const JsonDocument&`
+
+v6.19.3 (2022-03-08)
+-------
+
+* Fix `call of overloaded 'String(const char*, int)' is ambiguous`
+* Fix `JsonString` operator `==` and `!=` for non-zero-terminated string
+* Fix `-Wsign-conversion` on GCC 8 (issue #1715)
+* MessagePack: serialize round floats as integers (issue #1718)
+
+v6.19.2 (2022-02-14)
+-------
+
+* Fix `cannot convert 'pgm_p' to 'const void*'` (issue #1707)
+
+v6.19.1 (2022-01-14)
+-------
+
+* Fix crash when adding an object member in a too small `JsonDocument`
+* Fix filter not working in zero-copy mode (issue #1697)
+
+v6.19.0 (2022-01-08)
+-------
+
+* Remove `ARDUINOJSON_EMBEDDED_MODE` and assume we run on an embedded platform.  
+  Dependent settings (like `ARDUINOJSON_DEFAULT_NESTING_LIMIT`) must be set individually.
+* Change the default of `ARDUINOJSON_USE_DOUBLE` to `1`
+* Change the default of `ARDUINOJSON_USE_LONG_LONG` to `1` on 32-bit platforms
+* Add `as<JsonString>()` and `is<JsonString>()`
+* Add safe bool idiom in `JsonString`
+* Add support for NUL in string values (issue #1646)
+* Add support for arbitrary array rank in `copyArray()`
+* Add support for `char[][]` in `copyArray()`
+* Remove `DeserializationError == bool` and `DeserializationError != bool`
+* Renamed undocumented function `isUndefined()` to `isUnbound()`
+* Fix `JsonVariant::memoryUsage()` for raw strings
+* Fix `call of overloaded 'swap(BasicJsonDocument&, BasicJsonDocument&)' is ambiguous` (issue #1678)
+* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move constructors
+* Fix inconsistent pool capacity between `BasicJsonDocument`'s copy and move assignments
+* Fix return type of `StaticJsonDocument::operator=`
+* Avoid pool reallocation in `BasicJsonDocument`'s copy assignment if capacity is the same
+* Avoid including `Arduino.h` when all its features are disabled (issue #1692, PR #1693 by @paulocsanz)
+* Assume `PROGMEM` is available as soon as `ARDUINO` is defined (consequence of #1693)
+
+v6.18.5 (2021-09-28)
+-------
+
+* Set `ARDUINOJSON_EMBEDDED_MODE` to `1` on Nios II (issue #1657)
+
+v6.18.4 (2021-09-06)
+-------
+
+* Fixed error `'dummy' may be used uninitialized` on GCC 11
+* Fixed error `expected unqualified-id before 'const'` on GCC 11 (issue #1622)
+* Filter: exact match takes precedence over wildcard (issue #1628)
+* Fixed deserialization of `\u0000` (issue #1646)
+
+v6.18.3 (2021-07-27)
+-------
+
+* Changed return type of `convertToJson()` and `Converter<T>::toJson()` to `void`
+* Added `as<std::string_view>()` and `is<std::string_view>()`
+
+v6.18.2 (2021-07-19)
+-------
+
+* Removed a symlink because the Arduino Library Specification forbids it
+
+v6.18.1 (2021-07-03)
+-------
+
+* Fixed support for `volatile float` and `volatile double` (issue #1557)
+* Fixed error `[Pe070]: incomplete type is not allowed` on IAR (issue #1560)
+* Fixed `serializeJson(doc, String)` when allocation fails (issue #1572)
+* Fixed clang-tidy warnings (issue #1574, PR #1577 by @armandas)
+* Added fake class `InvalidConversion<T1,T2>` to easily identify invalid conversions (issue #1585)
+* Added support for `std::string_view` (issue #1578, PR #1554 by @0xFEEDC0DE64)
+* Fixed warning `definition of implicit copy constructor for 'MsgPackDeserializer' is deprecated because it has a user-declared copy assignment operator`
+* Added `JsonArray::clear()` (issue #1597)
+* Fixed `JsonVariant::as<unsigned>()` (issue #1601)
+* Added support for ESP-IDF component build (PR #1562 by @qt1, PR #1599 by @andreaskuster)
+
+v6.18.0 (2021-05-05)
+-------
+
+* Added support for custom converters (issue #687)
+* Added support for `Printable` (issue #1444)
+* Removed support for `char` values, see below (issue #1498)
+* `deserializeJson()` leaves `\uXXXX` unchanged instead of returning `NotSupported`
+* `deserializeMsgPack()` inserts `null` instead of returning `NotSupported`
+* Removed `DeserializationError::NotSupported`
+* Added `JsonVariant::is<JsonArrayConst/JsonObjectConst>()` (issue #1412)
+* Added `JsonVariant::is<JsonVariant/JsonVariantConst>()` (issue #1412)
+* Changed `JsonVariantConst::is<JsonArray/JsonObject>()` to return `false` (issue #1412)
+* Simplified `JsonVariant::as<T>()` to always return `T` (see below)
+* Updated folders list in `.mbedignore` (PR #1515 by @AGlass0fMilk)
+* Fixed member-call-on-null-pointer in `getMember()` when array is empty
+* `serializeMsgPack(doc, buffer, size)` doesn't add null-terminator anymore (issue #1545)
+* `serializeJson(doc, buffer, size)` adds null-terminator only if there is enough room
+* PlatformIO: set `build.libArchive` to `false` (PR #1550 by @askreet)
+
+> ### BREAKING CHANGES
+>
+> #### Support for `char` removed
+>
+> We cannot cast a `JsonVariant` to a `char` anymore, so the following will break:
+> ```c++
+> char age = doc["age"];  //  error: no matching function for call to 'variantAs(VariantData*&)'
+> ```
+> Instead, you must use another integral type, such as `int8_t`:
+> ```c++
+> int8_t age = doc["age"];  // OK
+> ```
+>
+> Similarly, we cannot assign from a `char` anymore, so the following will break:
+> ```c++
+> char age;
+> doc["age"] = age;  // error: no matching function for call to 'VariantRef::set(const char&)'
+> ```
+> Instead, you must use another integral type, such as `int8_t`:
+> ```c++
+> int8_t age;
+> doc["age"] = age;  // OK
+> ```
+> A deprecation warning with the message "Support for `char` is deprecated, use `int8_t` or `uint8_t` instead" was added to allow a smooth transition.
+>
+> #### `as<T>()` always returns `T`
+>
+> Previously, `JsonVariant::as<T>()` could return a type different from `T`.
+> The most common example is `as<char*>()` that returned a `const char*`.
+> While this feature simplified a few use cases, it was confusing and complicated the
+> implementation of custom converters.
+>
+> Starting from this version, `as<T>` doesn't try to auto-correct the return type and always return `T`,
+> which means that you cannot write this anymore:
+>
+> ```c++
+> Serial.println(doc["sensor"].as<char*>());  // error: invalid conversion from 'const char*' to 'char*' [-fpermissive]
+> ```
+> 
+> Instead, you must write:
+>
+> ```c++
+> Serial.println(doc["sensor"].as<const char*>());  // OK
+> ```
+>
+> A deprecation warning with the message "Replace `as<char*>()` with `as<const char*>()`" was added to allow a smooth transition.
+>
+> #### `DeserializationError::NotSupported` removed
+>
+> On a different topic, `DeserializationError::NotSupported` has been removed.
+> Instead of returning this error:
+>
+> * `deserializeJson()` leaves `\uXXXX` unchanged (only when `ARDUINOJSON_DECODE_UNICODE` is `0`)
+> * `deserializeMsgPack()` replaces unsupported values with `null`s
+>
+> #### Const-aware `is<T>()`
+>
+> Lastly, a very minor change concerns `JsonVariantConst::is<T>()`.
+> It used to return `true` for `JsonArray` and `JsonOject`, but now it returns `false`.
+> Instead, you must use `JsonArrayConst` and `JsonObjectConst`.
+
+v6.17.3 (2021-02-15)
+-------
+
+* Made `JsonDocument`'s destructor protected (issue #1480)
+* Added missing calls to `client.stop()` in `JsonHttpClient.ino` (issue #1485)
+* Fixed error `expected ')' before 'char'` when `isdigit()` is a macro (issue #1487)
+* Fixed error `definition of implicit copy constructor is deprecated` on Clang 10
+* PlatformIO: set framework compatibility to `*` (PR #1490 by @maxgerhardt)
+
+v6.17.2 (2020-11-14)
+-------
+
+* Fixed invalid conversion error in `operator|(JsonVariant, char*)` (issue #1432)
+* Changed the default value of `ARDUINOJSON_ENABLE_PROGMEM` (issue #1433).
+  It now checks that the `pgm_read_XXX` macros are defined before enabling `PROGMEM`.
+
+v6.17.1 (2020-11-07)
+-------
+
+* Fixed error `ambiguous overload for 'operator|'` (issue #1411)
+* Fixed `operator|(MemberProxy, JsonObject)` (issue #1415)
+* Allowed more than 32767 values in non-embedded mode (issue #1414)
+
+v6.17.0 (2020-10-19)
+-------
+
+* Added a build failure when nullptr is defined as a macro (issue #1355)
+* Added `JsonDocument::overflowed()` which tells if the memory pool was too small (issue #1358)
+* Added `DeserializationError::EmptyInput` which tells if the input was empty
+* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
+* Added `operator|(JsonVariantConst, JsonVariantConst)`
+* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella)
+* Moved float convertion tables to PROGMEM
+* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
+* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
+
+v6.16.1 (2020-08-04)
+-------
+
+* Fixed `deserializeJson()` that stopped reading after `{}` (issue #1335)
+
+v6.16.0 (2020-08-01)
+-------
+
+* Added comparisons (`>`, `>=`, `==`, `!=`, `<`, and `<=`) between `JsonVariant`s
+* Added string deduplication (issue #1303)
+* Added `JsonString::operator!=`
+* Added wildcard key (`*`) for filters (issue #1309)
+* Set `ARDUINOJSON_DECODE_UNICODE` to `1` by default
+* Fixed `copyArray()` not working with `String`, `ElementProxy`, and `MemberProxy`
+* Fixed error `getOrAddElement is not a member of ElementProxy` (issue #1311)
+* Fixed excessive stack usage when compiled with `-Og` (issues #1210 and #1314)
+* Fixed `Warning[Pa093]: implicit conversion from floating point to integer` on IAR compiler (PR #1328 by @stawiski)
+
+v6.15.2 (2020-05-15)
+-------
+
+* CMake: don't build tests when imported in another project
+* CMake: made project arch-independent
+* Visual Studio: fixed error C2766 with flag `/Zc:__cplusplus` (issue #1250)
+* Added support for `JsonDocument` to `copyArray()` (issue #1255)
+* Added support for `enum`s in `as<T>()` and `is<T>()`  (issue #1256)
+* Added `JsonVariant` as an input type for `deserializeXxx()`  
+  For example, you can do: `deserializeJson(doc2, doc1["payload"])`
+* Break the build if using 64-bit integers with ARDUINOJSON_USE_LONG_LONG==0
+
+v6.15.1 (2020-04-08)
+-------
+
+* Fixed "maybe-uninitialized" warning (issue #1217)
+* Fixed "statement is unreachable" warning on IAR (issue #1233)
+* Fixed "pointless integer comparison" warning on IAR (issue #1233)
+* Added CMake "install" target (issue #1209)
+* Disabled alignment on AVR (issue #1231)
+
+v6.15.0 (2020-03-22)
+-------
+
+* Added `DeserializationOption::Filter` (issue #959)
+* Added example `JsonFilterExample.ino`
+* Changed the array subscript operator to automatically add missing elements
+* Fixed "deprecated-copy" warning on GCC 9 (fixes #1184)
+* Fixed `MemberProxy::set(char[])` not duplicating the string (issue #1191)
+* Fixed enums serialized as booleans (issue #1197)
+* Fixed incorrect string comparison on some platforms (issue #1198)
+* Added move-constructor and move-assignment to `BasicJsonDocument`
+* Added `BasicJsonDocument::garbageCollect()` (issue #1195)
+* Added `StaticJsonDocument::garbageCollect()`
+* Changed copy-constructor of `BasicJsonDocument` to preserve the capacity of the source.
+* Removed copy-constructor of `JsonDocument` (issue #1189)
+
+> ### BREAKING CHANGES
+> 
+> #### Copy-constructor of `BasicJsonDocument`
+>
+> In previous versions, the copy constructor of `BasicJsonDocument` looked at the source's `memoryUsage()` to choose its capacity.
+> Now, the copy constructor of `BasicJsonDocument` uses the same capacity as the source.
+>
+> Example:
+>
+> ```c++
+> DynamicJsonDocument doc1(64);
+> doc1.set(String("example"));
+>
+> DynamicJsonDocument doc2 = doc1;
+> Serial.print(doc2.capacity());  // 8 with ArduinoJson 6.14
+>                                 // 64 with ArduinoJson 6.15
+> ```
+>
+> I made this change to get consistent results between copy-constructor and move-constructor, and whether RVO applies or not.
+>
+> If you use the copy-constructor to optimize your documents, you can use `garbageCollect()` or `shrinkToFit()` instead.
+>
+> #### Copy-constructor of `JsonDocument`
+>
+> In previous versions, it was possible to create a function that take a `JsonDocument` by value.
+>
+> ```c++
+> void myFunction(JsonDocument doc) {}
+> ```
+>
+> This function gives the wrong clues because it doesn't receive a copy of the `JsonDocument`, only a sliced version.
+> It worked because the copy constructor copied the internal pointers, but it was an accident.
+>
+> From now, if you need to pass a `JsonDocument` to a function, you must use a reference:
+>
+> ```c++
+> void myFunction(JsonDocument& doc) {}
+> ```
+
+v6.14.1 (2020-01-27)
+-------
+
+* Fixed regression in UTF16 decoding (issue #1173)
+* Fixed `containsKey()` on `JsonVariantConst`
+* Added `getElement()` and `getMember()` to `JsonVariantConst`
+
+v6.14.0 (2020-01-16)
+-------
+
+* Added `BasicJsonDocument::shrinkToFit()`
+* Added support of `uint8_t` for `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` (issue #1142)
+* Added `ARDUINOJSON_ENABLE_COMMENTS` to enable support for comments (defaults to 0)
+* Auto enable support for `std::string` and `std::stream` on modern compilers (issue #1156)
+  (No need to define `ARDUINOJSON_ENABLE_STD_STRING` and `ARDUINOJSON_ENABLE_STD_STREAM` anymore)
+* Improved decoding of UTF-16 surrogate pairs (PR #1157 by @kaysievers)
+  (ArduinoJson now produces standard UTF-8 instead of CESU-8)
+* Added `measureJson`, `measureJsonPretty`, and `measureMsgPack` to `keywords.txt`
+  (This file is used for syntax highlighting in the Arduino IDE) 
+* Fixed `variant.is<nullptr_t>()`
+* Fixed value returned by `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
+* Improved speed of `serializeJson()`, `serializeJsonPretty()`, and `serializeMsgPack()` when writing to a `String`
+
+> ### BREAKING CHANGES
+> 
+> #### Comments
+> 
+> Support for comments in input is now optional and disabled by default.
+>
+> If you need support for comments, you must defined `ARDUINOJSON_ENABLE_COMMENTS` to `1`; otherwise, you'll receive `InvalidInput` errors.
+>
+> ```c++
+> #define ARDUINOJSON_ENABLE_COMMENTS 1
+> #include <ArduinoJson.h>
+> ```
+
+v6.13.0 (2019-11-01)
+-------
+
+* Added support for custom writer/reader classes (issue #1088)
+* Added conversion from `JsonArray` and `JsonObject` to `bool`, to be consistent with `JsonVariant`
+* Fixed `deserializeJson()` when input contains duplicate keys (issue #1095)
+* Improved `deserializeMsgPack()` speed by reading several bytes at once
+* Added detection of Atmel AVR8/GNU C Compiler (issue #1112)
+* Fixed deserializer that stopped reading at the first `0xFF` (PR #1118 by @mikee47)
+* Fixed dangling reference in copies of `MemberProxy` and `ElementProxy` (issue #1120)
+
+v6.12.0 (2019-09-05)
+-------
+
+* Use absolute instead of relative includes (issue #1072)
+* Changed `JsonVariant::as<bool>()` to return `true` for any non-null value (issue #1005)
+* Moved ancillary files to `extras/` (issue #1011)
+
+v6.11.5 (2019-08-23)
+-------
+
+* Added fallback implementations of `strlen_P()`, `strncmp_P()`, `strcmp_P()`, and `memcpy_P()` (issue #1073)
+
+v6.11.4 (2019-08-12)
+-------
+
+* Added `measureJson()` to the `ArduinoJson` namespace (PR #1069 by @nomis)
+* Added support for `basic_string<char, traits, allocator>` (issue #1045)
+* Fixed example `JsonConfigFile.ino` for ESP8266
+* Include `Arduino.h` if `ARDUINO` is defined (PR #1071 by @nomis)
+
+v6.11.3 (2019-07-22)
+-------
+
+* Added operators `==` and `!=` for `JsonDocument`, `ElementProxy`, and `MemberProxy`
+* Fixed comparison of `JsonVariant` when one contains a linked string and the other contains an owned string (issue #1051)
+
+v6.11.2 (2019-07-08)
+-------
+
+* Fixed assignment of `JsonDocument` to `JsonVariant` (issue #1023)
+* Fix invalid conversion error on Particle Argon (issue #1035)
+
+v6.11.1 (2019-06-21)
+-------
+
+* Fixed `serialized()` not working with Flash strings (issue #1030)
+
+v6.11.0 (2019-05-26)
+-------
+
+* Fixed `deserializeJson()` silently accepting a `Stream*` (issue #978)
+* Fixed invalid result from `operator|` (issue #981)
+* Made `deserializeJson()` more picky about trailing characters (issue #980)
+* Added `ARDUINOJSON_ENABLE_NAN` (default=0) to enable NaN in JSON (issue #973)
+* Added `ARDUINOJSON_ENABLE_INFINITY` (default=0) to enable Infinity in JSON
+* Removed implicit conversion in comparison operators (issue #998)
+* Added lexicographical comparison for `JsonVariant`
+* Added support for `nullptr` (issue #998)
+
+> ### BREAKING CHANGES
+> 
+> #### NaN and Infinity
+> 
+> The JSON specification allows neither NaN not Infinity, but previous
+> versions of ArduinoJson supported it. Now, ArduinoJson behaves like most
+> other libraries: a NaN or and Infinity in the `JsonDocument`, becomes
+> a `null` in the output JSON. Also, `deserializeJson()` returns
+> `InvalidInput` if the JSON document contains NaN or Infinity.
+> 
+> This version still supports NaN and Infinity in JSON documents, but
+> it's disabled by default to be compatible with other JSON parsers.
+> If you need the old behavior back, define `ARDUINOJSON_ENABLE_NAN` and
+> `ARDUINOJSON_ENABLE_INFINITY` to `1`;:
+> 
+> ```c++
+> #define ARDUINOJSON_ENABLE_NAN 1
+> #define ARDUINOJSON_ENABLE_INFINITY 1
+> #include <ArduinoJson.h>
+> ```
+> 
+> #### The "or" operator
+> 
+> This version slightly changes the behavior of the | operator when the 
+> variant contains a float and the user requests an integer.
+>
+> Older versions returned the floating point value truncated.
+> Now, it returns the default value.
+> 
+> ```c++
+> // suppose variant contains 1.2
+> int value = variant | 3;
+> 
+> // old behavior:
+> value == 1
+> 
+> // new behavior
+> value == 3
+> ```
+> 
+> If you need the old behavior, you must add `if (variant.is<float>())`.
+
+v6.10.1 (2019-04-23)
+-------
+
+* Fixed error "attributes are not allowed on a function-definition"
+* Fixed `deserializeJson()` not being picky enough (issue #969)
+* Fixed error "no matching function for call to write(uint8_t)" (issue #972)
+
+v6.10.0 (2019-03-22)
+-------
+
+* Fixed an integer overflow in the JSON deserializer
+* Added overflow handling in `JsonVariant::as<T>()` and `JsonVariant::is<T>()`.
+   - `as<T>()` returns `0` if the integer `T` overflows
+   - `is<T>()` returns `false` if the integer `T` overflows
+* Added `BasicJsonDocument` to support custom allocator (issue #876)
+* Added `JsonDocument::containsKey()` (issue #938)
+* Added `JsonVariant::containsKey()`
+
+v6.9.1 (2019-03-01)
+------
+
+* Fixed warning "unused variable" with GCC 4.4 (issue #912)
+* Fixed warning "cast  increases required alignment" (issue #914)
+* Fixed warning "conversion may alter value" (issue #914)
+* Fixed naming conflict with "CAPACITY" (issue #839)
+* Muted warning "will change in GCC 7.1" (issue #914)
+* Added a clear error message for `StaticJsonBuffer` and `DynamicJsonBuffer`
+* Marked ArduinoJson.h  as a "system header"
+
+v6.9.0 (2019-02-26)
+------
+
+* Decode escaped Unicode characters like \u00DE (issue #304, PR #791)
+  Many thanks to Daniel Schulte (aka @trilader) who implemented this feature.
+* Added option ARDUINOJSON_DECODE_UNICODE to enable it
+* Converted `JsonArray::copyFrom()/copyTo()` to free functions `copyArray()`
+* Renamed `JsonArray::copyFrom()` and `JsonObject::copyFrom()` to `set()`
+* Renamed `JsonArray::get()` to `getElement()`
+* Renamed `JsonArray::add()` (without arg) to `addElement()`
+* Renamed `JsonObject::get()` to `getMember()`
+* Renamed `JsonObject::getOrCreate()` to `getOrAddMember()`
+* Fixed `JsonVariant::isNull()` not returning `true` after `set((char*)0)`
+* Fixed segfault after `variant.set(serialized((char*)0))`
+* Detect `IncompleteInput` in `false`, `true`, and `null`
+* Added `JsonDocument::size()`
+* Added `JsonDocument::remove()`
+* Added `JsonVariant::clear()`
+* Added `JsonVariant::remove()`
+
+v6.8.0-beta (2019-01-30)
+-----------
+
+* Import functions in the ArduinoJson namespace to get clearer errors
+* Improved syntax highlighting in Arduino IDE
+* Removed default capacity of `DynamicJsonDocument`
+* `JsonArray::copyFrom()` accepts `JsonArrayConst`
+* `JsonVariant::set()` accepts `JsonArrayConst` and `JsonObjectConst`
+* `JsonDocument` was missing in the ArduinoJson namespace
+* Added `memoryUsage()` to `JsonArray`, `JsonObject`, and `JsonVariant`
+* Added `nesting()` to `JsonArray`, `JsonDocument`, `JsonObject`, and `JsonVariant`
+* Replaced `JsonDocument::nestingLimit` with an additional parameter
+  to `deserializeJson()` and `deserializeMsgPack()`
+* Fixed uninitialized variant in `JsonDocument`
+* Fixed `StaticJsonDocument` copy constructor and copy assignment
+* The copy constructor of `DynamicJsonDocument` chooses the capacity according to the memory usage of the source, not from the capacity of the source.
+* Added the ability to create/assign a `StaticJsonDocument`/`DynamicJsonDocument` from a `JsonArray`/`JsonObject`/`JsonVariant`
+* Added `JsonDocument::isNull()`
+* Added `JsonDocument::operator[]`
+* Added `ARDUINOJSON_TAB` to configure the indentation character
+* Reduced the size of the pretty JSON serializer
+* Added `add()`, `createNestedArray()` and `createNestedObject()` to `JsonVariant`
+* `JsonVariant` automatically promotes to `JsonObject` or `JsonArray` on write.
+  Calling `JsonVariant::to<T>()` is not required anymore.
+* `JsonDocument` now support the same operations as `JsonVariant`.
+  Calling `JsonDocument::as<T>()` is not required anymore.
+* Fixed example `JsonHttpClient.ino`
+* User can now use a `JsonString` as a key or a value
+
+> ### BREAKING CHANGES
+> 
+> #### `DynamicJsonDocument`'s constructor
+> 
+> The parameter to the constructor of `DynamicJsonDocument` is now mandatory
+>
+> Old code:
+>
+> ```c++
+> DynamicJsonDocument doc;
+> ```
+>
+> New code:
+>
+> ```c++
+> DynamicJsonDocument doc(1024);
+> ```
+> 
+> #### Nesting limit
+> 
+> `JsonDocument::nestingLimit` was replaced with a new parameter to `deserializeJson()` and `deserializeMsgPack()`.
+> 
+> Old code:
+> 
+> ```c++
+> doc.nestingLimit = 15;
+> deserializeJson(doc, input);
+> ```
+> 
+> New code: 
+> 
+> ```c++
+> deserializeJson(doc, input, DeserializationOption::NestingLimit(15));
+> ```
+
+v6.7.0-beta (2018-12-07)
+-----------
+
+* Removed the automatic expansion of `DynamicJsonDocument`, it now has a fixed capacity.
+* Restored the monotonic allocator because the code was getting too big
+* Reduced the memory usage
+* Reduced the code size
+* Renamed `JsonKey` to `JsonString`
+* Removed spurious files in the Particle library
+
+v6.6.0-beta (2018-11-13)
+-----------
+
+* Removed `JsonArray::is<T>(i)` and `JsonArray::set(i,v)`
+* Removed `JsonObject::is<T>(k)` and `JsonObject::set(k,v)`
+* Replaced `T JsonArray::get<T>(i)` with `JsonVariant JsonArray::get(i)`
+* Replaced `T JsonObject::get<T>(k)` with `JsonVariant JsonObject::get(k)`
+* Added `JSON_STRING_SIZE()`
+* ~~Replacing or removing a value now releases the memory~~
+* Added `DeserializationError::code()` to be used in switch statements (issue #846)
+
+v6.5.0-beta (2018-10-13)
+-----------
+
+* Added implicit conversion from `JsonArray` and `JsonObject` to `JsonVariant`
+* Allow mixed configuration in compilation units (issue #809)
+* Fixed object keys not being duplicated
+* `JsonPair::key()` now returns a `JsonKey`
+* Increased the default capacity of `DynamicJsonDocument`
+* Fixed `JsonVariant::is<String>()` (closes #763)
+* Added `JsonArrayConst`, `JsonObjectConst`, and `JsonVariantConst`
+* Added copy-constructor and copy-assignment-operator for `JsonDocument` (issue #827)
+
+v6.4.0-beta (2018-09-11)
+-----------
+
+* Copy `JsonArray` and `JsonObject`, instead of storing pointers (issue #780)
+* Added `JsonVariant::to<JsonArray>()` and `JsonVariant::to<JsonObject>()`
+
+v6.3.0-beta (2018-08-31)
+-----------
+
+* Implemented reference semantics for `JsonVariant`
+* Replaced `JsonPair`'s `key` and `value` with `key()` and `value()`
+* Fixed `serializeJson(obj[key], dst)` (issue #794)
+
+> ### BREAKING CHANGES
+>
+> #### JsonVariant
+> 
+> `JsonVariant` now has a semantic similar to `JsonObject` and `JsonArray`.
+> It's a reference to a value stored in the `JsonDocument`.
+> As a consequence, a `JsonVariant` cannot be used as a standalone variable anymore.
+>
+> Old code:
+>
+> ```c++
+> JsonVariant myValue = 42;
+> ```
+>
+> New code:
+>
+> ```c++
+> DynamicJsonDocument doc;
+> JsonVariant myValue = doc.to<JsonVariant>();
+> myValue.set(42);
+> ```
+>
+> #### JsonPair
+>
+> Old code:
+>
+> ```c++
+> for(JsonPair p : myObject) {
+>   Serial.println(p.key);
+>   Serial.println(p.value.as<int>());
+> }
+> ```
+>
+> New code:
+>
+> ```c++
+> for(JsonPair p : myObject) {
+>   Serial.println(p.key());
+>   Serial.println(p.value().as<int>());
+> }
+> ```
+>
+> CAUTION: the key is now read only!
+
+v6.2.3-beta (2018-07-19)
+-----------
+
+* Fixed exception when using Flash strings as object keys (issue #784)
+
+v6.2.2-beta (2018-07-18)
+-----------
+
+* Fixed `invalid application of 'sizeof' to incomplete type '__FlashStringHelper'` (issue #783)
+* Fixed `char[]` not duplicated when passed to `JsonVariant::operator[]`
+
+v6.2.1-beta (2018-07-17)
+-----------
+
+* Fixed `JsonObject` not inserting keys of type `String` (issue #782)
+
+v6.2.0-beta (2018-07-12)
+-----------
+
+* Disabled lazy number deserialization (issue #772)
+* Fixed `JsonVariant::is<int>()` that returned true for empty strings
+* Improved float serialization when `-fsingle-precision-constant` is used
+* Renamed function `RawJson()` to `serialized()`
+* `serializeMsgPack()` now supports values marked with `serialized()`
+
+> ### BREAKING CHANGES
+>
+> #### Non quoted strings
+>
+> Non quoted strings are now forbidden in values, but they are still allowed in keys.
+> For example, `{key:"value"}` is accepted, but `{key:value}` is not.
+>
+> #### Preformatted values
+>
+> Old code:
+>
+> ```c++
+> object["values"] = RawJson("[1,2,3,4]");
+> ```
+> 
+> New code:
+> 
+> ```c++
+> object["values"] = serialized("[1,2,3,4]");
+> ```
+
+v6.1.0-beta (2018-07-02)
+-----------
+
+* Return `JsonArray` and `JsonObject` by value instead of reference (issue #309)
+* Replaced `success()` with `isNull()`
+
+> ### BREAKING CHANGES
+> 
+> Old code:
+>
+> ```c++
+> JsonObject& obj = doc.to<JsonObject>();
+> JsonArray& arr = obj.createNestedArray("key");
+> if (!arr.success()) {
+>   Serial.println("Not enough memory");
+>   return;
+> }
+> ```
+> 
+> New code:
+> 
+> ```c++
+> JsonObject obj = doc.to<JsonObject>();
+> JsonArray arr = obj.createNestedArray("key");
+> if (arr.isNull()) {
+>   Serial.println("Not enough memory");
+>   return;
+> }
+> ```
+
+v6.0.1-beta (2018-06-11)
+-----------
+
+* Fixed conflicts with `isnan()` and `isinf()` macros (issue #752)
+
+v6.0.0-beta (2018-06-07)
+-----------
+
+* Added `DynamicJsonDocument` and `StaticJsonDocument`
+* Added `deserializeJson()`
+* Added `serializeJson()` and `serializeJsonPretty()`
+* Added `measureJson()` and `measureJsonPretty()`
+* Added `serializeMsgPack()`, `deserializeMsgPack()` and `measureMsgPack()` (issue #358)
+* Added example `MsgPackParser.ino` (issue #358)
+* Added support for non zero-terminated strings (issue #704)
+* Removed `JsonBuffer::parseArray()`, `parseObject()` and `parse()`
+* Removed `JsonBuffer::createArray()` and `createObject()`
+* Removed `printTo()` and `prettyPrintTo()`
+* Removed `measureLength()` and `measurePrettyLength()`
+* Removed all deprecated features
+
+> ### BREAKING CHANGES
+> 
+> #### Deserialization
+> 
+> Old code:
+> 
+> ```c++
+> DynamicJsonBuffer jb;
+> JsonObject& obj = jb.parseObject(json);
+> if (obj.success()) {
+> 
+> }
+> ```
+> 
+> New code:
+> 
+> ```c++
+> DynamicJsonDocument doc;
+> DeserializationError error = deserializeJson(doc, json);
+> if (error) {
+> 
+> }
+> JsonObject& obj = doc.as<JsonObject>();
+> ```
+> 
+> #### Serialization
+> 
+> Old code:
+> 
+> ```c++
+> DynamicJsonBuffer jb;
+> JsonObject& obj = jb.createObject();
+> obj["key"] = "value";
+> obj.printTo(Serial);
+> ```
+> 
+> New code:
+> 
+> ```c++
+> DynamicJsonDocument obj;
+> JsonObject& obj = doc.to<JsonObject>();
+> obj["key"] = "value";
+> serializeJson(doc, Serial);
+> ```

+ 25 - 0
lib/ArduinoJson-6.20.1/CMakeLists.txt

@@ -0,0 +1,25 @@
+# ArduinoJson - https://arduinojson.org
+# Copyright © 2014-2022, Benoit BLANCHON
+# MIT License
+
+cmake_minimum_required(VERSION 3.15)
+
+if(ESP_PLATFORM)
+   # Build ArduinoJson as an ESP-IDF component
+   idf_component_register(INCLUDE_DIRS src)
+   return()
+endif()
+
+project(ArduinoJson VERSION 6.20.1)
+
+if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
+    include(CTest)
+endif()
+
+add_subdirectory(src)
+
+if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING)
+	include(extras/CompileOptions.cmake)
+	add_subdirectory(extras/tests)
+	add_subdirectory(extras/fuzzing)
+endif()

+ 10 - 0
lib/ArduinoJson-6.20.1/CONTRIBUTING.md

@@ -0,0 +1,10 @@
+# Contribution to ArduinoJson
+
+First, thank you for taking the time to contribute to this project.
+
+You can submit changes via GitHub Pull Requests.
+
+Please:
+
+1. Update the test suite for any change of behavior
+2. Use clang-format in "file" mode to format the code

+ 10 - 0
lib/ArduinoJson-6.20.1/LICENSE.txt

@@ -0,0 +1,10 @@
+The MIT License (MIT)
+---------------------
+
+Copyright © 2014-2022, Benoit BLANCHON
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 160 - 0
lib/ArduinoJson-6.20.1/README.md

@@ -0,0 +1,160 @@
+<p align="center">
+  <a href="https://arduinojson.org/"><img alt="ArduinoJson" src="https://arduinojson.org/images/logo.svg" width="200" /></a>
+</p>
+
+---
+
+[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/bblanchon/ArduinoJson/ci.yml?branch=6.x&logo=github)](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A6.x)
+[![Continuous Integration](https://ci.appveyor.com/api/projects/status/m7s53wav1l0abssg/branch/6.x?svg=true)](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
+[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/arduinojson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
+[![Coveralls branch](https://img.shields.io/coveralls/github/bblanchon/ArduinoJson/6.x?logo=coveralls)](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)  
+[![Arduino Library Manager](https://img.shields.io/static/v1?label=Arduino&message=v6.20.1&logo=arduino&logoColor=white&color=blue)](https://www.ardu-badge.com/ArduinoJson/6.20.1)
+[![PlatformIO Registry](https://badges.registry.platformio.org/packages/bblanchon/library/ArduinoJson.svg?version=6.20.1)](https://registry.platformio.org/packages/libraries/bblanchon/ArduinoJson?version=6.20.1) 
+[![ESP IDF](https://img.shields.io/static/v1?label=ESP+IDF&message=v6.20.1&logo=cpu&logoColor=white&color=blue)](https://components.espressif.com/components/bblanchon/arduinojson)  
+[![GitHub stars](https://img.shields.io/github/stars/bblanchon/ArduinoJson?style=flat&logo=github&color=orange)](https://github.com/bblanchon/ArduinoJson/stargazers)
+[![GitHub Sponsors](https://img.shields.io/github/sponsors/bblanchon?logo=github&color=orange)](https://github.com/sponsors/bblanchon)
+
+ArduinoJson is a C++ JSON library for Arduino and IoT (Internet Of Things).
+
+## Features
+
+* [JSON deserialization](https://arduinojson.org/v6/api/json/deserializejson/)
+    * [Optionally decodes UTF-16 escape sequences to UTF-8](https://arduinojson.org/v6/api/config/decode_unicode/)
+    * [Optionally stores links to the input buffer (zero-copy)](https://arduinojson.org/v6/api/json/deserializejson/)
+    * [Optionally supports comments in the input](https://arduinojson.org/v6/api/config/enable_comments/)
+    * [Optionally filters the input to keep only desired values](https://arduinojson.org/v6/api/json/deserializejson/#filtering)
+    * Supports single quotes as a string delimiter
+    * Compatible with [NDJSON](http://ndjson.org/) and [JSON Lines](https://jsonlines.org/)
+* [JSON serialization](https://arduinojson.org/v6/api/json/serializejson/)
+    * [Can write to a buffer or a stream](https://arduinojson.org/v6/api/json/serializejson/)
+    * [Optionally indents the document (prettified JSON)](https://arduinojson.org/v6/api/json/serializejsonpretty/)
+* [MessagePack serialization](https://arduinojson.org/v6/api/msgpack/serializemsgpack/)
+* [MessagePack deserialization](https://arduinojson.org/v6/api/msgpack/deserializemsgpack/)
+* Efficient
+    * [Twice smaller than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
+    * [Almost 10% faster than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
+    * [Consumes roughly 10% less RAM than the "official" Arduino_JSON library](https://arduinojson.org/2019/11/19/arduinojson-vs-arduino_json/)
+    * [Fixed memory allocation, no heap fragmentation](https://arduinojson.org/v6/api/jsondocument/)
+    * [Optionally works without heap memory (zero malloc)](https://arduinojson.org/v6/api/staticjsondocument/)
+    * [Deduplicates strings](https://arduinojson.org/news/2020/08/01/version-6-16-0/)
+* Versatile
+    * Supports [custom allocators (to use external RAM chip, for example)](https://arduinojson.org/v6/how-to/use-external-ram-on-esp32/)
+    * Supports [`String`](https://arduinojson.org/v6/api/config/enable_arduino_string/), [`std::string`](https://arduinojson.org/v6/api/config/enable_std_string/), and [`std::string_view`](https://arduinojson.org/v6/api/config/enable_string_view/)
+    * Supports [`Stream`](https://arduinojson.org/v6/api/config/enable_arduino_stream/) and [`std::istream`/`std::ostream`](https://arduinojson.org/v6/api/config/enable_std_stream/)
+    * Supports [Flash strings](https://arduinojson.org/v6/api/config/enable_progmem/)
+    * Supports [custom readers](https://arduinojson.org/v6/api/json/deserializejson/#custom-reader) and [custom writers](https://arduinojson.org/v6/api/json/serializejson/#custom-writer)
+    * Supports [custom converters](https://arduinojson.org/news/2021/05/04/version-6-18-0/)
+* Portable
+    * Usable on any C++ project (not limited to Arduino)
+    * Compatible with C++98, C++11, C++14 and C++17
+    * Zero warnings with `-Wall -Wextra -pedantic` and `/W4`
+    * [Header-only library](https://en.wikipedia.org/wiki/Header-only)
+    * Works with virtually any board
+        * Arduino boards: [Uno](https://amzn.to/38aL2ik), [Due](https://amzn.to/36YkWi2), [Micro](https://amzn.to/35WkdwG), [Nano](https://amzn.to/2QTvwRX), [Mega](https://amzn.to/36XWhuf), [Yun](https://amzn.to/30odURc), [Leonardo](https://amzn.to/36XWjlR)...
+        * Espressif chips: [ESP8266](https://amzn.to/36YluV8), [ESP32](https://amzn.to/2G4pRCB)
+        * Lolin (WeMos) boards: [D1 mini](https://amzn.to/2QUpz7q), [D1 Mini Pro](https://amzn.to/36UsGSs)...
+        * Teensy boards: [4.0](https://amzn.to/30ljXGq), [3.2](https://amzn.to/2FT0EuC), [2.0](https://amzn.to/2QXUMXj)
+        * Particle boards: [Argon](https://amzn.to/2FQHa9X), [Boron](https://amzn.to/36WgLUd), [Electron](https://amzn.to/30vEc4k), [Photon](https://amzn.to/387F9Cd)...
+        * Texas Instruments boards: [MSP430](https://amzn.to/30nJWgg)...
+        * Soft cores: [Nios II](https://en.wikipedia.org/wiki/Nios_II)...
+    * Tested on all major development environments
+        * [Arduino IDE](https://www.arduino.cc/en/Main/Software)
+        * [Atmel Studio](http://www.atmel.com/microsite/atmel-studio/)
+        * [Atollic TrueSTUDIO](https://atollic.com/truestudio/)
+        * [Energia](http://energia.nu/)
+        * [IAR Embedded Workbench](https://www.iar.com/iar-embedded-workbench/)
+        * [Keil uVision](http://www.keil.com/)
+        * [MPLAB X IDE](http://www.microchip.com/mplab/mplab-x-ide)
+        * [Particle](https://www.particle.io/)
+        * [PlatformIO](http://platformio.org/)
+        * [Sloeber plugin for Eclipse](https://eclipse.baeyens.it/)
+        * [Visual Micro](http://www.visualmicro.com/)
+        * [Visual Studio](https://www.visualstudio.com/)
+    * [Even works with online compilers like wandbox.org](https://wandbox.org/permlink/RlZSKy17DjJ6HcdN)
+    * [CMake friendly](https://arduinojson.org/v6/how-to/use-arduinojson-with-cmake/)
+* Well designed
+    * [Elegant API](http://arduinojson.org/v6/example/)
+    * [Thread-safe](https://en.wikipedia.org/wiki/Thread_safety)
+    * Self-contained (no external dependency)
+    * `const` friendly
+    * [`for` friendly](https://arduinojson.org/v6/api/jsonobject/begin_end/)
+    * [TMP friendly](https://en.wikipedia.org/wiki/Template_metaprogramming)
+    * Handles [integer overflows](https://arduinojson.org/v6/api/jsonvariant/as/#integer-overflows)
+* Well tested
+    * [Unit test coverage close to 100%](https://coveralls.io/github/bblanchon/ArduinoJson?branch=6.x)
+    * Continuously tested on
+        * [Visual Studio 2010, 2012, 2013, 2015, 2017, 2019, 2022](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/6.x)
+        * [GCC 4.4, 4.6, 4.7, 4.8, 4.9, 5, 6, 7, 8, 9, 10, 11](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
+        * [Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4.0, 5.0, 6.0, 7, 8, 9, 10](https://github.com/bblanchon/ArduinoJson/actions?query=workflow%3A%22Continuous+Integration%22)
+    * [Continuously fuzzed with Google OSS Fuzz](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:arduinojson)
+    * Passes all default checks of [clang-tidy](https://releases.llvm.org/10.0.0/tools/clang/tools/extra/docs/clang-tidy/)
+* Well documented
+    * [Tutorials](https://arduinojson.org/v6/doc/deserialization/)
+    * [Examples](https://arduinojson.org/v6/example/)
+    * [How-tos](https://arduinojson.org/v6/example/)
+    * [FAQ](https://arduinojson.org/v6/faq/)
+    * [Troubleshooter](https://arduinojson.org/v6/troubleshooter/)
+    * [Book](https://arduinojson.org/book/)
+    * [Changelog](CHANGELOG.md)
+* Vibrant user community
+    * Most popular of all Arduino libraries on [GitHub](https://github.com/search?o=desc&q=arduino+library&s=stars&type=Repositories)
+    * [Used in hundreds of projects](https://www.hackster.io/search?i=projects&q=arduinojson)
+    * [Responsive support](https://github.com/bblanchon/ArduinoJson/issues?q=is%3Aissue+is%3Aclosed)
+
+## Quickstart
+
+### Deserialization
+
+Here is a program that parses a JSON document with ArduinoJson.
+
+```c++
+char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+
+DynamicJsonDocument doc(1024);
+deserializeJson(doc, json);
+
+const char* sensor = doc["sensor"];
+long time          = doc["time"];
+double latitude    = doc["data"][0];
+double longitude   = doc["data"][1];
+```
+
+See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/deserialization/)
+
+### Serialization
+
+Here is a program that generates a JSON document with ArduinoJson:
+
+```c++
+DynamicJsonDocument doc(1024);
+
+doc["sensor"] = "gps";
+doc["time"]   = 1351824120;
+doc["data"][0] = 48.756080;
+doc["data"][1] = 2.302038;
+
+serializeJson(doc, Serial);
+// This prints:
+// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
+```
+
+See the [tutorial on arduinojson.org](https://arduinojson.org/v6/doc/serialization/)
+
+## Sponsors
+
+ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve it!
+
+<p>
+  <a href="https://www.programmingelectronics.com/" rel="sponsored">
+    <img src="https://arduinojson.org/images/2021/10/programmingeleactronicsacademy.png" alt="Programming Electronics Academy" width="200">
+  </a>
+</p>
+<p>
+  <a href="https://github.com/1technophile" rel="sponsored">
+    <img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
+  </a>
+</p>
+
+If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
+
+If you are an individual user and want to support the development (or give a sign of appreciation), consider purchasing the book [Mastering ArduinoJson](https://arduinojson.org/book/)&nbsp;❤, or simply [cast a star](https://github.com/bblanchon/ArduinoJson/stargazers)&nbsp;⭐.

+ 27 - 0
lib/ArduinoJson-6.20.1/SUPPORT.md

@@ -0,0 +1,27 @@
+# ArduinoJson Support
+
+First off, thank you very much for using ArduinoJson.
+
+We'll be very happy to help you, but first please read the following.
+
+## Before asking for help
+
+1. Read the [FAQ](https://arduinojson.org/faq/?utm_source=github&utm_medium=support)
+2. Search in the [API Reference](https://arduinojson.org/api/?utm_source=github&utm_medium=support)
+
+If you did not find the answer, please create a [new issue on GitHub](https://github.com/bblanchon/ArduinoJson/issues/new).
+
+It is OK to add a comment to a currently opened issue, but please avoid adding comments to a closed issue.
+
+## Before hitting the Submit button
+
+Please provide all the relevant information:
+
+* Good title
+* Short description of the problem
+* Target platform
+* Compiler model and version
+* [MVCE](https://stackoverflow.com/help/mcve)
+* Compiler output
+
+Good questions get fast answers!

+ 37 - 0
lib/ArduinoJson-6.20.1/appveyor.yml

@@ -0,0 +1,37 @@
+version: 6.20.1.{build}
+environment:
+  matrix:
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
+      CMAKE_GENERATOR: Visual Studio 17 2022
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      CMAKE_GENERATOR: Visual Studio 16 2019
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      CMAKE_GENERATOR: Visual Studio 15 2017
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      CMAKE_GENERATOR: Visual Studio 14 2015
+    - CMAKE_GENERATOR: Visual Studio 12 2013
+    - CMAKE_GENERATOR: Visual Studio 11 2012
+    - CMAKE_GENERATOR: Visual Studio 10 2010
+    - CMAKE_GENERATOR: Ninja
+      MINGW: MinGW # MinGW 32-bit 5.3.0
+    - CMAKE_GENERATOR: Ninja
+      MINGW32: i686-5.3.0-posix-dwarf-rt_v4-rev0 # MinGW-w64 5.3.0
+    - CMAKE_GENERATOR: Ninja
+      MINGW32: i686-6.3.0-posix-dwarf-rt_v5-rev1 # MinGW-w64 6.3.0 i686
+    - CMAKE_GENERATOR: Ninja
+      MINGW64: x86_64-6.3.0-posix-seh-rt_v5-rev1 # MinGW-w64 6.3.0 x86_64
+    - CMAKE_GENERATOR: Ninja
+      MINGW64: x86_64-7.3.0-posix-seh-rt_v5-rev0 # MinGW-w64 7.3.0 x86_64
+    - CMAKE_GENERATOR: Ninja
+      MINGW64: x86_64-8.1.0-posix-seh-rt_v6-rev0 # MinGW-w64 8.1.0 x86_64
+configuration: Debug
+before_build:
+  - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% # Workaround for CMake not wanting sh.exe on PATH for MinGW
+  - if defined MINGW set PATH=C:\%MINGW%\bin;%PATH%
+  - if defined MINGW32 set PATH=C:\mingw-w64\%MINGW32%\mingw32\bin;%PATH%
+  - if defined MINGW64 set PATH=C:\mingw-w64\%MINGW64%\mingw64\bin;%PATH%
+  - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%CMAKE_GENERATOR%" .
+build_script:
+  - cmake --build . --config %CONFIGURATION%
+test_script:
+  - ctest -C %CONFIGURATION% --output-on-failure .

+ 1 - 0
lib/ArduinoJson-6.20.1/component.mk

@@ -0,0 +1 @@
+COMPONENT_ADD_INCLUDEDIRS := src

+ 160 - 0
lib/ArduinoJson-6.20.1/examples/JsonConfigFile/JsonConfigFile.ino

@@ -0,0 +1,160 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to store your project configuration in a file.
+// It uses the SD library but can be easily modified for any other file-system.
+//
+// The file contains a JSON document with the following content:
+// {
+//   "hostname": "examples.com",
+//   "port": 2731
+// }
+//
+// To run this program, you need an SD card connected to the SPI bus as follows:
+// * MOSI <-> pin 11
+// * MISO <-> pin 12
+// * CLK  <-> pin 13
+// * CS   <-> pin 4
+//
+// https://arduinojson.org/v6/example/config/
+
+#include <ArduinoJson.h>
+#include <SD.h>
+#include <SPI.h>
+
+// Our configuration structure.
+//
+// Never use a JsonDocument to store the configuration!
+// A JsonDocument is *not* a permanent storage; it's only a temporary storage
+// used during the serialization phase. See:
+// https://arduinojson.org/v6/faq/why-must-i-create-a-separate-config-object/
+struct Config {
+  char hostname[64];
+  int port;
+};
+
+const char *filename = "/config.txt";  // <- SD library uses 8.3 filenames
+Config config;                         // <- global configuration object
+
+// Loads the configuration from a file
+void loadConfiguration(const char *filename, Config &config) {
+  // Open file for reading
+  File file = SD.open(filename);
+
+  // Allocate a temporary JsonDocument
+  // Don't forget to change the capacity to match your requirements.
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<512> doc;
+
+  // Deserialize the JSON document
+  DeserializationError error = deserializeJson(doc, file);
+  if (error)
+    Serial.println(F("Failed to read file, using default configuration"));
+
+  // Copy values from the JsonDocument to the Config
+  config.port = doc["port"] | 2731;
+  strlcpy(config.hostname,                  // <- destination
+          doc["hostname"] | "example.com",  // <- source
+          sizeof(config.hostname));         // <- destination's capacity
+
+  // Close the file (Curiously, File's destructor doesn't close the file)
+  file.close();
+}
+
+// Saves the configuration to a file
+void saveConfiguration(const char *filename, const Config &config) {
+  // Delete existing file, otherwise the configuration is appended to the file
+  SD.remove(filename);
+
+  // Open file for writing
+  File file = SD.open(filename, FILE_WRITE);
+  if (!file) {
+    Serial.println(F("Failed to create file"));
+    return;
+  }
+
+  // Allocate a temporary JsonDocument
+  // Don't forget to change the capacity to match your requirements.
+  // Use https://arduinojson.org/assistant to compute the capacity.
+  StaticJsonDocument<256> doc;
+
+  // Set the values in the document
+  doc["hostname"] = config.hostname;
+  doc["port"] = config.port;
+
+  // Serialize JSON to file
+  if (serializeJson(doc, file) == 0) {
+    Serial.println(F("Failed to write to file"));
+  }
+
+  // Close the file
+  file.close();
+}
+
+// Prints the content of a file to the Serial
+void printFile(const char *filename) {
+  // Open file for reading
+  File file = SD.open(filename);
+  if (!file) {
+    Serial.println(F("Failed to read file"));
+    return;
+  }
+
+  // Extract each characters by one by one
+  while (file.available()) {
+    Serial.print((char)file.read());
+  }
+  Serial.println();
+
+  // Close the file
+  file.close();
+}
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Initialize SD library
+  const int chipSelect = 4;
+  while (!SD.begin(chipSelect)) {
+    Serial.println(F("Failed to initialize SD library"));
+    delay(1000);
+  }
+
+  // Should load default config if run for the first time
+  Serial.println(F("Loading configuration..."));
+  loadConfiguration(filename, config);
+
+  // Create configuration file
+  Serial.println(F("Saving configuration..."));
+  saveConfiguration(filename, config);
+
+  // Dump config file
+  Serial.println(F("Print config file..."));
+  printFile(filename);
+}
+
+void loop() {
+  // not used in this example
+}
+
+// Performance issue?
+// ------------------
+//
+// File is an unbuffered stream, which is not optimal for ArduinoJson.
+// See: https://arduinojson.org/v6/how-to/improve-speed/
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// serialization or deserialization problem.
+//
+// The book "Mastering ArduinoJson" contains a case study of a project that has
+// a complex configuration with nested members.
+// Contrary to this example, the project in the book uses the SPIFFS filesystem.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 63 - 0
lib/ArduinoJson-6.20.1/examples/JsonFilterExample/JsonFilterExample.ino

@@ -0,0 +1,63 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to use DeserializationOption::Filter
+//
+// https://arduinojson.org/v6/example/filter/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // The huge input: an extract from OpenWeatherMap response
+  const __FlashStringHelper* input_json = F(
+      "{\"cod\":\"200\",\"message\":0,\"list\":[{\"dt\":1581498000,\"main\":{"
+      "\"temp\":3.23,\"feels_like\":-3.63,\"temp_min\":3.23,\"temp_max\":4.62,"
+      "\"pressure\":1014,\"sea_level\":1014,\"grnd_level\":1010,\"humidity\":"
+      "58,\"temp_kf\":-1.39},\"weather\":[{\"id\":800,\"main\":\"Clear\","
+      "\"description\":\"clear "
+      "sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":0},\"wind\":{\"speed\":6."
+      "19,\"deg\":266},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
+      "09:00:00\"},{\"dt\":1581508800,\"main\":{\"temp\":6.09,\"feels_like\":-"
+      "1.07,\"temp_min\":6.09,\"temp_max\":7.13,\"pressure\":1015,\"sea_"
+      "level\":1015,\"grnd_level\":1011,\"humidity\":48,\"temp_kf\":-1.04},"
+      "\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear "
+      "sky\",\"icon\":\"01d\"}],\"clouds\":{\"all\":9},\"wind\":{\"speed\":6."
+      "64,\"deg\":268},\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2020-02-12 "
+      "12:00:00\"}],\"city\":{\"id\":2643743,\"name\":\"London\",\"coord\":{"
+      "\"lat\":51.5085,\"lon\":-0.1257},\"country\":\"GB\",\"population\":"
+      "1000000,\"timezone\":0,\"sunrise\":1581492085,\"sunset\":1581527294}}");
+
+  // The filter: it contains "true" for each value we want to keep
+  StaticJsonDocument<200> filter;
+  filter["list"][0]["dt"] = true;
+  filter["list"][0]["main"]["temp"] = true;
+
+  // Deserialize the document
+  StaticJsonDocument<400> doc;
+  deserializeJson(doc, input_json, DeserializationOption::Filter(filter));
+
+  // Print the result
+  serializeJsonPretty(doc, Serial);
+}
+
+void loop() {
+  // not used in this example
+}
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// deserialization problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
+// It begins with a simple example, like the one above, and then adds more
+// features like deserializing directly from a file or an HTTP request.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 77 - 0
lib/ArduinoJson-6.20.1/examples/JsonGeneratorExample/JsonGeneratorExample.ino

@@ -0,0 +1,77 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to generate a JSON document with ArduinoJson.
+//
+// https://arduinojson.org/v6/example/generator/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  // Initialize Serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Allocate the JSON document
+  //
+  // Inside the brackets, 200 is the RAM allocated to this document.
+  // Don't forget to change this value to match your requirement.
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<200> doc;
+
+  // StaticJsonObject allocates memory on the stack, it can be
+  // replaced by DynamicJsonDocument which allocates in the heap.
+  //
+  // DynamicJsonDocument  doc(200);
+
+  // Add values in the document
+  //
+  doc["sensor"] = "gps";
+  doc["time"] = 1351824120;
+
+  // Add an array.
+  //
+  JsonArray data = doc.createNestedArray("data");
+  data.add(48.756080);
+  data.add(2.302038);
+
+  // Generate the minified JSON and send it to the Serial port.
+  //
+  serializeJson(doc, Serial);
+  // The above line prints:
+  // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
+
+  // Start a new line
+  Serial.println();
+
+  // Generate the prettified JSON and send it to the Serial port.
+  //
+  serializeJsonPretty(doc, Serial);
+  // The above line prints:
+  // {
+  //   "sensor": "gps",
+  //   "time": 1351824120,
+  //   "data": [
+  //     48.756080,
+  //     2.302038
+  //   ]
+  // }
+}
+
+void loop() {
+  // not used in this example
+}
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// serialization problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on serialization.
+// It begins with a simple example, like the one above, and then adds more
+// features like serializing directly to a file or an HTTP request.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 126 - 0
lib/ArduinoJson-6.20.1/examples/JsonHttpClient/JsonHttpClient.ino

@@ -0,0 +1,126 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to parse a JSON document in an HTTP response.
+// It uses the Ethernet library, but can be easily adapted for Wifi.
+//
+// It performs a GET resquest on https://arduinojson.org/example.json
+// Here is the expected response:
+// {
+//   "sensor": "gps",
+//   "time": 1351824120,
+//   "data": [
+//     48.756080,
+//     2.302038
+//   ]
+// }
+//
+// https://arduinojson.org/v6/example/http-client/
+
+#include <ArduinoJson.h>
+#include <Ethernet.h>
+#include <SPI.h>
+
+void setup() {
+  // Initialize Serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Initialize Ethernet library
+  byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
+  if (!Ethernet.begin(mac)) {
+    Serial.println(F("Failed to configure Ethernet"));
+    return;
+  }
+  delay(1000);
+
+  Serial.println(F("Connecting..."));
+
+  // Connect to HTTP server
+  EthernetClient client;
+  client.setTimeout(10000);
+  if (!client.connect("arduinojson.org", 80)) {
+    Serial.println(F("Connection failed"));
+    return;
+  }
+
+  Serial.println(F("Connected!"));
+
+  // Send HTTP request
+  client.println(F("GET /example.json HTTP/1.0"));
+  client.println(F("Host: arduinojson.org"));
+  client.println(F("Connection: close"));
+  if (client.println() == 0) {
+    Serial.println(F("Failed to send request"));
+    client.stop();
+    return;
+  }
+
+  // Check HTTP status
+  char status[32] = {0};
+  client.readBytesUntil('\r', status, sizeof(status));
+  // It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK"
+  if (strcmp(status + 9, "200 OK") != 0) {
+    Serial.print(F("Unexpected response: "));
+    Serial.println(status);
+    client.stop();
+    return;
+  }
+
+  // Skip HTTP headers
+  char endOfHeaders[] = "\r\n\r\n";
+  if (!client.find(endOfHeaders)) {
+    Serial.println(F("Invalid response"));
+    client.stop();
+    return;
+  }
+
+  // Allocate the JSON document
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
+  DynamicJsonDocument doc(capacity);
+
+  // Parse JSON object
+  DeserializationError error = deserializeJson(doc, client);
+  if (error) {
+    Serial.print(F("deserializeJson() failed: "));
+    Serial.println(error.f_str());
+    client.stop();
+    return;
+  }
+
+  // Extract values
+  Serial.println(F("Response:"));
+  Serial.println(doc["sensor"].as<const char*>());
+  Serial.println(doc["time"].as<long>());
+  Serial.println(doc["data"][0].as<float>(), 6);
+  Serial.println(doc["data"][1].as<float>(), 6);
+
+  // Disconnect
+  client.stop();
+}
+
+void loop() {
+  // not used in this example
+}
+
+// Performance issue?
+// ------------------
+//
+// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
+// See: https://arduinojson.org/v6/how-to/improve-speed/
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// serialization  problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on deserialization
+// showing how to parse the response from GitHub's API. In the last chapter,
+// it shows how to parse the huge documents from OpenWeatherMap
+// and Reddit.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 80 - 0
lib/ArduinoJson-6.20.1/examples/JsonParserExample/JsonParserExample.ino

@@ -0,0 +1,80 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to deserialize a JSON document with ArduinoJson.
+//
+// https://arduinojson.org/v6/example/parser/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Allocate the JSON document
+  //
+  // Inside the brackets, 200 is the capacity of the memory pool in bytes.
+  // Don't forget to change this value to match your JSON document.
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<200> doc;
+
+  // StaticJsonDocument<N> allocates memory on the stack, it can be
+  // replaced by DynamicJsonDocument which allocates in the heap.
+  //
+  // DynamicJsonDocument doc(200);
+
+  // JSON input string.
+  //
+  // Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
+  // the minimal amount of memory because the JsonDocument stores pointers to
+  // the input buffer.
+  // If you use another type of input, ArduinoJson must copy the strings from
+  // the input to the JsonDocument, so you need to increase the capacity of the
+  // JsonDocument.
+  char json[] =
+      "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+
+  // Deserialize the JSON document
+  DeserializationError error = deserializeJson(doc, json);
+
+  // Test if parsing succeeds.
+  if (error) {
+    Serial.print(F("deserializeJson() failed: "));
+    Serial.println(error.f_str());
+    return;
+  }
+
+  // Fetch values.
+  //
+  // Most of the time, you can rely on the implicit casts.
+  // In other case, you can do doc["time"].as<long>();
+  const char* sensor = doc["sensor"];
+  long time = doc["time"];
+  double latitude = doc["data"][0];
+  double longitude = doc["data"][1];
+
+  // Print values.
+  Serial.println(sensor);
+  Serial.println(time);
+  Serial.println(latitude, 6);
+  Serial.println(longitude, 6);
+}
+
+void loop() {
+  // not used in this example
+}
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// deserialization problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on deserialization.
+// It begins with a simple example, like the one above, and then adds more
+// features like deserializing directly from a file or an HTTP request.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 117 - 0
lib/ArduinoJson-6.20.1/examples/JsonServer/JsonServer.ino

@@ -0,0 +1,117 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to implement an HTTP server that sends a JSON document
+// in the response.
+// It uses the Ethernet library but can be easily adapted for Wifi.
+//
+// The JSON document contains the values of the analog and digital pins.
+// It looks like that:
+// {
+//   "analog": [0, 76, 123, 158, 192, 205],
+//   "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
+// }
+//
+// https://arduinojson.org/v6/example/http-server/
+
+#include <ArduinoJson.h>
+#include <Ethernet.h>
+#include <SPI.h>
+
+byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
+EthernetServer server(80);
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Initialize Ethernet libary
+  if (!Ethernet.begin(mac)) {
+    Serial.println(F("Failed to initialize Ethernet library"));
+    return;
+  }
+
+  // Start to listen
+  server.begin();
+
+  Serial.println(F("Server is ready."));
+  Serial.print(F("Please connect to http://"));
+  Serial.println(Ethernet.localIP());
+}
+
+void loop() {
+  // Wait for an incomming connection
+  EthernetClient client = server.available();
+
+  // Do we have a client?
+  if (!client)
+    return;
+
+  Serial.println(F("New client"));
+
+  // Read the request (we ignore the content in this example)
+  while (client.available()) client.read();
+
+  // Allocate a temporary JsonDocument
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<500> doc;
+
+  // Create the "analog" array
+  JsonArray analogValues = doc.createNestedArray("analog");
+  for (int pin = 0; pin < 6; pin++) {
+    // Read the analog input
+    int value = analogRead(pin);
+
+    // Add the value at the end of the array
+    analogValues.add(value);
+  }
+
+  // Create the "digital" array
+  JsonArray digitalValues = doc.createNestedArray("digital");
+  for (int pin = 0; pin < 14; pin++) {
+    // Read the digital input
+    int value = digitalRead(pin);
+
+    // Add the value at the end of the array
+    digitalValues.add(value);
+  }
+
+  Serial.print(F("Sending: "));
+  serializeJson(doc, Serial);
+  Serial.println();
+
+  // Write response headers
+  client.println(F("HTTP/1.0 200 OK"));
+  client.println(F("Content-Type: application/json"));
+  client.println(F("Connection: close"));
+  client.print(F("Content-Length: "));
+  client.println(measureJsonPretty(doc));
+  client.println();
+
+  // Write JSON document
+  serializeJsonPretty(doc, client);
+
+  // Disconnect
+  client.stop();
+}
+
+// Performance issue?
+// ------------------
+//
+// EthernetClient is an unbuffered stream, which is not optimal for ArduinoJson.
+// See: https://arduinojson.org/v6/how-to/improve-speed/
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// serialization problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on serialization.
+// It begins with a simple example, then adds more features like serializing
+// directly to a file or an HTTP client.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 106 - 0
lib/ArduinoJson-6.20.1/examples/JsonUdpBeacon/JsonUdpBeacon.ino

@@ -0,0 +1,106 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to send a JSON document to a UDP socket.
+// At regular interval, it sends a UDP packet that contains the status of
+// analog and digital pins.
+// It looks like that:
+// {
+//   "analog": [0, 76, 123, 158, 192, 205],
+//   "digital": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0]
+// }
+//
+// If you want to test this program, you need to be able to receive the UDP
+// packets.
+// For example, you can run netcat on your computer
+// $ ncat -ulp 8888
+// See https://nmap.org/ncat/
+//
+// https://arduinojson.org/v6/example/udp-beacon/
+
+#include <ArduinoJson.h>
+#include <Ethernet.h>
+#include <SPI.h>
+
+byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
+IPAddress remoteIp(192, 168, 0, 108);  // <- EDIT!!!!
+unsigned short remotePort = 8888;
+unsigned short localPort = 8888;
+EthernetUDP udp;
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Initialize Ethernet libary
+  if (!Ethernet.begin(mac)) {
+    Serial.println(F("Failed to initialize Ethernet library"));
+    return;
+  }
+
+  // Enable UDP
+  udp.begin(localPort);
+}
+
+void loop() {
+  // Allocate a temporary JsonDocument
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<500> doc;
+
+  // Create the "analog" array
+  JsonArray analogValues = doc.createNestedArray("analog");
+  for (int pin = 0; pin < 6; pin++) {
+    // Read the analog input
+    int value = analogRead(pin);
+
+    // Add the value at the end of the array
+    analogValues.add(value);
+  }
+
+  // Create the "digital" array
+  JsonArray digitalValues = doc.createNestedArray("digital");
+  for (int pin = 0; pin < 14; pin++) {
+    // Read the digital input
+    int value = digitalRead(pin);
+
+    // Add the value at the end of the array
+    digitalValues.add(value);
+  }
+
+  // Log
+  Serial.print(F("Sending to "));
+  Serial.print(remoteIp);
+  Serial.print(F(" on port "));
+  Serial.println(remotePort);
+  serializeJson(doc, Serial);
+
+  // Send UDP packet
+  udp.beginPacket(remoteIp, remotePort);
+  serializeJson(doc, udp);
+  udp.println();
+  udp.endPacket();
+
+  // Wait
+  delay(10000);
+}
+
+// Performance issue?
+// ------------------
+//
+// EthernetUDP is an unbuffered stream, which is not optimal for ArduinoJson.
+// See: https://arduinojson.org/v6/how-to/improve-speed/
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any
+// serialization problem.
+//
+// The book "Mastering ArduinoJson" contains a tutorial on serialization.
+// It begins with a simple example, then adds more features like serializing
+// directly to a file or any stream.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 75 - 0
lib/ArduinoJson-6.20.1/examples/MsgPackParser/MsgPackParser.ino

@@ -0,0 +1,75 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows how to deserialize a MessagePack document with
+// ArduinoJson.
+//
+// https://arduinojson.org/v6/example/msgpack-parser/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  // Initialize serial port
+  Serial.begin(9600);
+  while (!Serial) continue;
+
+  // Allocate the JSON document
+  //
+  // Inside the brackets, 200 is the capacity of the memory pool in bytes.
+  // Don't forget to change this value to match your JSON document.
+  // Use https://arduinojson.org/v6/assistant to compute the capacity.
+  StaticJsonDocument<200> doc;
+
+  // StaticJsonObject allocates memory on the stack, it can be
+  // replaced by DynamicJsonObject which allocates in the heap.
+  //
+  // DynamicJsonObject doc(200);
+
+  // MessagePack input string.
+  //
+  // Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
+  // the minimal amount of memory because the JsonDocument stores pointers to
+  // the input buffer.
+  // If you use another type of input, ArduinoJson must copy the strings from
+  // the input to the JsonDocument, so you need to increase the capacity of the
+  // JsonDocument.
+  uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
+                     164, 116, 105, 109, 101, 206, 80,  147, 50,  248, 164, 100,
+                     97,  116, 97,  146, 203, 64,  72,  96,  199, 58,  188, 148,
+                     112, 203, 64,  2,   106, 146, 230, 33,  49,  169};
+  // This MessagePack document contains:
+  // {
+  //   "sensor": "gps",
+  //   "time": 1351824120,
+  //   "data": [48.75608, 2.302038]
+  // }
+
+  DeserializationError error = deserializeMsgPack(doc, input);
+
+  // Test if parsing succeeded.
+  if (error) {
+    Serial.print("deserializeMsgPack() failed: ");
+    Serial.println(error.f_str());
+    return;
+  }
+
+  // Fetch values.
+  //
+  // Most of the time, you can rely on the implicit casts.
+  // In other case, you can do doc["time"].as<long>();
+  const char* sensor = doc["sensor"];
+  long time = doc["time"];
+  double latitude = doc["data"][0];
+  double longitude = doc["data"][1];
+
+  // Print values.
+  Serial.println(sensor);
+  Serial.println(time);
+  Serial.println(latitude, 6);
+  Serial.println(longitude, 6);
+}
+
+void loop() {
+  // not used in this example
+}

+ 63 - 0
lib/ArduinoJson-6.20.1/examples/ProgmemExample/ProgmemExample.ino

@@ -0,0 +1,63 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows the different ways you can use Flash strings with
+// ArduinoJson.
+//
+// Use Flash strings sparingly, because ArduinoJson duplicates them in the
+// JsonDocument. Prefer plain old char*, as they are more efficient in term of
+// code size, speed, and memory usage.
+//
+// https://arduinojson.org/v6/example/progmem/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  DynamicJsonDocument doc(1024);
+
+  // You can use a Flash String as your JSON input.
+  // WARNING: the strings in the input will be duplicated in the JsonDocument.
+  deserializeJson(doc, F("{\"sensor\":\"gps\",\"time\":1351824120,"
+                         "\"data\":[48.756080,2.302038]}"));
+
+  // You can use a Flash String as a key to get a member from JsonDocument
+  // No duplication is done.
+  long time = doc[F("time")];
+
+  // You can use a Flash String as a key to set a member of a JsonDocument
+  // WARNING: the content of the Flash String will be duplicated in the
+  // JsonDocument.
+  doc[F("time")] = time;
+
+  // You can set a Flash String as the content of a JsonVariant
+  // WARNING: the content of the Flash String will be duplicated in the
+  // JsonDocument.
+  doc["sensor"] = F("gps");
+
+  // It works with serialized() too:
+  doc["sensor"] = serialized(F("\"gps\""));
+  doc["sensor"] = serialized(F("\xA3gps"), 3);
+
+  // You can compare the content of a JsonVariant to a Flash String
+  if (doc["sensor"] == F("gps")) {
+    // ...
+  }
+}
+
+void loop() {
+  // not used in this example
+}
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any memory
+// problem.
+//
+// The book "Mastering ArduinoJson" contains a quick C++ course that explains
+// how your microcontroller stores strings in memory. It also tells why you
+// should not abuse Flash strings with ArduinoJson.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 77 - 0
lib/ArduinoJson-6.20.1/examples/StringExample/StringExample.ino

@@ -0,0 +1,77 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+//
+// This example shows the different ways you can use String with ArduinoJson.
+//
+// Use String objects sparingly, because ArduinoJson duplicates them in the
+// JsonDocument. Prefer plain old char[], as they are more efficient in term of
+// code size, speed, and memory usage.
+//
+// https://arduinojson.org/v6/example/string/
+
+#include <ArduinoJson.h>
+
+void setup() {
+  DynamicJsonDocument doc(1024);
+
+  // You can use a String as your JSON input.
+  // WARNING: the string in the input  will be duplicated in the JsonDocument.
+  String input =
+      "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
+  deserializeJson(doc, input);
+
+  // You can use a String as a key to get a member from JsonDocument
+  // No duplication is done.
+  long time = doc[String("time")];
+
+  // You can use a String as a key to set a member of a JsonDocument
+  // WARNING: the content of the String will be duplicated in the JsonDocument.
+  doc[String("time")] = time;
+
+  // You can get the content of a JsonVariant as a String
+  // No duplication is done, at least not in the JsonDocument.
+  String sensor = doc["sensor"];
+
+  // Unfortunately, the following doesn't work (issue #118):
+  // sensor = doc["sensor"]; // <-  error "ambiguous overload for 'operator='"
+  // As a workaround, you need to replace by:
+  sensor = doc["sensor"].as<String>();
+
+  // You can set a String as the content of a JsonVariant
+  // WARNING: the content of the String will be duplicated in the JsonDocument.
+  doc["sensor"] = sensor;
+
+  // It works with serialized() too:
+  doc["sensor"] = serialized(sensor);
+
+  // You can also concatenate strings
+  // WARNING: the content of the String will be duplicated in the JsonDocument.
+  doc[String("sen") + "sor"] = String("gp") + "s";
+
+  // You can compare the content of a JsonObject with a String
+  if (doc["sensor"] == sensor) {
+    // ...
+  }
+
+  // Lastly, you can print the resulting JSON to a String
+  // WARNING: it doesn't replace the content but appends to it
+  String output;
+  serializeJson(doc, output);
+}
+
+void loop() {
+  // not used in this example
+}
+
+// See also
+// --------
+//
+// https://arduinojson.org/ contains the documentation for all the functions
+// used above. It also includes an FAQ that will help you solve any problem.
+//
+// The book "Mastering ArduinoJson" contains a quick C++ course that explains
+// how your microcontroller stores strings in memory. On several occasions, it
+// shows how you can avoid String in your program.
+// Learn more at https://arduinojson.org/book/
+// Use the coupon code TWENTY for a 20% discount ❤❤❤❤❤

+ 4 - 0
lib/ArduinoJson-6.20.1/extras/ArduinoJsonConfig.cmake.in

@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+check_required_components("@PROJECT_NAME@")

+ 101 - 0
lib/ArduinoJson-6.20.1/extras/CompileOptions.cmake

@@ -0,0 +1,101 @@
+if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
+	add_compile_options(
+		-pedantic
+		-Wall
+		-Wcast-align
+		-Wcast-qual
+		-Wconversion
+		-Wctor-dtor-privacy
+		-Wdisabled-optimization
+		-Werror
+		-Wextra
+		-Wformat=2
+		-Winit-self
+		-Wmissing-include-dirs
+		-Wnon-virtual-dtor
+		-Wold-style-cast
+		-Woverloaded-virtual
+		-Wparentheses
+		-Wredundant-decls
+		-Wshadow
+		-Wsign-conversion
+		-Wsign-promo
+		-Wstrict-aliasing
+		-Wundef
+	)
+
+	if(${COVERAGE})
+		set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage")
+	endif()
+
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL  "GNU")
+	if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND (NOT ${COVERAGE}))
+		add_compile_options(-g -Og)
+	else()
+		add_compile_options(-g -O0)
+	endif()
+
+	add_compile_options(
+		-Wstrict-null-sentinel
+		-Wno-vla # Allow VLA in tests
+	)
+	add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
+
+	if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
+		add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
+	endif()
+
+	if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
+		add_compile_options(-Wnoexcept)
+	endif()
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+	add_compile_options(
+		-Wc++11-compat
+		-Wdeprecated-register
+		-Wno-vla-extension # Allow VLA in tests
+	)
+	add_definitions(
+		-DHAS_VARIABLE_LENGTH_ARRAY
+		-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
+	)
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+	if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0) AND (NOT ${COVERAGE}))
+		add_compile_options(-g -Og)
+	else()
+		add_compile_options(-g -O0)
+	endif()
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+	if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) AND (NOT ${COVERAGE}))
+		add_compile_options(-g -Og)
+	else()
+		add_compile_options(-g -O0)
+	endif()
+endif()
+
+if(MSVC)
+	add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+	add_compile_options(
+		/W4 # Set warning level
+		/WX # Treats all compiler warnings as errors.
+	)
+
+	if (NOT MSVC_VERSION LESS  1910) #  >= Visual Studio 2017
+		add_compile_options(
+			/Zc:__cplusplus  # Enable updated __cplusplus macro
+		)
+	endif()
+endif()
+
+if(MINGW)
+  # Static link on MinGW to avoid linking with the wrong DLLs when multiple
+	# versions are installed.
+	add_link_options(-static)
+endif()

+ 8 - 0
lib/ArduinoJson-6.20.1/extras/ci/espidf/CMakeLists.txt

@@ -0,0 +1,8 @@
+# ArduinoJson - https://arduinojson.org
+# Copyright © 2014-2022, Benoit BLANCHON
+# MIT License
+
+cmake_minimum_required(VERSION 3.5)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(example)

+ 6 - 0
lib/ArduinoJson-6.20.1/extras/ci/espidf/main/CMakeLists.txt

@@ -0,0 +1,6 @@
+# ArduinoJson - https://arduinojson.org
+# Copyright © 2014-2022, Benoit BLANCHON
+# MIT License
+
+idf_component_register(SRCS "main.cpp"
+                       INCLUDE_DIRS "")

+ 4 - 0
lib/ArduinoJson-6.20.1/extras/ci/espidf/main/component.mk

@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

+ 16 - 0
lib/ArduinoJson-6.20.1/extras/ci/espidf/main/main.cpp

@@ -0,0 +1,16 @@
+// ArduinoJson - https://arduinojson.org
+// Copyright © 2014-2022, Benoit BLANCHON
+// MIT License
+
+#include <ArduinoJson.h>
+
+extern "C" void app_main() {
+  char buffer[256];
+  StaticJsonDocument<200> doc;
+
+  doc["hello"] = "world";
+  serializeJson(doc, buffer);
+  deserializeJson(doc, buffer);
+  serializeMsgPack(doc, buffer);
+  deserializeMsgPack(doc, buffer);
+}

+ 10 - 0
lib/ArduinoJson-6.20.1/extras/ci/particle.sh

@@ -0,0 +1,10 @@
+#!/bin/sh -ex
+
+BOARD=$1
+
+cd "$(dirname "$0")/../../"
+
+cp extras/particle/src/smocktest.ino src/
+cp extras/particle/project.properties ./
+
+particle compile "$BOARD"

+ 16 - 0
lib/ArduinoJson-6.20.1/extras/conf_test/avr.cpp

@@ -0,0 +1,16 @@
+#include <ArduinoJson.h>
+
+static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
+
+static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 1,
+              "ARDUINOJSON_SLOT_OFFSET_SIZE");
+
+static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
+
+static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
+
+static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 8,
+              "sizeof(VariantSlot)");
+
+void setup() {}
+void loop() {}

+ 16 - 0
lib/ArduinoJson-6.20.1/extras/conf_test/esp8266.cpp

@@ -0,0 +1,16 @@
+#include <ArduinoJson.h>
+
+static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
+
+static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2,
+              "ARDUINOJSON_SLOT_OFFSET_SIZE");
+
+static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
+
+static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
+
+static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 16,
+              "sizeof(VariantSlot)");
+
+void setup() {}
+void loop() {}

+ 15 - 0
lib/ArduinoJson-6.20.1/extras/conf_test/x64.cpp

@@ -0,0 +1,15 @@
+#include <ArduinoJson.h>
+
+static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
+
+static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 4,
+              "ARDUINOJSON_SLOT_OFFSET_SIZE");
+
+static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
+
+static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
+
+static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 32,
+              "sizeof(VariantSlot)");
+
+int main() {}

+ 15 - 0
lib/ArduinoJson-6.20.1/extras/conf_test/x86.cpp

@@ -0,0 +1,15 @@
+#include <ArduinoJson.h>
+
+static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
+
+static_assert(ARDUINOJSON_SLOT_OFFSET_SIZE == 2,
+              "ARDUINOJSON_SLOT_OFFSET_SIZE");
+
+static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
+
+static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
+
+static_assert(sizeof(ARDUINOJSON_NAMESPACE::VariantSlot) == 16,
+              "sizeof(VariantSlot)");
+
+int main() {}

+ 59 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/CMakeLists.txt

@@ -0,0 +1,59 @@
+# ArduinoJson - https://arduinojson.org
+# Copyright © 2014-2022, Benoit BLANCHON
+# MIT License
+
+if(MSVC)
+	add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+add_executable(msgpack_reproducer
+	msgpack_fuzzer.cpp
+	reproducer.cpp
+)
+target_link_libraries(msgpack_reproducer
+	ArduinoJson
+)
+
+add_executable(json_reproducer
+	json_fuzzer.cpp
+	reproducer.cpp
+)
+target_link_libraries(json_reproducer
+	ArduinoJson
+)
+
+macro(add_fuzzer name)	
+	set(FUZZER "${name}_fuzzer")
+	set(CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_corpus")
+	set(SEED_CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_seed_corpus")
+	add_executable("${FUZZER}"
+		"${name}_fuzzer.cpp"
+	)
+	target_link_libraries("${FUZZER}"
+		ArduinoJson
+	)
+	set_target_properties("${FUZZER}"
+		PROPERTIES 
+			COMPILE_FLAGS  
+				"-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
+			LINK_FLAGS
+				"-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
+	)
+
+	add_test(
+		NAME
+			"${FUZZER}"
+		COMMAND
+			"${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1
+	)
+
+	set_tests_properties("${FUZZER}"
+		PROPERTIES
+			LABELS 		"Fuzzing"
+	)
+endmacro()
+
+if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
+	add_fuzzer(json)
+	add_fuzzer(msgpack)
+endif()

+ 22 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/Makefile

@@ -0,0 +1,22 @@
+# CAUTION: this file is invoked by https://github.com/google/oss-fuzz
+
+CXXFLAGS += -I../../src -DARDUINOJSON_DEBUG=1
+
+all: \
+	$(OUT)/json_fuzzer \
+	$(OUT)/json_fuzzer_seed_corpus.zip \
+	$(OUT)/json_fuzzer.options \
+	$(OUT)/msgpack_fuzzer \
+	$(OUT)/msgpack_fuzzer_seed_corpus.zip \
+	$(OUT)/msgpack_fuzzer.options
+
+$(OUT)/%_fuzzer: %_fuzzer.cpp $(shell find ../../src -type f)
+	$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE)
+
+$(OUT)/%_fuzzer_seed_corpus.zip: %_seed_corpus/*
+	zip -j $@ $?
+
+$(OUT)/%_fuzzer.options:
+	@echo "[libfuzzer]" > $@
+	@echo "max_len = 256" >> $@
+	@echo "timeout = 10" >> $@

+ 2 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_corpus/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 11 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_fuzzer.cpp

@@ -0,0 +1,11 @@
+#include <ArduinoJson.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  DynamicJsonDocument doc(4096);
+  DeserializationError error = deserializeJson(doc, data, size);
+  if (!error) {
+    std::string json;
+    serializeJson(doc, json);
+  }
+  return 0;
+}

+ 10 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Comments.json

@@ -0,0 +1,10 @@
+//comment
+/*comment*/
+[ //comment
+/*comment*/"comment"/*comment*/,//comment
+/*comment*/{//comment
+/* comment*/"key"//comment
+: //comment
+"value"//comment
+}/*comment*/
+]//comment

+ 1 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/EmptyArray.json

@@ -0,0 +1 @@
+[]

+ 1 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/EmptyObject.json

@@ -0,0 +1 @@
+{}

+ 1 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/ExcessiveNesting.json

@@ -0,0 +1 @@
+[1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20,[21,[22,[23,[24,[25,[26,[27,[28,[29,[30,[31,[32,[33,[34,[35,[36,[37,[38,[39,[40,[41,[42,[43,[44,[45,[46,[47,[48,[49,[50,[51,[52,[53,[54,[55,[56,[57,[58,[59,[60,[61,[62,[63,[64,[65,[66,[67,[68,[69,[70,[71,[72,[73,[74,[75,[76,[77,[78,[79,[80,[81,[82,[83,[84,[85,[86,[87,[88,[89,[90,[91,[92,[93,[94,[95,[96,[97,[98,[99,[100,[101,[102,[103,[104,[105,[106,[107,[108,[109,[110,[111,[112,[113,[114,[115,[116,[117,[118,[119,[120]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]

+ 1 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/IntegerOverflow.json

@@ -0,0 +1 @@
+9720730739393920739

+ 24 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Numbers.json

@@ -0,0 +1,24 @@
+[
+  123,
+  -123,
+  123.456,
+  -123.456,
+  12e34,
+  12e-34,
+  12e+34,
+  12E34,
+  12E-34,
+  12E+34,
+  12.34e56,
+  12.34e-56,
+  12.34e+56,
+  12.34E56,
+  12.34E-56,
+  12.34E+56,
+  NaN,
+  -NaN,
+  +NaN,
+  Infinity,
+  +Infinity,
+  -Infinity
+]

+ 53 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/OpenWeatherMap.json

@@ -0,0 +1,53 @@
+{
+  "coord": {
+    "lon": -0.13,
+    "lat": 51.51
+  },
+  "weather": [
+    {
+      "id": 301,
+      "main": "Drizzle",
+      "description": "drizzle",
+      "icon": "09n"
+    },
+    {
+      "id": 701,
+      "main": "Mist",
+      "description": "mist",
+      "icon": "50n"
+    },
+    {
+      "id": 741,
+      "main": "Fog",
+      "description": "fog",
+      "icon": "50n"
+    }
+  ],
+  "base": "stations",
+  "main": {
+    "temp": 281.87,
+    "pressure": 1032,
+    "humidity": 100,
+    "temp_min": 281.15,
+    "temp_max": 283.15
+  },
+  "visibility": 2900,
+  "wind": {
+    "speed": 1.5
+  },
+  "clouds": {
+    "all": 90
+  },
+  "dt": 1483820400,
+  "sys": {
+    "type": 1,
+    "id": 5091,
+    "message": 0.0226,
+    "country": "GB",
+    "sunrise": 1483776245,
+    "sunset": 1483805443
+  },
+  "id": 2643743,
+  "name": "London",
+  "cod": 200
+}

+ 8 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/Strings.json

@@ -0,0 +1,8 @@
+[
+  "hello",
+  'hello',
+  hello,
+  {"hello":"world"},
+  {'hello':'world'},
+  {hello:world}
+]

+ 90 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/json_seed_corpus/WeatherUnderground.json

@@ -0,0 +1,90 @@
+{
+  "response": {
+    "version": "0.1",
+    "termsofService": "http://www.wunderground.com/weather/api/d/terms.html",
+    "features": {
+      "conditions": 1
+    }
+  },
+  "current_observation": {
+    "image": {
+      "url": "http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png",
+      "title": "Weather Underground",
+      "link": "http://www.wunderground.com"
+    },
+    "display_location": {
+      "full": "San Francisco, CA",
+      "city": "San Francisco",
+      "state": "CA",
+      "state_name": "California",
+      "country": "US",
+      "country_iso3166": "US",
+      "zip": "94101",
+      "latitude": "37.77500916",
+      "longitude": "-122.41825867",
+      "elevation": "47.00000000"
+    },
+    "observation_location": {
+      "full": "SOMA - Near Van Ness, San Francisco, California",
+      "city": "SOMA - Near Van Ness, San Francisco",
+      "state": "California",
+      "country": "US",
+      "country_iso3166": "US",
+      "latitude": "37.773285",
+      "longitude": "-122.417725",
+      "elevation": "49 ft"
+    },
+    "estimated": {},
+    "station_id": "KCASANFR58",
+    "observation_time": "Last Updated on June 27, 5:27 PM PDT",
+    "observation_time_rfc822": "Wed, 27 Jun 2012 17:27:13 -0700",
+    "observation_epoch": "1340843233",
+    "local_time_rfc822": "Wed, 27 Jun 2012 17:27:14 -0700",
+    "local_epoch": "1340843234",
+    "local_tz_short": "PDT",
+    "local_tz_long": "America/Los_Angeles",
+    "local_tz_offset": "-0700",
+    "weather": "Partly Cloudy",
+    "temperature_string": "66.3 F (19.1 C)",
+    "temp_f": 66.3,
+    "temp_c": 19.1,
+    "relative_humidity": "65%",
+    "wind_string": "From the NNW at 22.0 MPH Gusting to 28.0 MPH",
+    "wind_dir": "NNW",
+    "wind_degrees": 346,
+    "wind_mph": 22,
+    "wind_gust_mph": "28.0",
+    "wind_kph": 35.4,
+    "wind_gust_kph": "45.1",
+    "pressure_mb": "1013",
+    "pressure_in": "29.93",
+    "pressure_trend": "+",
+    "dewpoint_string": "54 F (12 C)",
+    "dewpoint_f": 54,
+    "dewpoint_c": 12,
+    "heat_index_string": "NA",
+    "heat_index_f": "NA",
+    "heat_index_c": "NA",
+    "windchill_string": "NA",
+    "windchill_f": "NA",
+    "windchill_c": "NA",
+    "feelslike_string": "66.3 F (19.1 C)",
+    "feelslike_f": "66.3",
+    "feelslike_c": "19.1",
+    "visibility_mi": "10.0",
+    "visibility_km": "16.1",
+    "solarradiation": "",
+    "UV": "5",
+    "precip_1hr_string": "0.00 in ( 0 mm)",
+    "precip_1hr_in": "0.00",
+    "precip_1hr_metric": " 0",
+    "precip_today_string": "0.00 in (0 mm)",
+    "precip_today_in": "0.00",
+    "precip_today_metric": "0",
+    "icon": "partlycloudy",
+    "icon_url": "http://icons-ak.wxug.com/i/c/k/partlycloudy.gif",
+    "forecast_url": "http://www.wunderground.com/US/CA/San_Francisco.html",
+    "history_url": "http://www.wunderground.com/history/airport/KCASANFR58/2012/6/27/DailyHistory.html",
+    "ob_url": "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.773285,-122.417725"
+  }
+}

+ 2 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_corpus/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 11 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_fuzzer.cpp

@@ -0,0 +1,11 @@
+#include <ArduinoJson.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  DynamicJsonDocument doc(4096);
+  DeserializationError error = deserializeMsgPack(doc, data, size);
+  if (!error) {
+    std::string json;
+    serializeMsgPack(doc, json);
+  }
+  return 0;
+}

BIN
lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/array16


BIN
lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/array32


+ 1 - 0
lib/ArduinoJson-6.20.1/extras/fuzzing/msgpack_seed_corpus/false

@@ -0,0 +1 @@

Some files were not shown because too many files changed in this diff