Compare commits

..

24 commits
V0.1.7 ... main

Author SHA1 Message Date
5ae78eddc1 Merge pull request 'Release v0.4.0: complete rewrite' (#1) from Plus-Claire into main
Reviewed-on: #1
2024-09-24 21:54:11 +02:00
f22d4c3d80 Added color-preserving dimming of display 2024-09-24 11:27:59 +02:00
7094d20eca Several improvements:
* Fix color mapping of precipitation
* Fix bug in calculation of max value of pollen / AQI
* Added update() method to backend which will only update after interval period has passed
2024-09-07 00:03:53 +02:00
09dc9805bc Added BME680 sensor 2024-09-01 22:10:53 +02:00
8dc11493aa Use NeoPixel led for wifi status 2024-09-01 16:50:16 +02:00
5cba98368f Fix merging pollen + AQI 2024-09-01 13:24:40 +02:00
60d91a5def Pass reference to NeoPixels to Display class. 2024-08-31 17:32:34 +02:00
3aecd54880 Added Display class; Neopixel is disabled for now 2024-08-30 21:08:34 +02:00
388bd0a84c Added classes for WifiHandler and BackendCommunication 2024-08-18 11:19:41 +02:00
a0dc2e257a Get config from server 2024-08-17 22:46:10 +02:00
48e071ef90 Update WIFIMANAGER-ESP32 and dESPatch libraries 2024-08-17 17:27:35 +02:00
93d5240443 Use LED_BUITIN and BUTTON_BUILTIN for user input/output + reset settings if user presses button within 3 seconds 2024-08-16 21:29:50 +02:00
c60c3ecb2d Detach ticker in right places, do not call reset settings for WifiManager 2024-08-08 22:54:33 +02:00
c04c4138a3 Setup PlatformIO project using WIFIMANAGER-ESP32 and dESPatch 2024-07-28 17:24:50 +02:00
b9f90c2db2 Update to latest libraries + use new root ca 2024-04-05 20:16:05 +02:00
f8d25822ce Fix indentation 2022-06-05 17:22:54 +02:00
2966bb7d84 Add workaround for wifi disconnect issue 2022-06-05 17:04:01 +02:00
87c76e945f Added a bit more logging 2022-06-04 10:37:23 +02:00
1ed29953fe Use https://sinoptik.luon.net and really close connections when doing http.end() 2022-05-27 20:48:58 +02:00
6c360d9473 Use 256 x oversampling to reduce noise on light sensor 2022-05-25 23:33:57 +02:00
e413703196 Make light sensor more sensitive 2022-05-25 23:04:20 +02:00
6926d35baf Read out light sensor 2022-05-24 22:42:44 +02:00
ba7906ad9f Set static temperature offset for BME680 + select correct configuration 2022-05-24 22:24:39 +02:00
25dd53116c Update IAQI colormap + fix led ordering for proto V1 2022-05-24 00:07:24 +02:00
25 changed files with 2396 additions and 932 deletions

4
.clang-format Normal file
View file

@ -0,0 +1,4 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 120

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.pio

521
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -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
}

10
.vscode/extensions.json vendored Normal file
View file

@ -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"
]
}

44
.vscode/launch.json vendored Normal file
View file

@ -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"
}
]
}

52
.vscode/settings.json vendored Normal file
View file

@ -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"
}
}

View file

@ -1,932 +0,0 @@
//#define DISABLE_WIFI
#define HW_PROTO_PAPER 1
#define HW_PROTO_V1 2
#include <WiFiManager.h> // https://github.com/admarschoonen/WiFiManager
#include <dESPatch.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>
#include "bsec.h"
#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;
#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);
#define SEALEVELPRESSURE_HPA (1013.25)
#define BME_CS 5
String output;
Bsec iaqSensor;
static HTTPClient http;
static const String baseUrlAQI = "http://target.luon.net:2356//forecast?&metrics=PAQI&metrics=AQI&metrics=pollen&metrics=UVI";
static const String baseUrlPrecipitation = "http://target.luon.net:2356//forecast?metrics=precipitation";
static int hw_variant = 0;
WiFiManager wifiManager;
DESPatch dESPatch;
const char* root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" \
"PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" \
"Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" \
"AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" \
"rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" \
"OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" \
"xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" \
"7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" \
"aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" \
"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" \
"SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" \
"ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" \
"AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" \
"R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" \
"JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" \
"Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\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<JsonArray>()) {
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<JsonArray>()) {
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<JsonArray>()) {
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<JsonArray>()) {
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<JsonArray>()) {
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)
{
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;
}
static void setup_pins_proto_v1(void)
{
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;
}
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.status != BSEC_OK) {
if (iaqSensor.status < BSEC_OK) {
output = "BSEC error code : " + String(iaqSensor.status);
Serial.println(output);
//for (;;);
} else {
output = "BSEC warning code : " + String(iaqSensor.status);
Serial.println(output);
}
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme680Status < BME680_OK) {
output = "BME680 error code : " + String(iaqSensor.bme680Status);
Serial.println(output);
//for (;;);
} else {
output = "BME680 warning code : " + String(iaqSensor.bme680Status);
Serial.println(output);
}
}
return iaqSensor.bme680Status;
}
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 += " ms, 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 += " %, IAQ static" + String(iaqSensor.staticIaq);
output += ", eCO2: " + String(iaqSensor.co2Equivalent);
output += " ppm, eVOC: " + String(iaqSensor.breathVocEquivalent);
output += " ppm";
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;
// sanity check delay - allows reprogramming if accidently blowing power w/leds
delay(2000);
Serial.begin(115200);
Serial.println("buienradarklok starting");
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 != BME680_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\""));
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.println(url);
http.begin(url);
httpCode = http.GET();
if (httpCode > 0) {
payload = http.getString();
parseJson(&payload);
} else {
Serial.print(__func__);
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.println(url);
http.begin(url);
httpCode = http.GET();
if (httpCode > 0) {
payload = http.getString();
parseJson(&payload);
} else {
Serial.print(__func__);
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.println(url);
http.begin(url);
httpCode = http.GET();
if (httpCode > 0) {
payload = http.getString();
parseJson(&payload);
} else {
Serial.print(__func__);
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.println(url);
http.begin(url);
httpCode = http.GET();
if (httpCode > 0) {
payload = http.getString();
parseJson(&payload);
} else {
Serial.print(__func__);
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.iaq;
if (iaqi <= 50.0f) {
x = 1.0f; // Excellent
} else if (iaqi <= 100.0f) {
x = 2.0f; // Good
} else if (iaqi <= 150.0f) {
x = 4.0f; // Lightly polluted
} else if (iaqi <= 200.0f) {
x = 7.0f; // Moderately polluted
} else if (iaqi <= 250.0f) {
x = 9.0f; // Heavily polluted
} 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(ledIdx, 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(ledIdx, 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);
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(ledIdx, 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
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
}

39
include/README Normal file
View file

@ -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

View file

@ -0,0 +1,53 @@
#ifndef __BACKEND_COMMUNICATION_HPP__
#define __BACKEND_COMMUNICATION_HPP__
#include <Arduino.h>
#include <ArduinoJson.h>
#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__

View file

@ -0,0 +1,24 @@
#ifndef __COLOR_CONVERSION_HPP__
#define __COLOR_CONVERSION_HPP__
#include <cstdint>
#include <tuple>
std::tuple<float, float, float> rgb_to_xyz(uint8_t p_red, uint8_t p_green, uint8_t p_blue);
std::tuple<uint8_t, uint8_t, uint8_t> xyz_to_rgb(float p_x, float p_y, float p_z);
std::tuple<float, float, float> xyz_to_cieluv(float p_x, float p_y, float p_z);
std::tuple<float, float, float> cieluv_to_xyz(float p_l_star, float p_u_star, float p_v_star);
std::tuple<float, float, float> cieluv_to_cielchuv(float p_l_star, float p_u_star, float p_v_star);
std::tuple<float, float, float> 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<float, float, float> map_cielchuv_to_visible_color(float p_l_star, float p_c_star, float p_h_star);
std::tuple<float, float, float> rgb_to_cielchuv(uint8_t p_red, uint8_t p_green, uint8_t p_blue);
std::tuple<uint8_t, uint8_t, uint8_t> cielchuv_to_rgb(float p_l_star, float p_c_star, float p_h_star);
#endif // __COLOR_CONVERSION_HPP__

58
include/display.hpp Normal file
View file

@ -0,0 +1,58 @@
#ifndef __DISPLAY_HPP__
#define __DISPLAY_HPP__
#include <Adafruit_NeoPixel.h>
#include <Arduino.h>
#include <ArduinoJson.h>
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<float> mergeJsonArraysFromTimestamp(uint32_t p_time_stamp, ArduinoJson::V710PB22::JsonArray p_array_a,
ArduinoJson::V710PB22::JsonArray p_array_b);
std::vector<float> 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<uint8_t, uint8_t, uint8_t> mapValueToColorRGB(float p_value);
std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> 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<uint8_t, 12U> m_precipitation_forecast_map;
std::array<uint8_t, 12U> 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__

6
include/root_ca.hpp Normal file
View file

@ -0,0 +1,6 @@
#ifndef __ROOT_CA_H__
#define __ROOT_CA_H__
extern const char* root_ca;
#endif // __ROOT_CA_H__

View file

@ -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__

33
include/wifi_handler.hpp Normal file
View file

@ -0,0 +1,33 @@
#ifndef __WIFI_HANDLER_HPP__
#define __WIFI_HANDLER_HPP__
#include <WiFiManager-esp32.h> // https://github.com/admarschoonen/WiFiManager
class WifiHandler {
public:
// Constructor
WifiHandler(std::function<void(WiFiManager::Status p_wifi_status)> 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__

46
lib/README Normal file
View file

@ -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 <Foo.h>
#include <Bar.h>
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

22
platformio.ini Normal file
View file

@ -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

View file

@ -0,0 +1,163 @@
#include <HTTPClient.h>
#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<int32_t>(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;
}

248
src/color_conversion.cpp Normal file
View file

@ -0,0 +1,248 @@
#include <algorithm>
#include <cmath>
#include "../include/color_conversion.hpp"
std::tuple<float, float, float> 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<float>(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<float, float, float> 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<uint8_t, uint8_t, uint8_t> 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<uint8_t>(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<float, float> 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<float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<uint8_t, uint8_t, uint8_t> 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};
}

328
src/display.cpp Normal file
View file

@ -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<float> 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<uint32_t>();
float color_index = mapPrecipitationToColorIndex(elem["value"].as<float>());
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<uint32_t>();
float value = elem["value"].as<float>();
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<uint32_t>();
float value = elem["value"].as<float>();
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<float> 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>();
uint32_t start_time_b = p_array_b[0]["time"].as<uint32_t>();
std::vector<float> 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<float> 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<float> 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<uint32_t>();
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<uint32_t>();
float value_a = p_array_a[index_a]["value"].as<float>();
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<uint32_t>();
if (time_b == time_a) {
float value_b = p_array_b[index_b]["value"].as<float>();
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<float>();
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<uint8_t, uint8_t, uint8_t> 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<uint8_t, uint8_t, uint8_t, uint8_t> 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));
}

114
src/main.cpp Normal file
View file

@ -0,0 +1,114 @@
#include <Adafruit_NeoPixel.h>
#include <dESPatch.h>
#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<JsonInteger>();
Serial.println("Uptime: " + String(millis()) + ", UTC time: " + String(utc_time));
display.setPollenPlusAQIForecastLeds(utc_time, backend_communication.m_weather_data["pollen"].as<JsonArray>(),
backend_communication.m_weather_data["AQI"].as<JsonArray>());
display.setPrecipitationForecastLeds(utc_time,
backend_communication.m_weather_data["precipitation"].as<JsonArray>());
display.setUVIForecastLed(utc_time, backend_communication.m_weather_data["UVI"].as<JsonArray>());
display.setWifiStatusLed(false);
display.setBrightness(backend_communication.m_config["brightness"].as<JsonFloat>());
}
display.show();
dESPatch.checkForUpdate(true);
delay(1000U);
}

32
src/root_ca.cpp Normal file
View file

@ -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";

113
src/sensor_manager.cpp Normal file
View file

@ -0,0 +1,113 @@
#include <cstdint>
#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<uint32_t>(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;
}

85
src/wifi_handler.cpp Normal file
View file

@ -0,0 +1,85 @@
#include <Ticker.h>
#include "../include/wifi_handler.hpp"
static Ticker g_ticker;
static WiFiManager::Status g_wifi_status;
static std::function<void(WiFiManager::Status p_wifi_status)> g_tickerCb = nullptr;
WifiHandler::WifiHandler(std::function<void(WiFiManager::Status p_wifi_status)> 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;
}

11
test/README Normal file
View file

@ -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

335
test/cieluv.cpp Normal file
View file

@ -0,0 +1,335 @@
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <tuple>
#include <iostream>
#include <utility>
std::tuple<float, float, float> 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<float>(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<float, float, float> 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<uint8_t, uint8_t, uint8_t> 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<uint8_t>(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<float, float> 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<float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<float, float, float> 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<uint8_t, uint8_t, uint8_t> 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;
}