diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b914e15 --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: Google +IndentWidth: 4 +ColumnLimit: 120 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..e0a9f3a --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,521 @@ +// +// !!! WARNING !!! AUTO-GENERATED FILE! +// PLEASE DO NOT MODIFY IT AND USE "platformio.ini": +// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +// +{ + "configurations": [ + { + "name": "PlatformIO", + "includePath": [ + "/home/admar/Documents/Arduino/buienradarklok/Claire/include", + "/home/admar/Documents/Arduino/buienradarklok/Claire/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/BSEC Software Library/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/Adafruit NeoPixel", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/dESPatch", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/ArduinoJson/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/WifiManager-esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/newlib/platform_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions/freertos", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/port/xtensa/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/heap/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/log/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps/sntp", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include/arch", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/platform_port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/soc", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/public_compat", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_pm/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ringbuf/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/vfs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_wifi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_netif/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_eth/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcpip_adapter/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ipc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_trace/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_timer/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/mbedtls/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_update/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spi_flash/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bootloader_support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nvs_flash/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/pthread/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/xtensa", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include/port/xtensa", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ieee802154/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/console", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/asio/asio/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/osi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/include/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/api/include/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/storage", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/btc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/core/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/models/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cbor/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/unity/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cmock/CMock/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/libcoap/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls/esp-tls-crypto", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_adc_cal/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hid/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcp_transport/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_ota/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/interface", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protobuf-c/protobuf-c", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/common", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/security", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/transports", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mdns/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_local_ctrl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/sdmmc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_serial_slave_link/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_websocket_client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/expat/expat/lib", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wear_levelling/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/diskio", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/vfs", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freemodbus/freemodbus/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/jsmn/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json/cJSON", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/port_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mqtt/esp-mqtt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/openssl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/perfmon/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spiffs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ulp/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wifi_provisioning/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rmaker_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_diagnostics/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rtc_store/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_insights/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_generator/upstream", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_schedule/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp_secure_cert_mgr/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rainmaker/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/gpio_button/button/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/qrcode/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ws2812_led", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_littlefs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/tool", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/typedef", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/image", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/math", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/nn", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/layer", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/detect", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/model_zoo", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/conversions/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dotprod/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/mem/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/hann/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/nuttall/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/flat_top/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/iir/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fir/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/add/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mul/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/addc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mulc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sqrt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mul/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/add/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/addc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mulc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/sub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fft/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dct/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/conv/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mul/test/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fb_gfx/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/dio_qspi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "" + ], + "browse": { + "limitSymbolsToIncludedHeaders": true, + "path": [ + "/home/admar/Documents/Arduino/buienradarklok/Claire/include", + "/home/admar/Documents/Arduino/buienradarklok/Claire/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/BSEC Software Library/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/Adafruit NeoPixel", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/dESPatch", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Update/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/ArduinoJson/src", + "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/libdeps/esp32dev/WifiManager-esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/FS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/newlib/platform_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions/freertos", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/port/xtensa/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/heap/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/log/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps/sntp", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include/arch", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/platform_port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/soc", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/public_compat", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_pm/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ringbuf/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/vfs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_wifi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_netif/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_eth/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcpip_adapter/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ipc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_trace/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_timer/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/mbedtls/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_update/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spi_flash/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bootloader_support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nvs_flash/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/pthread/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/xtensa", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include/port/xtensa", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ieee802154/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/console", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/asio/asio/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/osi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/include/esp32/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/api/include/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/storage", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/btc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/core/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/models/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cbor/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/unity/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cmock/CMock/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/libcoap/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls/esp-tls-crypto", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_adc_cal/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hid/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcp_transport/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_ota/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_server/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/interface", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protobuf-c/protobuf-c", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/common", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/security", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/transports", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mdns/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_local_ctrl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/sdmmc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_serial_slave_link/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_websocket_client/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/expat/expat/lib", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/port/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wear_levelling/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/diskio", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/vfs", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freemodbus/freemodbus/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/jsmn/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json/cJSON", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/port_include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mqtt/esp-mqtt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/openssl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/perfmon/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spiffs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ulp/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wifi_provisioning/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rmaker_common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_diagnostics/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rtc_store/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_insights/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_generator/upstream", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_schedule/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp_secure_cert_mgr/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rainmaker/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/gpio_button/button/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/qrcode/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ws2812_led", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_littlefs/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/tool", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/typedef", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/image", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/math", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/nn", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/layer", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/detect", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/model_zoo", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/conversions/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dotprod/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/support/mem/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/hann/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_harris/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/blackman_nuttall/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/nuttall/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/windows/flat_top/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/iir/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fir/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/add/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mul/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/addc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/mulc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/math/sqrt/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mul/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/add/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/addc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mulc/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/sub/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/fft/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/dct/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/conv/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/common/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/matrix/mul/test/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espressif__esp-dsp/modules/kalman/ekf_imu13states/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fb_gfx/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/dio_qspi/include", + "/home/admar/.platformio/packages/framework-arduinoespressif32/cores/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/Insights/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/USB/src", + "/home/admar/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", + "" + ] + }, + "defines": [ + "PLATFORMIO=60115", + "ARDUINO_ESP32_DEV", + "HAVE_CONFIG_H", + "MBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"", + "UNITY_INCLUDE_CONFIG_H", + "WITH_POSIX", + "_GNU_SOURCE", + "IDF_VER=\"v4.4.7-dirty\"", + "ESP_PLATFORM", + "_POSIX_READER_WRITER_LOCKS", + "ARDUINO_ARCH_ESP32", + "ESP32", + "F_CPU=240000000L", + "ARDUINO=10812", + "ARDUINO_VARIANT=\"esp32\"", + "ARDUINO_BOARD=\"Espressif ESP32 Dev Module\"", + "ARDUINO_PARTITION_default", + "" + ], + "cStandard": "gnu99", + "cppStandard": "gnu++20", + "compilerPath": "/home/admar/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcc", + "compilerArgs": [ + "-mlongcalls", + "" + ] + } + ], + "version": 4 +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.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" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f510696 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,44 @@ +// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY +// +// PlatformIO Debugging Solution +// +// Documentation: https://docs.platformio.org/en/latest/plus/debugging.html +// Configuration: https://docs.platformio.org/en/latest/projectconf/sections/env/options/debug/index.html + +{ + "version": "0.2.0", + "configurations": [ + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug", + "executable": "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "/home/admar/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart", + "preLaunchTask": { + "type": "PlatformIO", + "task": "Pre-Debug" + } + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (skip Pre-Debug)", + "executable": "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "/home/admar/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart" + }, + { + "type": "platformio-debug", + "request": "launch", + "name": "PIO Debug (without uploading)", + "executable": "/home/admar/Documents/Arduino/buienradarklok/Claire/.pio/build/esp32dev/firmware.elf", + "projectEnvName": "esp32dev", + "toolchainBinDir": "/home/admar/.platformio/packages/toolchain-xtensa-esp32/bin", + "internalConsoleOptions": "openOnSessionStart", + "loadMode": "manual" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b72cb1c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,52 @@ +{ + "files.associations": { + "string_view": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "string": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" + } +} \ No newline at end of file diff --git a/Claire.ino b/Claire.ino deleted file mode 100644 index d298742..0000000 --- a/Claire.ino +++ /dev/null @@ -1,1061 +0,0 @@ -//#define DISABLE_WIFI -#define HW_PROTO_PAPER 1 -#define HW_PROTO_V1 2 - -#ifndef LED_BUILTIN -#define LED_BUILTIN 2 -#endif - -#ifndef BUTTON_BUILTIN -#define BUTTON_BUILTIN 0 -#endif - -#include // https://github.com/admarschoonen/WiFiManager -#include - -#include -#include -#include - -#include -#include "bsec.h" - -#include "soc/soc.h" -#include "soc/rtc_cntl_reg.h" - -#ifndef LED_BUILTIN -#define LED_BUILTIN 2 -#endif - -#define NUM_LEDS_PROTO_PAPER 93 -#define DATA_PIN_PROTO_PAPER 5 -#define CONNECT_SW_PIN_PROTO_PAPER BUTTON_BUILTIN -#define NUM_LEDS_PROTO_V1 29 -#define DATA_PIN_PROTO_V1 14 -#define CONNECT_SW_PIN_PROTO_V1 21 - -static int BUIENRADAR_START_LED = 0; -static int BUIENRADAR_SKIP_LED = 1; -static int BUIENRADAR_NUM_LEDS = 12; -static int PAQI_START_LED = 0; -static int PAQI_SKIP_LED = 0; -static int PAQI_NUM_LEDS = 0; -static int UVI_LED = 0; -static int AQI_LED = 0; -static int POLLEN_LED = 0; -static int IAQI_LED = 0; -static int CONNECT_SW_PIN = 0; -static int LIGHT_PIN = 0; - -#define SHOW_AQI_LED -#define SHOW_POLLEN_LED -#define SHOW_UVI_LED - -#define MIN(x, y) (((x) <= (y)) ? (x) : (y)) - -Adafruit_NeoPixel leds_rgb_proto_paper(NUM_LEDS_PROTO_PAPER, DATA_PIN_PROTO_PAPER, NEO_GRB + NEO_KHZ800); -Adafruit_NeoPixel leds_rgbw_proto_v1(NUM_LEDS_PROTO_V1, DATA_PIN_PROTO_V1, NEO_RGBW + NEO_KHZ800); - -const uint8_t bsec_config_iaq[] = { - #include "config/generic_33v_3s_4d/bsec_iaq.txt" -}; - -static int ledMapPrecipitation[12] = {0}; -static int ledMapPAQI[12] = {0}; -static int ledMapUVI = 0; -static int ledMapPollen = 0; -static int ledMapIAQI = 0; -static int ledMapAQI = 0; - -#define SEALEVELPRESSURE_HPA (1013.25) -#define BME_CS 5 -String output; -Bsec iaqSensor; - -static HTTPClient http; -static const String baseUrlAQI = "https://sinoptik.luon.net/forecast?metrics=PAQI&metrics=AQI&metrics=pollen&metrics=UVI"; -static const String baseUrlPrecipitation = "https://sinoptik.luon.net/forecast?metrics=precipitation"; - -static int hw_variant = 0; - -WiFiManager wifiManager; -DESPatch dESPatch; -const char* root_ca = \ - "-----BEGIN CERTIFICATE-----\n" \ - "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \ - "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \ - "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \ - "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \ - "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \ - "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \ - "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \ - "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \ - "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \ - "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \ - "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \ - "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \ - "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \ - "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \ - "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \ - "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \ - "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \ - "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \ - "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \ - "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \ - "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \ - "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \ - "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \ - "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \ - "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \ - "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \ - "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \ - "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \ - "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \ - "-----END CERTIFICATE-----\n"; - - - -const float location[] = {51.445466493287434, 5.515445691496135}; // Telefoonstraat, Eindhoven -const String address = "Telefoonstraat 18, Eindhoven"; - -//const float location[] = {51.44083, 5.47778}; // Eindhoven -//const float location[] = {52.09083, 5.12222}; // Utrecht -//const float location[] = {51.8425, 5.85278}; // Nijmegen -//const float location[] = {52.37403, 4.88969}; // Amsterdam -//const float location[] = {52.15833, 4.49306}; // Leiden - -typedef struct RainPickerDataArray24 { - const int len = 24; - long time[24]; - float value[24]; -} RainPickerDataArray24; - -typedef struct RainPickerDataArray5 { - const int len = 5; - long time[5]; - float value[5]; -} RainPickerDataArray5; - -typedef struct RainpickerData { - float lat; - float lon; - long time; - - RainPickerDataArray24 PAQI; - RainPickerDataArray24 AQI; - RainPickerDataArray24 pollen; - RainPickerDataArray5 UVI; - RainPickerDataArray24 precipitation; -} RainpickerData; - -RainpickerData rainpickerData; - -StaticJsonDocument<6144> doc; - -static bool initDone = false; - -void parseJson(String * payload) -{ - doc.clear(); - - DeserializationError error = deserializeJson(doc, * payload); - - if (error) { - Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.f_str()); - return; - } - - rainpickerData.lat = doc["lat"]; - rainpickerData.lon = doc["lon"]; - rainpickerData.time = doc["time"]; - - int n = 0; - for (JsonObject elem : doc["PAQI"].as()) { - if (n >= rainpickerData.PAQI.len) { - break; - } - rainpickerData.PAQI.time[n] = elem["time"]; - rainpickerData.PAQI.value[n] = elem["value"]; - n = n + 1; - } - - n = 0; - for (JsonObject elem : doc["AQI"].as()) { - if (n >= rainpickerData.AQI.len) { - break; - } - rainpickerData.AQI.time[n] = elem["time"]; - rainpickerData.AQI.value[n] = elem["value"]; - n = n + 1; - } - - n = 0; - for (JsonObject elem : doc["pollen"].as()) { - if (n >= rainpickerData.pollen.len) { - break; - } - rainpickerData.pollen.time[n] = elem["time"]; - rainpickerData.pollen.value[n] = elem["value"]; - n = n + 1; - } - - n = 0; - for (JsonObject elem : doc["UVI"].as()) { - if (n >= rainpickerData.UVI.len) { - break; - } - rainpickerData.UVI.time[n] = elem["time"]; - rainpickerData.UVI.value[n] = elem["value"]; - n = n + 1; - } - - n = 0; - for (JsonObject elem : doc["precipitation"].as()) { - if (n >= rainpickerData.precipitation.len) { - break; - } - rainpickerData.precipitation.time[n] = elem["time"]; - rainpickerData.precipitation.value[n] = elem["value"]; - n = n + 1; - } -} - -static void setup_pins_proto_paper(void) -{ - int n = 0; - - BUIENRADAR_START_LED = 32; - BUIENRADAR_SKIP_LED = 1; - BUIENRADAR_NUM_LEDS = 12; - - PAQI_START_LED = 72; - PAQI_SKIP_LED = 0; - PAQI_NUM_LEDS = 12; - - // #define UVI_LED 92 // LED in center - UVI_LED = 84; // LED above center - AQI_LED = 86; // LED to the right - POLLEN_LED = 90; // LED to the left - IAQI_LED = 88; // LED below center - - CONNECT_SW_PIN = CONNECT_SW_PIN_PROTO_PAPER; - - n = 0; - while (n < BUIENRADAR_NUM_LEDS) { - ledMapPrecipitation[n] = BUIENRADAR_START_LED + n * (BUIENRADAR_SKIP_LED + 1); - n = n + 1; - } - - n = 0; - while (n < PAQI_NUM_LEDS) { - ledMapPAQI[n] = PAQI_START_LED + n * (PAQI_SKIP_LED + 1); - n = n + 1; - } - - ledMapAQI = AQI_LED; - ledMapUVI = UVI_LED; - ledMapPollen = POLLEN_LED; - ledMapIAQI = IAQI_LED; -} - -static void setup_pins_proto_v1(void) -{ - int n = 0; - - BUIENRADAR_START_LED = 0; - BUIENRADAR_SKIP_LED = 0; - BUIENRADAR_NUM_LEDS = 12; - - PAQI_START_LED = 12; - PAQI_SKIP_LED = 0; - PAQI_NUM_LEDS = 12; - - UVI_LED = 27; // LED above center - AQI_LED = 24; // LED to the right - POLLEN_LED = 26; // LED to the left - IAQI_LED = 25; // LED below center - - CONNECT_SW_PIN = CONNECT_SW_PIN_PROTO_V1; - - ledMapPrecipitation[0] = 11; - n = 1; - while (n < BUIENRADAR_NUM_LEDS) { - ledMapPrecipitation[n] = BUIENRADAR_START_LED + (n - 1) * (BUIENRADAR_SKIP_LED + 1); - n = n + 1; - } - - ledMapPAQI[0] = 23; - n = 1; - while (n < PAQI_NUM_LEDS) { - ledMapPAQI[n] = PAQI_START_LED + (n - 1) * (PAQI_SKIP_LED + 1); - n = n + 1; - } - - ledMapAQI = AQI_LED; - ledMapUVI = UVI_LED; - ledMapPollen = POLLEN_LED; - ledMapIAQI = IAQI_LED; - - LIGHT_PIN = 34; - analogSetPinAttenuation(LIGHT_PIN, ADC_0db); - analogReadResolution(12); -} - -void leds_clear(void) { - if (hw_variant == HW_PROTO_PAPER) { - leds_rgb_proto_paper.clear(); - leds_rgb_proto_paper.show(); - } else if (hw_variant == HW_PROTO_V1) { - leds_rgbw_proto_v1.clear(); - leds_rgbw_proto_v1.show(); - } -} - -int checkIaqSensorStatus(void) -{ - if (iaqSensor.bsecStatus != BSEC_OK) { - if (iaqSensor.bsecStatus < BSEC_OK) { - output = "BSEC error code : " + String(iaqSensor.bsecStatus); - Serial.println(output); - //for (;;); - } else { - output = "BSEC warning code : " + String(iaqSensor.bsecStatus); - Serial.println(output); - } - } - - if (iaqSensor.bme68xStatus != BME68X_OK) { - if (iaqSensor.bme68xStatus < BME68X_OK) { - output = "BME680 error code : " + String(iaqSensor.bme68xStatus); - Serial.println(output); - //for (;;); - } else { - output = "BME680 warning code : " + String(iaqSensor.bme68xStatus); - Serial.println(output); - } - } - - return iaqSensor.bme68xStatus; -} - -void readSensors(void) { - static bool readingInProgress = false; - static unsigned long endTime = 0; - - if (hw_variant == HW_PROTO_PAPER) { - return; - } - - unsigned long time_trigger = millis(); - if (iaqSensor.run()) { // If new data is available - output = String(time_trigger); - output += " Sensor data: Traw: " + String(iaqSensor.rawTemperature); - output += " *C , P: " + String(iaqSensor.pressure); - output += " hPa, RHraw: " + String(iaqSensor.rawHumidity); - output += " %, Rgas: " + String(iaqSensor.gasResistance); - output += " Ohm, IAQ: " + String(iaqSensor.iaq); - output += ", accuracy: " + String(iaqSensor.iaqAccuracy); - output += ", Tcorr: " + String(iaqSensor.temperature); - output += " *C, RHcorr: " + String(iaqSensor.humidity); - output += " %, IAQstatic: " + String(iaqSensor.staticIaq); - output += ", eCO2: " + String(iaqSensor.co2Equivalent); - output += " ppm, eVOC: " + String(iaqSensor.breathVocEquivalent); - output += " ppm"; - - int light = 0; - for (int n = 0; n < 256; n++) { - light += analogRead(LIGHT_PIN); - } - light = (light + 128) >> 8; - output += ", light: " + String(light); - Serial.println(output); - } else { - checkIaqSensorStatus(); - } -} - -void taskBME680( void * parameter ) -{ - while (initDone == false) { - delay(100); - } - - while (true) { - readSensors(); - delay(100); - } - - //Serial.println("Ending task 1"); - //vTaskDelete( NULL ); -} - -void setup() { - const char url[] = "https://apikey:cqprlgiafadnidsgeqozcpldkaeqimqw@despatch.luon.net/files/4/despatch.json"; - unsigned long interval = 60; // By default check for updates every 60 seconds - int x; - - WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Disable brownout; needed for some dev kits - - // sanity check delay - allows reprogramming if accidently blowing power w/leds - delay(2000); - - Serial.begin(115200); - Serial.println("buienradarklok starting"); - - http.setReuse(false); - - SPI.begin(); - iaqSensor.begin(BME_CS, SPI); - String output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix); - Serial.println(output); - x = checkIaqSensorStatus(); - - if (x != BME68X_OK) { - Serial.println(F("Could not find a valid BME680 sensor; assuming hw variant \"paper prototype\"!")); - hw_variant = HW_PROTO_PAPER; - setup_pins_proto_paper(); - leds_rgb_proto_paper.begin(); // INITIALIZE NeoPixel strip object - } else { - Serial.println(F("BME680 found; assuming hw variant \"proto v1\"")); - - iaqSensor.setConfig(bsec_config_iaq); - iaqSensor.setTemperatureOffset(13.5f); - checkIaqSensorStatus(); - - hw_variant = HW_PROTO_V1; - setup_pins_proto_v1(); - leds_rgbw_proto_v1.begin(); // INITIALIZE NeoPixel strip object - } - - bsec_virtual_sensor_t sensorList[10] = { - BSEC_OUTPUT_RAW_TEMPERATURE, - BSEC_OUTPUT_RAW_PRESSURE, - BSEC_OUTPUT_RAW_HUMIDITY, - BSEC_OUTPUT_RAW_GAS, - BSEC_OUTPUT_IAQ, - BSEC_OUTPUT_STATIC_IAQ, - BSEC_OUTPUT_CO2_EQUIVALENT, - BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, - }; - - iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP); - checkIaqSensorStatus(); - - // Print the header - output = "Timestamp [ms], raw temperature [°C], pressure [hPa], raw relative humidity [%], gas [Ohm], IAQ, IAQ accuracy, temperature [°C], relative humidity [%], Static IAQ, CO2 equivalent, breath VOC equivalent"; - Serial.println(output); - - leds_clear(); - -#ifndef DISABLE_WIFI - //wifiManager.resetSettings(); - wifiManager.configure("Claire-", true, LED_BUILTIN, true, CONNECT_SW_PIN, false); - - //fetches ssid and pass and tries to connect - //if it does not connect it starts an access point - //and goes into a blocking loop awaiting configuration - if (!wifiManager.autoConnect()) { - Serial.println("failed to connect and hit timeout"); - //reset and try again, or maybe put it to deep sleep - ESP.restart(); - delay(1000); - } - - //if you get here you have connected to the WiFi - Serial.print("connected with address: "); - Serial.println(WiFi.localIP()); - - if (hw_variant == HW_PROTO_PAPER) { - //keep LED on - digitalWrite(LED_BUILTIN, LED_ON_VALUE_DEFAULT); - } - - x = dESPatch.configure(url, true, false, interval, false, root_ca); - Serial.print("dESPatch.configure() returned with code "); - Serial.println(x); -#endif - initDone = true; - - xTaskCreate(taskBME680, "taskBME680", 10000, NULL, 1, NULL); -} - -// From https://circuits4you.com/2019/03/21/esp8266-url-encode-decode-example/ -String urlencode(String str) -{ - String encodedString=""; - char c; - char code0; - char code1; - char code2; - for (int i =0; i < str.length(); i++){ - c=str.charAt(i); - if (c == ' '){ - encodedString+= '+'; - } else if (isalnum(c)){ - encodedString+=c; - } else{ - code1=(c & 0xf)+'0'; - if ((c & 0xf) >9){ - code1=(c & 0xf) - 10 + 'A'; - } - c=(c>>4)&0xf; - code0=c+'0'; - if (c > 9){ - code0=c - 10 + 'A'; - } - code2='\0'; - encodedString+='%'; - encodedString+=code0; - encodedString+=code1; - //encodedString+=code2; - } - yield(); - } - - return encodedString; -} - -void getPrecipitation(const float * location) { - int httpCode; - //String url = baseUrl + "&lat=" + String(location[0]) + "&lon=" + String(location[1]); - String url, latS, lonS; - int tmp1, tmp2; - String payload = ""; - - tmp1 = int(location[0]); - tmp2 = int((location[0] - tmp1) * 1000000); - latS = String(tmp1) + "." + String(tmp2); - tmp1 = int(location[1]); - tmp2 = int((location[1] - tmp1) * 1000000); - lonS = String(tmp1) + "." + String(tmp2); - - url = baseUrlPrecipitation + "&lat=" + latS + "&lon=" + lonS; - - Serial.print(millis()); - Serial.print(" Retrieving precipitation from "); - Serial.println(url); - - http.begin(url, root_ca); - httpCode = http.GET(); - - if (httpCode > 0) { - payload = http.getString(); - parseJson(&payload); - } else { - Serial.print(millis()); - Serial.print(" Got http code "); - Serial.println(httpCode); - } - http.end(); -} - -void getPrecipitation(const String address) { - int httpCode; - //String url = baseUrl + "&lat=" + String(location[0]) + "&lon=" + String(location[1]); - String url, a; - String payload = ""; - - a = urlencode(address); - - url = baseUrlPrecipitation + "&address=" + a; - - Serial.print(millis()); - Serial.print(" Retrieving precipitation from "); - Serial.println(url); - - http.begin(url, root_ca); - httpCode = http.GET(); - - if (httpCode > 0) { - payload = http.getString(); - parseJson(&payload); - } else { - Serial.print(millis()); - Serial.print(" Got http code "); - Serial.println(httpCode); - } - http.end(); -} - -void getAQI(const float * location) { - int httpCode; - //String url = baseUrl + "&lat=" + String(location[0]) + "&lon=" + String(location[1]); - String url, latS, lonS; - int tmp1, tmp2; - String payload = ""; - - tmp1 = int(location[0]); - tmp2 = int((location[0] - tmp1) * 1000000); - latS = String(tmp1) + "." + String(tmp2); - tmp1 = int(location[1]); - tmp2 = int((location[1] - tmp1) * 1000000); - lonS = String(tmp1) + "." + String(tmp2); - - url = baseUrlAQI + "&lat=" + latS + "&lon=" + lonS; - - Serial.print(millis()); - Serial.print(" Retrieving AQI from "); - Serial.println(url); - - http.begin(url, root_ca); - httpCode = http.GET(); - - if (httpCode > 0) { - payload = http.getString(); - parseJson(&payload); - } else { - Serial.print(millis()); - Serial.print(" Got http code "); - Serial.println(httpCode); - } - http.end(); -} - -void getAQI(const String address) { - int httpCode; - //String url = baseUrl + "&lat=" + String(location[0]) + "&lon=" + String(location[1]); - String url, a; - String payload = ""; - - a = urlencode(address); - - url = baseUrlAQI + "&address=" + a; - - Serial.print(millis()); - Serial.print(" Retrieving AQI from "); - Serial.println(url); - - http.begin(url, root_ca); - httpCode = http.GET(); - - if (httpCode > 0) { - payload = http.getString(); - parseJson(&payload); - } else { - Serial.print(millis()); - Serial.print(" Got http code "); - Serial.println(httpCode); - } - http.end(); -} - -static int colormap(float x) { - // Input: intensity - // Output: RGB encoded pixel color similar to luchtmeetnet legend - int y = 0; - - if (x < 1.0) { - y = (0 << 16) | (0 << 8) | 0; // black (good) - } else if (x < 2.0) { - // 1.0 <= x < 2.0 - if (hw_variant == HW_PROTO_PAPER) { - y = (0 << 16) | (0 << 8) | 160; // blue (good) - } else if (hw_variant == HW_PROTO_V1) { - y = (0 << 16) | (0 << 8) | 255; // blue (good) - } - } else if (x < 3.0) { - // 2.0 <= x < 3.0 - y = (0 << 16) | (255 << 8) | 255; // cyan (good) - } else if (x < 4.0) { - // 3.0 <= x < 4.0 - y = (255 << 16) | (255 << 8) | 255; // white (mediocre) - } else if (x < 5.0) { - // 4.0 <= x < 5.0 - y = (200 << 16) | (200 << 8) | 32; // light yellow (mediocre) - } else if (x < 6.0) { - // 5.0 <= x < 6.0 - y = (120 << 16) | (120 << 8) | 0; // yellow (mediocre) - } else if (x < 7.0) { - // 6.0 <= x < 7.0 - y = (200 << 16) | (80 << 8) | 0; // orange (inadequate) - } else if (x < 8.0) { - // 7.0 <= x < 8.0 - y = (255 << 16) | (50 << 8) | 0; // red orange (inadequate) - } else if (x < 9.0) { - // 8.0 <= x < 9.0 - y = (180 << 16) | (0 << 8) | 0; // red (bad) - } else if (x < 10.0) { - // 9.0 <= x < 10.0 - y = (200 << 16) | (0 << 8) | 160; // magenta (bad) - } else { - // 10.0 <= x - y = (60 << 16) | (0 << 8) | 210; // purple (terrible) - } - - return y; -} - -float colormapIaqi(void) -{ - float x = 0.0f; - float iaqi = iaqSensor.staticIaq; - - if (iaqi <= 50.0f) { - x = 1.0f; // Excellent - } else if (iaqi <= 100.0f) { - x = 2.0f; // Good - } else if (iaqi <= 125.0f) { - x = 4.0f; - } else if (iaqi <= 150.0f) { - x = 4.0f; // Lightly polluted - } else if (iaqi <= 175.0f) { - x = 5.0f; - } else if (iaqi <= 200.0f) { - x = 6.0f; // Moderately polluted - } else if (iaqi <= 225.0f) { - x = 7.0f; - } else if (iaqi <= 250.0f) { - x = 8.0f; // Heavily polluted - } else if (iaqi <= 300.0f) { - x = 9.0f; - } else if (iaqi <= 350.0f) { - x = 10.0f; // Severely polluted - } else { - x = 11.0f; // Extremely polluted - } - - return colormap(x); -} - -static float buienradarMap(float x) { - // Input: rain intensity (mm/h) - // Output: floating point number which can be mapped on color scale - float y = 0; - - // Use E3 series of preferred numbers to map intensity to color - if (x < 0.1) { - y = 0.5; - } else if (x < 0.22) { - y = 1.5; - } else if (x < 0.47) { - y = 2.5; - } else if (x < 1.0) { - y = 3.5; - } else if (x < 2.2) { - y = 4.5; - } else if (x < 4.7) { - y = 5.5; - } else if (x < 10) { - y = 6.5; - } else if (x < 22) { - y = 7.5; - } else if (x < 47) { - y = 8.5; - } else if (x < 100) { - y = 9.5; - } else { - y = 10.5; - } - - return y; -} - -static void ledsSetPixelColor(uint32_t ledIdx, int r, int g, int b, int w) { - if (hw_variant == HW_PROTO_PAPER) { - leds_rgb_proto_paper.setPixelColor(ledIdx, leds_rgb_proto_paper.Color(r, g, b)); - } else if (hw_variant == HW_PROTO_V1) { - leds_rgbw_proto_v1.setPixelColor(ledIdx, leds_rgbw_proto_v1.Color(g, r, b, w)); - } -} - -static void ledsSetPixelColor(uint32_t ledIdx, int r, int g, int b) { - ledsSetPixelColor(ledIdx, r, g, b, 0); -} - -static void updateLedsNoWifi(void) { - uint32_t ledIdx; - uint32_t ledCount; - uint32_t color; - int r, g, b, w, n; - - if (hw_variant == HW_PROTO_PAPER) { - // Start by setting all leds to value of the first datapoint - ledIdx = 11; - ledCount = 0; - for (ledCount = 0; ledCount < 11; ledCount++) { - color = colormap(ledCount); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(ledIdx, r, g, b); - ledIdx = ledIdx + PAQI_SKIP_LED + 1; - } - } else if (hw_variant == HW_PROTO_V1) { - // Start by setting all leds to value of the first datapoint - ledIdx = 0; - ledCount = 0; - for (ledCount = 0; ledCount < 11; ledCount++) { - color = colormap(ledCount); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - w = (color & 0xFF000000) >> 24; - - ledsSetPixelColor(ledIdx, r, g, b, w); - ledIdx = ledIdx + PAQI_SKIP_LED + 1; - } - } -} - -static void updateLeds(void) { - uint32_t ledIdx; - uint32_t ledCount; - uint32_t color; - int r, g, b, w, n; - - // Start by setting all leds to value of the first datapoint - ledIdx = PAQI_START_LED; - ledCount = 0; - for (ledCount = 0; ledCount < PAQI_NUM_LEDS; ledCount++) { - color = colormap(rainpickerData.PAQI.value[0]); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - w = (color & 0xFF000000) >> 24; - - ledsSetPixelColor(ledMapPAQI[ledCount], r, g, b); - ledIdx = ledIdx + PAQI_SKIP_LED + 1; - } - - ledIdx = PAQI_START_LED; - ledCount = 0; - for (n = 0; n < rainpickerData.PAQI.len; n++) { - if (rainpickerData.time < rainpickerData.PAQI.time[n]) { - ledIdx = ledIdx + PAQI_SKIP_LED + 1; - ledCount = ledCount + 1; - } - if (ledCount >= PAQI_NUM_LEDS) { - break; - } - - color = colormap(rainpickerData.PAQI.value[n]); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - w = (color & 0xFF000000) >> 24; - - ledsSetPixelColor(ledMapPAQI[ledCount], r, g, b); - } - - #ifdef SHOW_AQI_LED - // calculate AQI max value for next 12 hours - uint32_t AQI_max_value = 0; - //Serial.println("AQI:"); - for (n = 0; n < rainpickerData.AQI.len; n++) { - /*Serial.print(" "); - Serial.print(rainpickerData.AQI.time[n]); - Serial.print(": "); - Serial.println(rainpickerData.AQI.value[n]);*/ - if (rainpickerData.time - rainpickerData.AQI.time[n] >= 60 * 60) { - continue; - } - if (rainpickerData.AQI.time[n] >= rainpickerData.time + PAQI_NUM_LEDS * 60 * 60) { - break; - } - if (rainpickerData.AQI.value[n] > AQI_max_value) { - AQI_max_value = rainpickerData.AQI.value[n]; - } - } - //Serial.print("AQI max value: "); - //Serial.println(AQI_max_value); - color = colormap(AQI_max_value); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(AQI_LED, r, g, b); - #endif - - #ifdef SHOW_POLLEN_LED - // calculate pollen max value for next 12 hours - uint32_t pollen_max_value = rainpickerData.pollen.value[0]; - for (n = 0; n < rainpickerData.pollen.len; n++) { - if (rainpickerData.time - rainpickerData.pollen.time[n] >= 60 * 60) { - continue; - } - if (rainpickerData.pollen.time[n] >= rainpickerData.time + PAQI_NUM_LEDS * 60 * 60) { - break; - } - if (rainpickerData.pollen.value[n] > pollen_max_value) { - pollen_max_value = rainpickerData.pollen.value[n]; - } - } - - color = colormap(pollen_max_value); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(POLLEN_LED, r, g, b); - #endif - - #ifdef SHOW_UVI_LED - // calculate UVI led value - // UVI data is daily based --> search for first timestamp in the future and select value of the timestamp just before that - uint32_t UVI_value = rainpickerData.UVI.value[0]; - - for (n = 0; n < rainpickerData.UVI.len; n++) { - if (rainpickerData.UVI.time[n] >= rainpickerData.time) { - break; - } - UVI_value = rainpickerData.UVI.value[n]; - } - color = colormap(UVI_value); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(UVI_LED, r, g, b); - #endif - - // Start by setting all leds to value of the first datapoint - ledIdx = BUIENRADAR_START_LED; - for (ledCount = 0; ledCount < BUIENRADAR_NUM_LEDS; ledCount++) { - color = colormap(rainpickerData.precipitation.value[0]); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(ledMapPrecipitation[ledCount], r, g, b); - ledIdx = ledIdx + BUIENRADAR_SKIP_LED + 1; - } - - ledIdx = BUIENRADAR_START_LED; - ledCount = 0; - for (n = 0; n < rainpickerData.precipitation.len; n++) { - if (rainpickerData.time < rainpickerData.precipitation.time[n]) { - ledIdx = ledIdx + BUIENRADAR_SKIP_LED + 1; - ledCount = ledCount + 1; - } - if (ledCount >= BUIENRADAR_NUM_LEDS) { - break; - } - - color = colormap(buienradarMap(rainpickerData.precipitation.value[n])); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - ledsSetPixelColor(ledMapPrecipitation[ledCount], r, g, b); - } - - ledsSetPixelColor(IAQI_LED, r, g, b); - - if (hw_variant == HW_PROTO_V1) { - color = colormapIaqi(); - - r = (color & 0xFF0000) >> 16; - g = (color & 0x00FF00) >> 8; - b = (color & 0x0000FF); - - ledsSetPixelColor(IAQI_LED, r, g, b); - } -} - -void readConnectButton(void) { - static int reset_wifi_timer = millis(); - static bool reset_blocked = true; - - if (digitalRead(CONNECT_SW_PIN) == HIGH) { - // button released - reset_wifi_timer = millis(); - reset_blocked = false; - digitalWrite(LED_BUILTIN, LOW); - } else { - // button pressed - if (reset_blocked == false) { - int delta = millis() - reset_wifi_timer; - if (delta < 10000) { - if (delta % 1000 < 500) { - digitalWrite(LED_BUILTIN, HIGH); - } else { - digitalWrite(LED_BUILTIN, LOW); - } - } else { - leds_clear(); - - wifiManager.resetSettings(); - - // block reset so user must release button before we can reset again - reset_blocked = true; - digitalWrite(LED_BUILTIN, LOW); - ESP.restart(); - } - } - } -} - -void loop(void) { - static unsigned long t_prev = 0; - static bool ledOn = false; - unsigned long t_now = millis(); - const int buttonPin = 0; - static int rainColor[12] = {0}; - static int AQIColor[12] = {0}; - static bool firstTime = true; - static int counter = 0; - - if (firstTime || (t_now - t_prev >= 60000)) { - t_prev = t_now; - firstTime = false; - -#ifndef DISABLE_WIFI - if (WiFi.status() != WL_CONNECTED) { - Serial.print(millis()); - Serial.print(" wifi status error: "); - Serial.print(WiFi.status()); - Serial.print("; expected: "); - Serial.println(WL_CONNECTED); - bool result = WiFi.reconnect(); - Serial.print(millis()); - Serial.print(" reconnecting result: "); - Serial.print(result); - Serial.print("; expected: "); - Serial.println(ESP_OK); - } - getPrecipitation(address); - - if (counter == 0) { - getAQI(address); - } - - counter = counter + 1; - - if (counter == 5) { - // AQI should only be retreived every 5 minutes - counter = 0; - } -#endif - } - -#ifdef DISABLE_WIFI - updateLedsNoWifi(); -#else - updateLeds(); -#endif - - if (hw_variant == HW_PROTO_PAPER) { - leds_rgb_proto_paper.show(); - } else if (hw_variant == HW_PROTO_V1) { - leds_rgbw_proto_v1.show(); - } - - readConnectButton(); - - delay(100); -#ifndef DISABLE_WIFI - dESPatch.checkForUpdate(true); -#endif -} diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/include/backend_communication.hpp b/include/backend_communication.hpp new file mode 100644 index 0000000..8103dbd --- /dev/null +++ b/include/backend_communication.hpp @@ -0,0 +1,53 @@ +#ifndef __BACKEND_COMMUNICATION_HPP__ +#define __BACKEND_COMMUNICATION_HPP__ + +#include +#include + +#include "../include/root_ca.hpp" +#include "../include/wifi_handler.hpp" + +class BackendCommunication { + public: + // Public enums + enum State { ERROR, STILL_VALID, UPDATED }; + + public: + // Constructor + BackendCommunication(WifiHandler& p_wifi_handler); + + public: + // Public methods + bool getConfig(); + + bool getWeatherData(); + + State update(); + + private: + // Private methods + bool parseConfig(String& p_payload); + + bool parseWeatherData(String& p_payload); + + String urlencode(String str); + + public: + // Public member objects + JsonDocument m_config; + bool m_is_config_valid; + String m_config_timestamp; + + JsonDocument m_weather_data; + int32_t m_next_call; + + private: + // Private static members + constexpr static uint32_t INTERVAL_MS = 60U * 1000U; + + private: + // Private member objects + WifiHandler& m_wifi_handler; +}; + +#endif // __BACKEND_COMMUNICATION_HPP__ \ No newline at end of file diff --git a/include/color_conversion.hpp b/include/color_conversion.hpp new file mode 100644 index 0000000..d8a2e38 --- /dev/null +++ b/include/color_conversion.hpp @@ -0,0 +1,24 @@ +#ifndef __COLOR_CONVERSION_HPP__ +#define __COLOR_CONVERSION_HPP__ + +#include +#include + +std::tuple rgb_to_xyz(uint8_t p_red, uint8_t p_green, uint8_t p_blue); +std::tuple xyz_to_rgb(float p_x, float p_y, float p_z); + +std::tuple xyz_to_cieluv(float p_x, float p_y, float p_z); +std::tuple cieluv_to_xyz(float p_l_star, float p_u_star, float p_v_star); + +std::tuple cieluv_to_cielchuv(float p_l_star, float p_u_star, float p_v_star); +std::tuple cielchuv_to_cieluv(float p_l_star, float p_c_star, float p_h_star); + +bool is_xyz_in_rgb_range(float p_x, float p_y, float p_z); +bool is_cieluv_in_rgb_range(float p_l_star, float p_u_star, float p_v_star); +bool is_cielchuv_in_rgb_range(float p_l_star, float p_c_star, float p_h_star); + +std::tuple map_cielchuv_to_visible_color(float p_l_star, float p_c_star, float p_h_star); + +std::tuple rgb_to_cielchuv(uint8_t p_red, uint8_t p_green, uint8_t p_blue); +std::tuple cielchuv_to_rgb(float p_l_star, float p_c_star, float p_h_star); +#endif // __COLOR_CONVERSION_HPP__ \ No newline at end of file diff --git a/include/display.hpp b/include/display.hpp new file mode 100644 index 0000000..c6c259b --- /dev/null +++ b/include/display.hpp @@ -0,0 +1,58 @@ +#ifndef __DISPLAY_HPP__ +#define __DISPLAY_HPP__ + +#include +#include +#include + +class Display { + public: + // Constructor + Display(Adafruit_NeoPixel& p_leds); + + public: + // Public methods + void setPollenPlusAQIForecastLeds(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_pollen, + ArduinoJson::V710PB22::JsonArray p_aqi); + void setPrecipitationForecastLeds(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_precipitation); + void setUVIForecastLed(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_uvi); + void setLocalAirQualityLed(float p_iaq); + void setWifiStatusLed(bool p_is_connected); + void setErrorLed(bool p_is_error); + void setPixelColor(uint32_t p_index, uint8_t p_red, uint8_t p_green, uint8_t p_blue, uint8_t p_white); + void setBrightness(float p_brightness); + void clear(); + void show(); + + private: + // Private methods + float findMaxValueInTwelveHourInterval(uint32_t p_time_stamp, ArduinoJson::V710PB22::JsonArray p_array); + std::vector mergeJsonArraysFromTimestamp(uint32_t p_time_stamp, ArduinoJson::V710PB22::JsonArray p_array_a, + ArduinoJson::V710PB22::JsonArray p_array_b); + std::vector mergeJsonArraysFromTimestampHelper(uint32_t p_time_stamp, + ArduinoJson::V710PB22::JsonArray p_array_a, + ArduinoJson::V710PB22::JsonArray p_array_b); + float mapPrecipitationToColorIndex(const float p_rain_intensity); + std::tuple mapValueToColorRGB(float p_value); + std::tuple mapValueToColorRGBW(float p_value); + void setPixelToColorMappedValue(uint8_t index, float p_value); + + private: + // Private static members + constexpr static uint16_t NUM_LEDS_PROTO_V1 = 29U; + constexpr static int16_t DATA_PIN_PROTO_V1 = 14; + + private: + // Private members + Adafruit_NeoPixel& m_leds; + std::array m_precipitation_forecast_map; + std::array m_air_quality_forecast_map; + uint8_t m_max_pollen_map; + uint8_t m_max_air_qualilty_map; + uint8_t m_uvi_map; + uint8_t m_local_air_quality_map; + uint8_t m_wifi_status_map; + float m_brightness; +}; + +#endif // __DISPLAY_HPP__ \ No newline at end of file diff --git a/include/root_ca.hpp b/include/root_ca.hpp new file mode 100644 index 0000000..a24e7e5 --- /dev/null +++ b/include/root_ca.hpp @@ -0,0 +1,6 @@ +#ifndef __ROOT_CA_H__ +#define __ROOT_CA_H__ + +extern const char* root_ca; + +#endif // __ROOT_CA_H__ \ No newline at end of file diff --git a/include/sensor_manager.hpp b/include/sensor_manager.hpp new file mode 100644 index 0000000..bd1fd43 --- /dev/null +++ b/include/sensor_manager.hpp @@ -0,0 +1,54 @@ +#ifndef __SENSOR_MANAGER_HPP__ +#define __SENSOR_MANAGER_HPP__ + +#include "bsec.h" + +class SensorManager { + public: + // Public types + struct SensorData { + __typeof__(Bsec::iaq) iaq; + __typeof__(Bsec::iaqAccuracy) iaq_accuracy; + __typeof__(Bsec::staticIaq) static_iaq; + __typeof__(Bsec::co2Equivalent) co2_equivalent; + __typeof__(Bsec::breathVocEquivalent) breath_voc_equivalent; + __typeof__(Bsec::rawTemperature) raw_temperature; + __typeof__(Bsec::pressure) pressure; + __typeof__(Bsec::rawHumidity) raw_humidity; + __typeof__(Bsec::gasResistance) gas_resistance; + __typeof__(Bsec::stabStatus) stab_status; + __typeof__(Bsec::runInStatus) run_in_status; + __typeof__(Bsec::temperature) temperature; + __typeof__(Bsec::humidity) humidity; + __typeof__(Bsec::gasPercentage) gas_percentage; + }; + + public: + // Constructor + SensorManager(); + + bool setup(); + + bool read(); + + public: + // Public members + SensorData data; + + private: + bool checkIaqSensorStatus(); + + private: + // Private static members + constexpr static uint8_t BME_CS = 5U; + constexpr static uint8_t BSEC_CONFIG_IAQ[] = { +#include "config/generic_33v_3s_4d/bsec_iaq.txt" + }; + + private: + // Private members + Bsec m_iaq_sensor; + uint32_t m_next_call; +}; + +#endif // __SENSOR_MANAGER_HPP__ diff --git a/include/wifi_handler.hpp b/include/wifi_handler.hpp new file mode 100644 index 0000000..fcb03af --- /dev/null +++ b/include/wifi_handler.hpp @@ -0,0 +1,33 @@ +#ifndef __WIFI_HANDLER_HPP__ +#define __WIFI_HANDLER_HPP__ + +#include // https://github.com/admarschoonen/WiFiManager + +class WifiHandler { + public: + // Constructor + WifiHandler(std::function p_tickerCb); + + public: + // Public static methods + static void setBlinkRate(float p_interval); + static void wifiManagerCb(WiFiManager::Status p_status); + + public: + // Public methods + void connect(); + void resetSettings(); + String getMac(bool insertColons); + + public: + // Public static objects + constexpr static float BLINK_RATE_CONNECTING = 0.6f; + constexpr static float BLINK_RATE_CONFIG = 0.2f; + constexpr static float BLINK_RATE_ERASE = 0.05f; + + private: + // Private objects + WiFiManager m_wifiManager; +}; + +#endif // __WIFI_HANDLER_HPP__ \ No newline at end of file diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..2593a33 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..26f5450 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,22 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +build_unflags = -std=gnu++11 +build_flags = -std=gnu++2a +lib_deps = + https://github.com/admarschoonen/WIFIMANAGER-ESP32.git#v0.100.0 + https://github.com/admarschoonen/dESPatch.git#v0.9.5 + bblanchon/ArduinoJson@^7.1.0 + adafruit/Adafruit NeoPixel@^1.12.3 + boschsensortec/BSEC Software Library@^1.8.1492 diff --git a/src/backend_communication.cpp b/src/backend_communication.cpp new file mode 100644 index 0000000..ac4097e --- /dev/null +++ b/src/backend_communication.cpp @@ -0,0 +1,163 @@ +#include + +#include "../include/backend_communication.hpp" +#include "../include/wifi_handler.hpp" + +BackendCommunication::BackendCommunication(WifiHandler& p_wifi_handler) : m_wifi_handler(p_wifi_handler) { return; } + +bool BackendCommunication::getConfig() { + HTTPClient http; + + String mac = m_wifi_handler.getMac(false); + String url = "https://target.luon.net/~admar/Claire/" + urlencode(mac) + "/config.json"; + + String payload = ""; + bool is_success = false; + + http.begin(url, root_ca); + if (m_is_config_valid) { + http.addHeader("If-Modified-Since", m_config_timestamp); + } + + const char* headerKeys[] = {"Last-Modified"}; + const size_t headerKeysCount = sizeof(headerKeys) / sizeof(headerKeys[0]); + http.collectHeaders(headerKeys, headerKeysCount); + + int httpCode = http.GET(); + + if (httpCode == 200) { + // Content is in payload + payload = http.getString(); + is_success = parseConfig(payload); + + if (is_success) { + m_config_timestamp = http.header("Last-Modified"); + } + } else if (httpCode == 304) { + // Content did not change + is_success = true; + } else { + Serial.println(String(millis()) + " Got http code " + httpCode); + } + http.end(); + + return is_success; +} + +bool BackendCommunication::getWeatherData() { + HTTPClient http; + + String url = "https://sinoptik.luon.net/forecast?address=" + urlencode(m_config["address"]) + + "&metrics=precipitation&metrics=UVI&metrics=AQI&metrics=pollen"; + + String payload = ""; + bool is_success = false; + + http.begin(url, root_ca); + + int http_code = http.GET(); + + if (http_code > 0) { + payload = http.getString(); + is_success = parseWeatherData(payload); + } else { + Serial.println(String(millis()) + " Got http code " + http_code); + } + http.end(); + + return is_success; +} + +BackendCommunication::State BackendCommunication::update() { + int32_t time = static_cast(millis() & 0x7FFFFFFF); + int32_t time_delta = m_next_call - time; + + if (time_delta > 0) { + return STILL_VALID; + } + + m_next_call = (time + INTERVAL_MS) & 0x7FFFFFFF; + + if (not getConfig()) { + return ERROR; + } + + if (not getWeatherData()) { + return ERROR; + } + + return UPDATED; +} + +bool BackendCommunication::parseConfig(String& payload) { + bool is_success = false; + + m_config.clear(); + + DeserializationError error = deserializeJson(m_config, payload); + + if (error) { + Serial.print(String(millis()) + " DeserializeJson() failed: " + String(error.f_str())); + } else { + if (m_config["config version"] != "0.0.1") { + Serial.println(String(millis()) + " Unsupported config version"); + } else { + m_is_config_valid = true; + is_success = true; + } + } + + return is_success; +} + +bool BackendCommunication::parseWeatherData(String& payload) { + bool isSuccess = false; + + m_weather_data.clear(); + + DeserializationError error = deserializeJson(m_weather_data, payload); + + if (error) { + Serial.print(String(millis()) + " DeserializeJson() failed: " + String(error.f_str())); + } else { + m_is_config_valid = true; + isSuccess = true; + } + + return isSuccess; +} + +String BackendCommunication::urlencode(String str) { + // From https://circuits4you.com/2019/03/21/esp8266-url-encode-decode-example/ + String encodedString = ""; + char c; + char code0; + char code1; + char code2; + for (int i = 0; i < str.length(); i++) { + c = str.charAt(i); + if (c == ' ') { + encodedString += '+'; + } else if (isalnum(c)) { + encodedString += c; + } else { + code1 = (c & 0xf) + '0'; + if ((c & 0xf) > 9) { + code1 = (c & 0xf) - 10 + 'A'; + } + c = (c >> 4) & 0xf; + code0 = c + '0'; + if (c > 9) { + code0 = c - 10 + 'A'; + } + code2 = '\0'; + encodedString += '%'; + encodedString += code0; + encodedString += code1; + // encodedString+=code2; + } + yield(); + } + + return encodedString; +} diff --git a/src/color_conversion.cpp b/src/color_conversion.cpp new file mode 100644 index 0000000..25d9227 --- /dev/null +++ b/src/color_conversion.cpp @@ -0,0 +1,248 @@ +#include +#include + +#include "../include/color_conversion.hpp" + +std::tuple rgb_to_xyz(const uint8_t p_red, const uint8_t p_green, const uint8_t p_blue) { + auto normalize_uint8_t = [](const uint8_t p_value) -> float { + return std::min(static_cast(p_value) / 255.0F, 1.0F); + }; + + auto gamma_correction = [](const float p_value) -> float { + float gamma_corrected_value = 0.0F; + + if (p_value <= 0.0405F) { + gamma_corrected_value = p_value / 12.92F; + } else { + gamma_corrected_value = std::pow((p_value + 0.055F) / 1.055F, 2.4F); + } + + return gamma_corrected_value; + }; + + float red = gamma_correction(normalize_uint8_t(p_red)); + float green = gamma_correction(normalize_uint8_t(p_green)); + float blue = gamma_correction(normalize_uint8_t(p_blue)); + + float x = 0.4124564F * red + 0.3575761F * green + 0.1804375F * blue; + float y = 0.2126729F * red + 0.7151522F * green + 0.0721750F * blue; + float z = 0.0193339F * red + 0.1191920F * green + 0.9503041F * blue; + + return {x * 100.0F, y * 100.0F, z * 100.0F}; +} + +std::tuple xyz_to_rgb_float(float p_x, float p_y, float p_z) { + auto reverse_gamma_correction = [](const float p_value) -> float { + float reverse_gamma_corrected_value = 0.0F; + + if (p_value <= 0.0031308F) { + reverse_gamma_corrected_value = p_value * 12.92F; + } else { + reverse_gamma_corrected_value = std::pow(p_value, 1.0F / 2.4F) * 1.055F - 0.055F; + } + + return reverse_gamma_corrected_value; + }; + + auto clamp_if_within_error_margin = [](const float p_value) -> float { + float value = p_value; + constexpr float MARGIN = 0.001F; + + if ((p_value >= -MARGIN) and (p_value < 0.0F)) { + value = 0.0F; + } else if ((p_value <= 1.0F + MARGIN) and (p_value > 1.0F)) { + value = 1.0F; + } + + return value; + }; + + float red = 3.2404542F * p_x / 100.0F - 1.5371385F * p_y / 100.0F - 0.4985314F * p_z / 100.0F; + float green = -0.9692660F * p_x / 100.0F + 1.8760108F * p_y / 100.0F + 0.0415560F * p_z / 100.0F; + float blue = 0.0556434F * p_x / 100.0F - 0.2040259F * p_y / 100.0F + 1.0572252F * p_z / 100.0F; + + red = clamp_if_within_error_margin(reverse_gamma_correction(red)); + green = clamp_if_within_error_margin(reverse_gamma_correction(green)); + blue = clamp_if_within_error_margin(reverse_gamma_correction(blue)); + + return {red, green, blue}; +} + +std::tuple xyz_to_rgb(float p_x, float p_y, float p_z) { + auto uint8_t_scale = [](const float p_value) -> uint8_t { + return static_cast(std::clamp(p_value, 0.0F, 1.0F) * 255.0F + 0.5F); + }; + + auto [red, green, blue] = xyz_to_rgb_float(p_x, p_y, p_z); + + uint8_t red_uint8_t = uint8_t_scale(red); + uint8_t green_uint8_t = uint8_t_scale(green); + uint8_t blue_uint8_t = uint8_t_scale(blue); + + return {red_uint8_t, green_uint8_t, blue_uint8_t}; +} + +std::tuple xyz_to_uv(const float p_x, const float p_y, const float p_z) { + float denominator = (p_x + 15.0F * p_y + 3.0F * p_z); + + if (denominator == 0.0F) { + denominator = 1.0F; + } + + float u = (4.0F * p_x) / denominator; + float v = (9.0F * p_y) / denominator; + + return {u, v}; +} + +std::tuple uv_to_xy(const float p_u, const float p_v) { + float denominator = 6.0F * p_u - 16.0F * p_v + 12.0F; + + if (denominator == 0.0F) { + denominator = 1.0F; + } + + float x = 9.0F * p_u / denominator; + float y = 4.0F * p_v / denominator; + + return {x, y}; +} + +std::tuple xyz_d65_reference_white_point() { + // Standard D64 reference white point values + constexpr float X_N = 95.047F; + constexpr float Y_N = 100.0F; + constexpr float Z_N = 108.833F; + + return {X_N, Y_N, Z_N}; +} + +std::tuple xyz_to_cieluv(const float p_x, const float p_y, const float p_z) { + auto [X_N, Y_N, Z_N] = xyz_d65_reference_white_point(); + auto [U_N, V_N] = xyz_to_uv(X_N, Y_N, Z_N); + + auto [u, v] = xyz_to_uv(p_x, p_y, p_z); + + float l_star = 0.0F; + + if (p_y == 0.0F) { + l_star = 0.0F; + } else if ((p_y / Y_N) > 0.0088565F) { + l_star = 116.0F * std::cbrt(p_y / Y_N) - 16.0F; + } else { + l_star = p_y / Y_N * 903.3F; + } + + float u_star = 13.0F * l_star * (u - U_N); + float v_star = 13.0F * l_star * (v - V_N); + + return {l_star, u_star, v_star}; +} + +std::tuple cieluv_to_xyz(float p_l_star, float p_u_star, float p_v_star) { + auto [X_N, Y_N, Z_N] = xyz_d65_reference_white_point(); + auto [U_N, V_N] = xyz_to_uv(X_N, Y_N, Z_N); + + float denominator = 13.0F * p_l_star; + + if (denominator == 0.0F) { + denominator = 13.0F; + } + + float u = p_u_star / denominator + U_N; + float v = p_v_star / denominator + V_N; + + float y = 0.0F; + if (p_l_star <= 8.0F) { + y = Y_N * p_l_star * 0.0011071F; + } else { + y = Y_N * std::pow((p_l_star + 16.F) / 116.0F, 3.0F); + } + + if (v == 0.0F) { + denominator = 4.0F; + } else { + denominator = 4.0F * v; + } + float x = y * 9.0F * u / denominator; + float z = y * (12.0F - 3.0F * u - 20.0F * v) / denominator; + + return {x, y, z}; +} + +std::tuple cieluv_to_cielchuv(float p_l_star, float p_u_star, float p_v_star) { + float c_star = std::sqrt(p_u_star * p_u_star + p_v_star * p_v_star); + float h_star = std::atan2(p_v_star, p_u_star); + + if (h_star < 0.0F) { + h_star += 2.0F * M_PI; + } + + return {p_l_star, c_star, h_star}; +} + +std::tuple cielchuv_to_cieluv(float p_l_star, float p_c_star, float p_h_star) { + float u_star = p_c_star * std::cos(p_h_star); + float v_star = p_c_star * std::sin(p_h_star); + + return {p_l_star, u_star, v_star}; +} + +bool is_xyz_in_rgb_range(float p_x, float p_y, float p_z) { + auto is_in_range_inclusive = [](const float p_value, const float p_min, const float p_max) -> bool { + return (p_value >= p_min and p_value <= p_max); + }; + + auto [red, green, blue] = xyz_to_rgb_float(p_x, p_y, p_z); + + bool is_red_in_range = is_in_range_inclusive(red, 0.0F, 1.0F); + bool is_green_in_range = is_in_range_inclusive(green, 0.0F, 1.0F); + bool is_blue_in_range = is_in_range_inclusive(blue, 0.0F, 1.0F); + + return is_red_in_range and is_green_in_range and is_blue_in_range; +} + +bool is_cieluv_in_rgb_range(float p_l_star, float p_u_star, float p_v_star) { + auto [x, y, z] = cieluv_to_xyz(p_l_star, p_u_star, p_v_star); + + return is_xyz_in_rgb_range(x, y, z); +} + +bool is_cielchuv_in_rgb_range(float p_l_star, float p_c_star, float p_h_star) { + auto [l, u, v] = cielchuv_to_cieluv(p_l_star, p_c_star, p_h_star); + + return is_cieluv_in_rgb_range(l, u, v); +} + +std::tuple map_cielchuv_to_visible_color(float p_l_star, float p_c_star, float p_h_star) { + float c_star = p_c_star; + uint32_t count = 0U; + + while (not is_cielchuv_in_rgb_range(p_l_star, c_star, p_h_star)) { + c_star = c_star * 0.99F; + count = count + 1U; + + if (count > 1000U) { + c_star = 0.0F; + break; + } + } + + return {p_l_star, c_star, p_h_star}; +} + +std::tuple rgb_to_cielchuv(uint8_t p_red, uint8_t p_green, uint8_t p_blue) { + auto [x, y, z] = rgb_to_xyz(p_red, p_green, p_blue); + auto [l, u, v] = xyz_to_cieluv(x, y, z); + auto [l_star, c_star, h_star] = cieluv_to_cielchuv(l, u, v); + + return {l_star, c_star, h_star}; +} + +std::tuple cielchuv_to_rgb(float p_l_star, float p_c_star, float p_h_star) { + auto [l, u, v] = cielchuv_to_cieluv(p_l_star, p_c_star, p_h_star); + auto [x, y, z] = cieluv_to_xyz(l, u, v); + auto [red, green, blue] = xyz_to_rgb(x, y, z); + + return {red, green, blue}; +} diff --git a/src/display.cpp b/src/display.cpp new file mode 100644 index 0000000..a3b5fb5 --- /dev/null +++ b/src/display.cpp @@ -0,0 +1,328 @@ +#include "../include/color_conversion.hpp" +#include "../include/display.hpp" + +Display::Display(Adafruit_NeoPixel& p_leds) : m_leds(p_leds) { + m_precipitation_forecast_map = {11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + m_air_quality_forecast_map = {23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}; + m_max_pollen_map = 26; + m_max_air_qualilty_map = 24; + m_uvi_map = 27; + m_local_air_quality_map = 25; + m_wifi_status_map = 28; + m_brightness = 0.2F; + return; +} + +void Display::setPollenPlusAQIForecastLeds(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_pollen, + ArduinoJson::V710PB22::JsonArray p_aqi) { + std::vector merged_array = mergeJsonArraysFromTimestamp(p_current_time, p_aqi, p_pollen); + + if (merged_array.size() > m_air_quality_forecast_map.size()) { + uint32_t number_of_elements_to_erase = merged_array.size() - m_air_quality_forecast_map.size(); + + merged_array.erase(merged_array.end() - number_of_elements_to_erase, merged_array.end()); + } + + uint32_t index = 0; + for (float value : merged_array) { + setPixelToColorMappedValue(m_air_quality_forecast_map.at(index), value); + index++; + } + + float max_aqi = findMaxValueInTwelveHourInterval(p_current_time, p_aqi); + setPixelToColorMappedValue(m_max_air_qualilty_map, max_aqi); + + float max_pollen = findMaxValueInTwelveHourInterval(p_current_time, p_pollen); + setPixelToColorMappedValue(m_max_pollen_map, max_pollen); +} + +void Display::setPrecipitationForecastLeds(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_precipitation) { + float previous_value = mapPrecipitationToColorIndex(0.0f); + + uint32_t index = 0U; + for (JsonObject elem : p_precipitation) { + uint32_t time = elem["time"].as(); + float color_index = mapPrecipitationToColorIndex(elem["value"].as()); + + if ((index == 0U) and (time > p_current_time)) { + setPixelToColorMappedValue(m_precipitation_forecast_map.at(index), previous_value); + index = 1U; + } + + if (index > 0U) { + setPixelToColorMappedValue(m_precipitation_forecast_map.at(index), color_index); + index += 1U; + } + + previous_value = color_index; + + if (index >= m_precipitation_forecast_map.size()) { + break; + } + } +} + +void Display::setUVIForecastLed(uint32_t p_current_time, ArduinoJson::V710PB22::JsonArray p_uvi) { + for (JsonObject elem : p_uvi) { + uint32_t time = elem["time"].as(); + float value = elem["value"].as(); + + if (time > p_current_time) { + setPixelToColorMappedValue(m_uvi_map, value); + break; + } + } +} + +void Display::setLocalAirQualityLed(float p_iaq) { + float value = 0.0f; + + if (p_iaq <= 50.0f) { + value = 1.0f; // Excellent + } else if (p_iaq <= 100.0f) { + value = 2.0f; // Good + } else if (p_iaq <= 125.0f) { + value = 4.0f; + } else if (p_iaq <= 150.0f) { + value = 4.0f; // Lightly polluted + } else if (p_iaq <= 175.0f) { + value = 5.0f; + } else if (p_iaq <= 200.0f) { + value = 6.0f; // Moderately polluted + } else if (p_iaq <= 225.0f) { + value = 7.0f; + } else if (p_iaq <= 250.0f) { + value = 8.0f; // Heavily polluted + } else if (p_iaq <= 300.0f) { + value = 9.0f; + } else if (p_iaq <= 350.0f) { + value = 10.0f; // Severely polluted + } else { + value = 11.0f; // Extremely polluted + } + + setPixelToColorMappedValue(m_local_air_quality_map, value); +} + +void Display::setWifiStatusLed(bool p_is_connected) { + if (p_is_connected) { + m_leds.setPixelColor(m_wifi_status_map, m_leds.Color(0U, 0U, 255U, 255U)); + } else { + m_leds.setPixelColor(m_wifi_status_map, m_leds.Color(0U, 0U, 0U, 0U)); + } +} + +void Display::setErrorLed(bool p_is_error) { + if (p_is_error) { + m_leds.setPixelColor(m_wifi_status_map, m_leds.Color(255U, 0U, 0U, 0U)); + } else { + m_leds.setPixelColor(m_wifi_status_map, m_leds.Color(0U, 0U, 0U, 0U)); + } +} + +void Display::setPixelColor(uint32_t p_index, uint8_t p_red, uint8_t p_green, uint8_t p_blue, uint8_t p_white) { + m_leds.setPixelColor(p_index, m_leds.Color(p_red, p_green, p_blue, p_white)); +} + +void Display::setBrightness(float p_brightness) { + m_brightness = p_brightness; + return; +} + +void Display::clear() { + m_leds.clear(); + return; +} + +void Display::show() { + m_leds.show(); + return; +} + +float Display::findMaxValueInTwelveHourInterval(uint32_t p_time_stamp, ArduinoJson::V710PB22::JsonArray p_array) { + float max_value = 0.0f; + float previous_value = 0.0f; + + for (auto elem : p_array) { + uint32_t time = elem["time"].as(); + float value = elem["value"].as(); + constexpr uint32_t TWELVE_HOURS_IN_SECONDS = 12U * 60U * 60U; + + if ((time >= p_time_stamp) and (time < p_time_stamp + TWELVE_HOURS_IN_SECONDS)) { + max_value = std::max(max_value, previous_value); + } + + previous_value = value; + } + + return max_value; +} + +std::vector Display::mergeJsonArraysFromTimestamp(uint32_t p_time_stamp, + ArduinoJson::V710PB22::JsonArray p_array_a, + ArduinoJson::V710PB22::JsonArray p_array_b) { + uint32_t start_time_a = p_array_a[0]["time"].as(); + uint32_t start_time_b = p_array_b[0]["time"].as(); + + std::vector merged_array = {}; + + if (start_time_a <= start_time_b) { + merged_array = mergeJsonArraysFromTimestampHelper(p_time_stamp, p_array_a, p_array_b); + } else { + merged_array = mergeJsonArraysFromTimestampHelper(p_time_stamp, p_array_b, p_array_a); + } + + return merged_array; +} + +std::vector Display::mergeJsonArraysFromTimestampHelper(uint32_t p_time_stamp, + ArduinoJson::V710PB22::JsonArray p_array_a, + ArduinoJson::V710PB22::JsonArray p_array_b) { + // Assumption: time stamp in first element of p_array_a <= p_array_b + + std::vector merged_vector = {}; + size_t start_point_a = 0; + size_t start_point_b = 0; + + for (size_t index_a = start_point_a; index_a < p_array_a.size(); index_a++) { + uint32_t time_a = p_array_a[index_a]["time"].as(); + + if (time_a > p_time_stamp) { + if (index_a > 0) { + start_point_a = index_a - 1; + } else { + start_point_a = 0; + } + break; + } + } + + for (size_t index_a = start_point_a; index_a < p_array_a.size(); index_a++) { + uint32_t time_a = p_array_a[index_a]["time"].as(); + float value_a = p_array_a[index_a]["value"].as(); + + bool is_merged = false; + for (size_t index_b = start_point_b; index_b < p_array_b.size(); index_b++) { + uint32_t time_b = p_array_b[index_b]["time"].as(); + + if (time_b == time_a) { + float value_b = p_array_b[index_b]["value"].as(); + float merged_value = std::max(value_a, value_b); + + merged_vector.push_back(merged_value); + is_merged = true; + start_point_b = index_b + 1U; + break; + } + } + + if (not is_merged) { + merged_vector.push_back(value_a); + } + } + + for (size_t index_b = start_point_b; index_b < p_array_b.size(); index_b++) { + float value_b = p_array_b[index_b]["value"].as(); + merged_vector.push_back(value_b); + } + + return merged_vector; +} + +float Display::mapPrecipitationToColorIndex(const float p_rain_intensity) { + float color_index = 0.0f; + + if (p_rain_intensity < 0.1f) { + color_index = 0.0f; + } else if (p_rain_intensity < 0.22f) { + color_index = 1.0f; + } else if (p_rain_intensity < 0.47f) { + color_index = 2.0f; + } else if (p_rain_intensity < 1.0f) { + color_index = 3.0f; + } else if (p_rain_intensity < 2.2f) { + color_index = 4.0f; + } else if (p_rain_intensity < 4.7f) { + color_index = 5.0f; + } else if (p_rain_intensity < 10.0f) { + color_index = 6.0f; + } else if (p_rain_intensity < 22.0f) { + color_index = 7.0f; + } else if (p_rain_intensity < 47.0f) { + color_index = 8.0f; + } else if (p_rain_intensity < 100.0f) { + color_index = 9.0f; + } else if (p_rain_intensity < 220.0f) { + color_index = 10.0f; + } else { + color_index = 11.0f; + } + + return color_index; +} + +std::tuple Display::mapValueToColorRGB(float p_value) { + if (p_value < 1.0) { + return {0, 0, 0}; // black (good) + } else if (p_value < 2.0) { + return {0, 0, 160}; // blue (good) + } else if (p_value < 3.0) { + return {0, 255, 255}; // cyan (good) + } else if (p_value < 4.0) { + return {255, 255, 255}; // white (mediocre) + } else if (p_value < 5.0) { + return {200, 200, 32}; // light yellow (mediocre) + } else if (p_value < 6.0) { + return {120, 120, 0}; // yellow (mediocre) + } else if (p_value < 7.0) { + return {200, 80, 0}; // orange (inadequate) + } else if (p_value < 8.0) { + return {255, 50, 0}; // red-orange (inadequate) + } else if (p_value < 9.0) { + return {180, 0, 0}; // red (bad) + } else if (p_value < 10.0) { + return {200, 0, 160}; // magenta (bad) + } else { + return {60, 0, 210}; // purple (terrible) + } +} + +std::tuple Display::mapValueToColorRGBW(float p_value) { + if (p_value < 1.0) { + return {0, 0, 0, 0}; // black (good) + } else if (p_value < 2.0) { + return {0, 0, 255, 0}; // blue (good) + } else if (p_value < 3.0) { + return {0, 255, 255, 0}; // cyan (good) + } else if (p_value < 4.0) { + return {255, 255, 255, 0}; // white (mediocre) + } else if (p_value < 5.0) { + return {200, 200, 32, 0}; // light yellow (mediocre) + } else if (p_value < 6.0) { + return {120, 120, 0, 0}; // yellow (mediocre) + } else if (p_value < 7.0) { + return {200, 80, 0, 0}; // orange (inadequate) + } else if (p_value < 8.0) { + return {255, 50, 0, 0}; // red-orange (inadequate) + } else if (p_value < 9.0) { + return {180, 0, 0, 0}; // red (bad) + } else if (p_value < 10.0) { + return {200, 0, 160, 0}; // magenta (bad) + } else { + return {60, 0, 210, 0}; // purple (terrible) + } +} + +void Display::setPixelToColorMappedValue(uint8_t p_index, float p_value) { + auto [red, green, blue, white] = mapValueToColorRGBW(p_value); + + auto [l_star, c_star, h_star] = rgb_to_cielchuv(red, green, blue); + + l_star = l_star * m_brightness; + + auto [l_star_dimmed, c_star_dimmed, h_star_dimmed] = map_cielchuv_to_visible_color(l_star, c_star, h_star); + + auto [red_dimmed, green_dimmed, blue_dimmed] = cielchuv_to_rgb(l_star_dimmed, c_star_dimmed, h_star_dimmed); + + m_leds.setPixelColor(p_index, m_leds.Color(red_dimmed, green_dimmed, blue_dimmed, white)); +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b2a6929 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include "../include/backend_communication.hpp" +#include "../include/display.hpp" +#include "../include/sensor_manager.hpp" +#include "../include/wifi_handler.hpp" + +#ifndef LED_BUILTIN +#define LED_BUILTIN 2 +#endif + +#ifndef BUTTON_BUILTIN +#define BUTTON_BUILTIN 0 +#endif + +#define CONNECT_BUTTON BUTTON_BUILTIN + +// Forward function declarations +void wifiHandlerFeedbackCb(WiFiManager::Status p_wifi_status); + +// Global objects +DESPatch dESPatch; + +Adafruit_NeoPixel leds = Adafruit_NeoPixel(29, 14, NEO_GRBW + NEO_KHZ800); +Display display(leds); + +WifiHandler wifi_handler(wifiHandlerFeedbackCb); + +BackendCommunication backend_communication(wifi_handler); + +SensorManager sensor_manager; + +void wifiHandlerFeedbackCb(WiFiManager::Status p_wifi_status) { + static bool state = false; + + if (p_wifi_status.mode == WiFiManager::Mode::CONNECTED) { + state = true; + } else if (p_wifi_status.mode == WiFiManager::Mode::DISCONNECTED) { + state = false; + } else { + state = !state; + } + + display.setWifiStatusLed(state); + display.show(); +} + +void setup() { + display.clear(); + display.show(); + + Serial.begin(115200); + + pinMode(LED_BUILTIN, OUTPUT); + + wifi_handler.setBlinkRate(WifiHandler::BLINK_RATE_CONNECTING); + + pinMode(CONNECT_BUTTON, INPUT); + + if (CONNECT_BUTTON >= 0) { + // Give user 3 second chance to press button and reset settings + Serial.println(String(millis()) + " Waiting 3 seconds to check if user presses the button"); + delay(3000); + if (not digitalRead(CONNECT_BUTTON)) { + wifi_handler.resetSettings(); + } + } + + wifi_handler.connect(); + digitalWrite(LED_BUILTIN, LOW); + + const char url[] = + "https://apikey:cqprlgiafadnidsgeqozcpldkaeqimqw@despatch.luon.net/" + "files/4/despatch.json"; + unsigned long interval = 60; // By default check for updates every 60 seconds + + int x = dESPatch.configure(url, true, false, interval, false, root_ca); + + Serial.println(String(millis()) + " dESPatch.configure() returned with code " + String(x)); + + sensor_manager.setup(); +} + +void loop(void) { + sensor_manager.read(); + display.setLocalAirQualityLed(sensor_manager.data.static_iaq); + + if (backend_communication.update() == BackendCommunication::State::ERROR) { + display.setErrorLed(true); + Serial.println("Uptime: " + String(millis()) + ", backend error"); + } else { + uint32_t utc_time = backend_communication.m_weather_data["time"].as(); + Serial.println("Uptime: " + String(millis()) + ", UTC time: " + String(utc_time)); + + display.setPollenPlusAQIForecastLeds(utc_time, backend_communication.m_weather_data["pollen"].as(), + backend_communication.m_weather_data["AQI"].as()); + + display.setPrecipitationForecastLeds(utc_time, + backend_communication.m_weather_data["precipitation"].as()); + + display.setUVIForecastLed(utc_time, backend_communication.m_weather_data["UVI"].as()); + + display.setWifiStatusLed(false); + + display.setBrightness(backend_communication.m_config["brightness"].as()); + } + + display.show(); + + dESPatch.checkForUpdate(true); + + delay(1000U); +} diff --git a/src/root_ca.cpp b/src/root_ca.cpp new file mode 100644 index 0000000..c981279 --- /dev/null +++ b/src/root_ca.cpp @@ -0,0 +1,32 @@ +const char* root_ca = + "-----BEGIN CERTIFICATE-----\n" + "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" + "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" + "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" + "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" + "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" + "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" + "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" + "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" + "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" + "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" + "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" + "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" + "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" + "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" + "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" + "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" + "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" + "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" + "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" + "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" + "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" + "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" + "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" + "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" + "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" + "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" + "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" + "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" + "-----END CERTIFICATE-----\n"; diff --git a/src/sensor_manager.cpp b/src/sensor_manager.cpp new file mode 100644 index 0000000..0740c25 --- /dev/null +++ b/src/sensor_manager.cpp @@ -0,0 +1,113 @@ +#include + +#include "../include/sensor_manager.hpp" + +SensorManager::SensorManager() { + data = {}; + return; +} + +bool SensorManager::setup() { + SPI.begin(); + m_iaq_sensor.begin(BME_CS, SPI); + String output = "BSEC library version " + String(m_iaq_sensor.version.major) + "." + + String(m_iaq_sensor.version.minor) + "." + String(m_iaq_sensor.version.major_bugfix) + "." + + String(m_iaq_sensor.version.minor_bugfix); + Serial.println(output); + + if (not checkIaqSensorStatus()) { + return false; + } + + m_iaq_sensor.setConfig(BSEC_CONFIG_IAQ); + m_iaq_sensor.setTemperatureOffset(13.5f); + + if (not checkIaqSensorStatus()) { + return false; + } + + bsec_virtual_sensor_t sensorList[13] = {BSEC_OUTPUT_IAQ, + BSEC_OUTPUT_STATIC_IAQ, + BSEC_OUTPUT_CO2_EQUIVALENT, + BSEC_OUTPUT_BREATH_VOC_EQUIVALENT, + BSEC_OUTPUT_RAW_TEMPERATURE, + BSEC_OUTPUT_RAW_PRESSURE, + BSEC_OUTPUT_RAW_HUMIDITY, + BSEC_OUTPUT_RAW_GAS, + BSEC_OUTPUT_STABILIZATION_STATUS, + BSEC_OUTPUT_RUN_IN_STATUS, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY, + BSEC_OUTPUT_GAS_PERCENTAGE}; + + m_iaq_sensor.updateSubscription(sensorList, 13, BSEC_SAMPLE_RATE_LP); + + if (checkIaqSensorStatus()) { + return false; + } + + return true; +} + +bool SensorManager::read() { + uint32_t time = millis(); + + if ((m_next_call == 0) or (time < m_next_call)) { + return false; + } + + bool is_run_result_valid = m_iaq_sensor.run(); + bool is_sensor_status_valid = checkIaqSensorStatus(); + + if (is_run_result_valid and is_sensor_status_valid) { // If new data is available + data.iaq = m_iaq_sensor.iaq; + data.iaq_accuracy = m_iaq_sensor.iaqAccuracy; + data.static_iaq = m_iaq_sensor.staticIaq; + data.co2_equivalent = m_iaq_sensor.co2Equivalent; + data.breath_voc_equivalent = m_iaq_sensor.breathVocEquivalent; + data.raw_temperature = m_iaq_sensor.rawTemperature; + data.pressure = m_iaq_sensor.pressure; + data.raw_humidity = m_iaq_sensor.rawHumidity; + data.gas_resistance = m_iaq_sensor.gasResistance; + data.stab_status = m_iaq_sensor.stabStatus; + data.run_in_status = m_iaq_sensor.runInStatus; + data.temperature = m_iaq_sensor.temperature; + data.humidity = m_iaq_sensor.humidity; + data.gas_percentage = m_iaq_sensor.gasPercentage; + + m_next_call = static_cast(m_iaq_sensor.nextCall & 0xFFFFFFFF); + + Serial.println("Next call: " + String(m_next_call)); + return true; + } else { + return false; + } +} + +bool SensorManager::checkIaqSensorStatus() { + if (m_iaq_sensor.bsecStatus != BSEC_OK) { + if (m_iaq_sensor.bsecStatus < BSEC_OK) { + Serial.println("BSEC error code: " + String(m_iaq_sensor.bsecStatus)); + + return false; + } else { + Serial.println("BSEC warning code: " + String(m_iaq_sensor.bsecStatus)); + + return false; + } + } + + if (m_iaq_sensor.bme68xStatus != BME68X_OK) { + if (m_iaq_sensor.bme68xStatus < BME68X_OK) { + Serial.println("BME68X error code: " + String(m_iaq_sensor.bme68xStatus)); + + return false; + } else { + Serial.println("BME68X warning code: " + String(m_iaq_sensor.bme68xStatus)); + + return false; + } + } + + return true; +} \ No newline at end of file diff --git a/src/wifi_handler.cpp b/src/wifi_handler.cpp new file mode 100644 index 0000000..11b9ff0 --- /dev/null +++ b/src/wifi_handler.cpp @@ -0,0 +1,85 @@ +#include + +#include "../include/wifi_handler.hpp" + +static Ticker g_ticker; +static WiFiManager::Status g_wifi_status; +static std::function g_tickerCb = nullptr; + +WifiHandler::WifiHandler(std::function p_tickerCb) { + g_tickerCb = p_tickerCb; + return; +} + +static void tick() { + if (g_tickerCb != nullptr) { + g_tickerCb(g_wifi_status); + } +} + +void WifiHandler::setBlinkRate(float p_interval) { + if (g_ticker.active()) { + g_ticker.detach(); + } + + if (p_interval > 0.0f) { + g_ticker.attach(p_interval, tick); + } +} + +void WifiHandler::wifiManagerCb(WiFiManager::Status p_status) { + g_wifi_status = p_status; + + if (p_status.mode == WiFiManager::Mode::CONNECTING) { + WifiHandler::setBlinkRate(WifiHandler::BLINK_RATE_CONNECTING); + } else if (p_status.mode == WiFiManager::Mode::SCANNING) { + WifiHandler::setBlinkRate(WifiHandler::BLINK_RATE_CONNECTING); + } else if (p_status.mode == WiFiManager::Mode::PORTAL) { + WifiHandler::setBlinkRate(WifiHandler::BLINK_RATE_CONFIG); + } else if (p_status.mode == WiFiManager::Mode::ERASING) { + WifiHandler::setBlinkRate(WifiHandler::BLINK_RATE_ERASE); + } else if (p_status.mode == WiFiManager::Mode::CONNECTED) { + WifiHandler::setBlinkRate(0.0f); + g_tickerCb(g_wifi_status); + } else if (p_status.mode == WiFiManager::Mode::DISCONNECTED) { + WifiHandler::setBlinkRate(0.0f); + g_tickerCb(g_wifi_status); + } +} + +void WifiHandler::connect() { + Serial.begin(115200); + + m_wifiManager.configure("Claire", WifiHandler::wifiManagerCb); + + // fetches ssid and pass and tries to connect + // if it does not connect it starts an access point + // and goes into a blocking loop awaiting configuration + if (!m_wifiManager.autoConnect()) { + Serial.println(String(millis()) + " Failed to connect and hit timeout"); + // reset and try again, or maybe put it to deep sleep + ESP.restart(); + delay(1000); + } + + // if you get here you have connected to the WiFi + Serial.print(String(millis()) + " Connected with address: "); + Serial.println(WiFi.localIP()); +} + +void WifiHandler::resetSettings() { + WiFiManager::Status status = {.wifi_status = 0U, .mode = WiFiManager::Mode::ERASING}; + + Serial.println(String(millis()) + " Resetting wifi settings..."); + + wifiManagerCb(status); + m_wifiManager.resetSettings(); + delay(1000); + status.mode = WiFiManager::Mode::DISCONNECTED; + wifiManagerCb(status); +} + +String WifiHandler::getMac(bool p_insertColons) { + String mac = m_wifiManager.getMacAsString(p_insertColons); + return mac; +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html diff --git a/test/cieluv.cpp b/test/cieluv.cpp new file mode 100644 index 0000000..b4b2d4b --- /dev/null +++ b/test/cieluv.cpp @@ -0,0 +1,335 @@ +#include +#include +#include +#include +#include +#include + +std::tuple rgb_to_xyz(const uint8_t p_red, const uint8_t p_green, const uint8_t p_blue) { + auto normalize_uint8_t = [](const uint8_t p_value) -> float { + return std::min(static_cast(p_value) / 255.0F, 1.0F); + }; + + auto gamma_correction = [](const float p_value) -> float { + float gamma_corrected_value = 0.0F; + + if (p_value <= 0.0405F) { + gamma_corrected_value = p_value / 12.92F; + } else { + gamma_corrected_value = std::pow((p_value + 0.055F) / 1.055F, 2.4F); + } + + return gamma_corrected_value; + }; + + float red = gamma_correction(normalize_uint8_t(p_red)); + float green = gamma_correction(normalize_uint8_t(p_green)); + float blue = gamma_correction(normalize_uint8_t(p_blue)); + + float x = 0.4124564F * red + 0.3575761F * green + 0.1804375F * blue; + float y = 0.2126729F * red + 0.7151522F * green + 0.0721750F * blue; + float z = 0.0193339F * red + 0.1191920F * green + 0.9503041F * blue; + + return {x * 100.0F, y * 100.0F, z * 100.0F}; +} + +std::tuple xyz_to_rgb_float(float p_x, float p_y, float p_z) { + auto reverse_gamma_correction = [](const float p_value) -> float { + float reverse_gamma_corrected_value = 0.0F; + + if (p_value <= 0.0031308F) { + reverse_gamma_corrected_value = p_value * 12.92F; + } else { + reverse_gamma_corrected_value = std::pow(p_value, 1.0F / 2.4F) * 1.055F - 0.055F; + } + + return reverse_gamma_corrected_value; + }; + + auto clamp_if_within_error_margin = [](const float p_value) -> float { + float value = p_value; + constexpr float MARGIN = 0.001F; + + if ((p_value >= -MARGIN) and (p_value < 0.0F)) { + value = 0.0F; + } else if ((p_value <= 1.0F + MARGIN) and (p_value > 1.0F)) { + value = 1.0F; + } + + return value; + }; + + float red = 3.2404542F * p_x / 100.0F - 1.5371385F * p_y / 100.0F - 0.4985314F * p_z / 100.0F; + float green = -0.9692660F * p_x / 100.0F + 1.8760108F * p_y / 100.0F + 0.0415560F * p_z / 100.0F; + float blue = 0.0556434F * p_x / 100.0F - 0.2040259F * p_y / 100.0F + 1.0572252F * p_z / 100.0F; + + red = clamp_if_within_error_margin(reverse_gamma_correction(red)); + green = clamp_if_within_error_margin(reverse_gamma_correction(green)); + blue = clamp_if_within_error_margin(reverse_gamma_correction(blue)); + + return {red, green, blue}; +} + +std::tuple xyz_to_rgb(float p_x, float p_y, float p_z) { + auto uint8_t_scale = [](const float p_value) -> uint8_t { + return static_cast(std::clamp(p_value, 0.0F, 1.0F) * 255.0F + 0.5F); + }; + + auto [red, green, blue] = xyz_to_rgb_float(p_x, p_y, p_z); + + uint8_t red_uint8_t = uint8_t_scale(red); + uint8_t green_uint8_t = uint8_t_scale(green); + uint8_t blue_uint8_t = uint8_t_scale(blue); + + return {red_uint8_t, green_uint8_t, blue_uint8_t}; +} + +std::tuple xyz_to_uv(const float p_x, const float p_y, const float p_z) { + float denominator = (p_x + 15.0F * p_y + 3.0F * p_z); + + if (denominator == 0.0F) { + denominator = 1.0F; + } + + float u = (4.0F * p_x) / denominator; + float v = (9.0F * p_y) / denominator; + + return {u, v}; +} + +std::tuple uv_to_xy(const float p_u, const float p_v) { + float denominator = 6.0F * p_u - 16.0F * p_v + 12.0F; + + if (denominator == 0.0F) { + denominator = 1.0F; + } + + float x = 9.0F * p_u / denominator; + float y = 4.0F * p_v / denominator; + + return {x, y}; +} + +std::tuple xyz_d65_reference_white_point() { + // Standard D64 reference white point values + constexpr float X_N = 95.047F; + constexpr float Y_N = 100.0F; + constexpr float Z_N = 108.833F; + + return {X_N, Y_N, Z_N}; +} + +std::tuple xyz_to_cieluv(const float p_x, const float p_y, const float p_z) { + auto [X_N, Y_N, Z_N] = xyz_d65_reference_white_point(); + auto [U_N, V_N] = xyz_to_uv(X_N, Y_N, Z_N); + + auto [u, v] = xyz_to_uv(p_x, p_y, p_z); + + float l_star = 0.0F; + + if (p_y == 0.0F) { + l_star = 0.0F; + } else if ((p_y / Y_N) > 0.0088565F) { + l_star = 116.0F * std::cbrt(p_y / Y_N) - 16.0F; + } else { + l_star = p_y / Y_N * 903.3F; + } + + float u_star = 13.0F * l_star * (u - U_N); + float v_star = 13.0F * l_star * (v - V_N); + + return {l_star, u_star, v_star}; +} + +std::tuple cieluv_to_xyz(float p_l_star, float p_u_star, float p_v_star) { + auto [X_N, Y_N, Z_N] = xyz_d65_reference_white_point(); + auto [U_N, V_N] = xyz_to_uv(X_N, Y_N, Z_N); + + float denominator = 13.0F * p_l_star; + + if (denominator == 0.0F) { + denominator = 13.0F; + } + + float u = p_u_star / denominator + U_N; + float v = p_v_star / denominator + V_N; + + // auto [x, y] = uv_to_xy(u, v); + + float y = 0.0F; + if (p_l_star <= 8.0F) { + y = Y_N * p_l_star * 0.0011071F; + } else { + y = Y_N * std::pow((p_l_star + 16.F) / 116.0F, 3.0F); + } + + if (v == 0.0F) { + denominator = 4.0F; + } else { + denominator = 4.0F * v; + } + float x = y * 9.0F * u / denominator; + float z = y * (12.0F - 3.0F * u - 20.0F * v) / denominator; + + return {x, y, z}; +} + +std::tuple cieluv_to_cielchuv(float p_l_star, float p_u_star, float p_v_star) { + float c_star = std::sqrt(p_u_star * p_u_star + p_v_star * p_v_star); + float h_star = std::atan2(p_v_star, p_u_star); + + if (h_star < 0.0F) { + h_star += 2.0F * M_PI; + } + + return {p_l_star, c_star, h_star}; +} + +std::tuple cielchuv_to_cieluv(float p_l_star, float p_c_star, float p_h_star) { + float u_star = p_c_star * std::cos(p_h_star); + float v_star = p_c_star * std::sin(p_h_star); + + return {p_l_star, u_star, v_star}; +} + +bool is_xyz_in_rgb_range(float p_x, float p_y, float p_z) { + auto is_in_range_inclusive = [](const float p_value, const float p_min, const float p_max) -> bool { + return (p_value >= p_min and p_value <= p_max); + }; + + auto [red, green, blue] = xyz_to_rgb_float(p_x, p_y, p_z); + + bool is_red_in_range = is_in_range_inclusive(red, 0.0F, 1.0F); + bool is_green_in_range = is_in_range_inclusive(green, 0.0F, 1.0F); + bool is_blue_in_range = is_in_range_inclusive(blue, 0.0F, 1.0F); + + return is_red_in_range and is_green_in_range and is_blue_in_range; +} + +bool is_cieluv_in_rgb_range(float p_l_star, float p_u_star, float p_v_star) { + auto [x, y, z] = cieluv_to_xyz(p_l_star, p_u_star, p_v_star); + + return is_xyz_in_rgb_range(x, y, z); +} + +bool is_cielchuv_in_rgb_range(float p_l_star, float p_c_star, float p_h_star) { + auto [l, u, v] = cielchuv_to_cieluv(p_l_star, p_c_star, p_h_star); + + return is_cieluv_in_rgb_range(l, u, v); +} + +std::tuple map_cielchuv_to_visible_color(float p_l_star, float p_c_star, float p_h_star) { + float c_star = p_c_star; + uint32_t count = 0U; + + while (not is_cielchuv_in_rgb_range(p_l_star, c_star, p_h_star)) { + c_star = c_star * 0.99F; + count = count + 1U; + + if (count > 1000U) { + c_star = 0.0F; + std::cout << "breaky breaky!" << std::endl; + break; + } + } + + return {p_l_star, c_star, p_h_star}; +} + +std::tuple rgb_to_cielchuv(uint8_t p_red, uint8_t p_green, uint8_t p_blue) { + auto [x, y, z] = rgb_to_xyz(p_red, p_green, p_blue); + auto [l, u, v] = xyz_to_cieluv(x, y, z); + auto [l_star, c_star, h_star] = cieluv_to_cielchuv(l, u, v); + + return {l_star, c_star, h_star}; +} + +std::tuple cielchuv_to_rgb(float p_l_star, float p_c_star, float p_h_star) { + auto [l, u, v] = cielchuv_to_cieluv(p_l_star, p_c_star, p_h_star); + auto [x, y, z] = cieluv_to_xyz(l, u, v); + auto [red, green, blue] = xyz_to_rgb(x, y, z); + + return {red, green, blue}; +} + +int main(void) { + uint8_t r = 0; + uint8_t g = 0; + uint8_t b = 0; + + for (r = 0; r < 192; r = r + 64) { + for (g = 0; g < 192; g = g + 64) { + for (b = 0; b < 192; b = b + 64) { + auto [x, y, z] = rgb_to_xyz(r, g, b); + auto [l, u, v] = xyz_to_cieluv(x, y, z); + auto [x2, y2, z2] = cieluv_to_xyz(l, u, v); + auto [r2, g2, b2] = xyz_to_rgb(x2, y2, z2); + + std::cout << "RGB: [" + std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b) + "]" + + " --> XYZ: [" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + "]" + + " --> LUV: [" + std::to_string(l) + ", " + std::to_string(u) + ", " + std::to_string(v) + "]" + + " --> XYZ: [" + std::to_string(x2) + ", " + std::to_string(y2) + ", " + std::to_string(z2) + "]" + + " --> RGB: [" + std::to_string(r2) + ", " + std::to_string(g2) + ", " + std::to_string(b2) + "]" + + " --> E: [" + std::to_string(r - r2) + ", " + std::to_string(g - g2) + ", " + std::to_string(b - b2) + "]" << std::endl; + } + } + } + + std::cout << std::endl; + + for (r = 0; r < 192; r = r + 64) { + for (g = 0; g < 192; g = g + 64) { + for (b = 0; b < 192; b = b + 64) { + auto [x, y, z] = rgb_to_xyz(r, g, b); + auto [l, u, v] = xyz_to_cieluv(x, y, z); + auto [l_, c, h] = cieluv_to_cielchuv(l, u, v); + + auto [l2, c2, h2] = map_cielchuv_to_visible_color(l / 2.0F, c, h); + + auto [l2_, u2, v2] = cielchuv_to_cieluv(l2, c2, h2); + auto [x2, y2, z2] = cieluv_to_xyz(l2, u2, v2); + auto [r2_f, g2_f, b2_f] = xyz_to_rgb_float(x2, y2, z2); + auto [r2, g2, b2] = xyz_to_rgb(x2, y2, z2); + + std::cout << "RGB: [" + std::to_string(r) + ", " + std::to_string(g) + ", " + std::to_string(b) + "]" + + " --> XYZ: [" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + "]" + + " --> LUV: [" + std::to_string(l) + ", " + std::to_string(u) + ", " + std::to_string(v) + "]" + + " --> LCH: [" + std::to_string(l) + ", " + std::to_string(c) + ", " + std::to_string(h) + "]" + + " --> / 2: [" + std::to_string(l2) + ", " + std::to_string(c2) + ", " + std::to_string(h2) + "]" + + "; visible: " + std::to_string(is_cielchuv_in_rgb_range(l / 2.0F, c, h)) + + " / " + std::to_string(is_cielchuv_in_rgb_range(l2, c2, h2)) + + " --> LUV: [" + std::to_string(l2) + ", " + std::to_string(u2) + ", " + std::to_string(v2) + "]" + + " --> XYZ: [" + std::to_string(x2) + ", " + std::to_string(y2) + ", " + std::to_string(z2) + "]" + + " --> RGB: [" + std::to_string(r2_f) + ", " + std::to_string(g2_f) + ", " + std::to_string(b2_f) + "]" + + " --> RGB: [" + std::to_string(r2) + ", " + std::to_string(g2) + ", " + std::to_string(b2) + "]" << std::endl; + } + } + } + + // std::cout << std::endl; + + // float x = 0.925094F; + // float y = 0.370037F; + // float z = 4.872159F; + // auto [red, green, blue] = xyz_to_rgb_float(x, y, z); + // std::cout << std::to_string(red) + " " + std::to_string(green) + " " + std::to_string(blue) + " " + std::to_string(is_xyz_in_rgb_range(x, y, z)) << std::endl; + + // float x2 = 0.740333F; + // float y2 = 0.185027F; + // float z2 = 0.031254F; + // auto [red2, green2, blue2] = xyz_to_rgb_float(x2, y2, z2); + // std::cout << std::to_string(red2) + " " + std::to_string(green2) + " " + std::to_string(blue2) + " " + std::to_string(is_xyz_in_rgb_range(x2, y2, z2)) << std::endl; + + // // float L = 3.342548F; + // float L = 1.671274F; + // float C = 13.526361F; + // float H = 4.640314F; + // + // auto [L_, U, V] = cielchuv_to_cieluv(L, C, H); + // auto [X, Y, Z] = cieluv_to_xyz(L_, U, V); + // auto [R, G, B] = xyz_to_rgb_float(X, Y, Z); + // std::cout << "RGB: " << std::to_string(R) + " " + std::to_string(G) + " " + std::to_string(B) + + // ", XYZ: " + std::to_string(X) + " " + std::to_string(Y) + " " + std::to_string(Z) + + // ", LUV: " + std::to_string(L_) + " " + std::to_string(U) + " " + std::to_string(V) + + // " " + std::to_string(is_xyz_in_rgb_range(X, Y, Z)) << std::endl; +}