Claire/Claire.ino

834 lines
23 KiB
Arduino
Raw Normal View History

2022-04-22 21:20:37 +02:00
//#define DISABLE_WIFI
2022-05-20 23:08:36 +02:00
#define HW_PROTO_PAPER 1
#define HW_PROTO_V1 2
2022-04-22 21:20:37 +02:00
#include <WiFiManager.h> // https://github.com/admarschoonen/WiFiManager
#include <dESPatch.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>
2022-05-21 10:28:59 +02:00
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
//#include "bsec.h"
#define NUM_LEDS_PROTO_PAPER 93
#define DATA_PIN_PROTO_PAPER 5
#define NUM_LEDS_PROTO_V1 29
#define DATA_PIN_PROTO_V1 14
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;
2022-04-22 21:20:37 +02:00
#define SHOW_AQI_LED
#define SHOW_POLLEN_LED
#define SHOW_UVI_LED
#define MIN(x, y) (((x) <= (y)) ? (x) : (y))
2022-05-21 10:28:59 +02:00
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
Adafruit_BME680 bme(BME_CS); // hardware SPI
//SPIClass SPI1(HSPI);
//Bsec iaqSensor;
2022-04-22 21:20:37 +02:00
static HTTPClient http;
static const String baseUrlAQI = "http://target.luon.net:2356//forecast?&metrics=PAQI&metrics=AQI&metrics=pollen&metrics=UVI";
2022-04-22 21:20:37 +02:00
static const String baseUrlPrecipitation = "http://target.luon.net:2356//forecast?metrics=precipitation";
2022-05-21 10:28:59 +02:00
static int hw_variant = 0;
2022-04-22 21:20:37 +02:00
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.51831326813842, 4.451744264773111}; // Bandeliersberg, Roosendaal
//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;
2022-05-15 07:45:31 +02:00
long time;
2022-04-22 21:20:37 +02:00
RainPickerDataArray24 PAQI;
RainPickerDataArray24 AQI;
RainPickerDataArray24 pollen;
2022-04-22 21:20:37 +02:00
RainPickerDataArray5 UVI;
RainPickerDataArray24 precipitation;
} RainpickerData;
RainpickerData rainpickerData;
StaticJsonDocument<6144> doc;
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;
}
2022-05-15 07:45:31 +02:00
2022-04-22 21:20:37 +02:00
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;
}
}
2022-05-21 10:28:59 +02:00
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
}
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
}
2022-04-22 21:20:37 +02:00
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);
2022-05-21 10:28:59 +02:00
2022-04-22 21:20:37 +02:00
Serial.begin(115200);
Serial.println("buienradarklok starting");
2022-05-21 10:28:59 +02:00
if (!bme.begin()) {
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\""));
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
hw_variant = HW_PROTO_V1;
setup_pins_proto_v1();
leds_rgbw_proto_v1.begin(); // INITIALIZE NeoPixel strip object
}
//SPI1.begin();
//iaqSensor.begin(BME_CS, SPI1);
//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);
2022-04-22 21:20:37 +02:00
#ifndef DISABLE_WIFI
//wifiManager.resetSettings();
wifiManager.configure("clairvoyance-", true, LED_BUILTIN, true, BUTTON_BUILTIN, 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());
2022-05-21 10:28:59 +02:00
if (hw_variant == HW_PROTO_PAPER) {
//keep LED on
digitalWrite(LED_BUILTIN, LED_ON_VALUE_DEFAULT);
}
2022-04-22 21:20:37 +02:00
x = dESPatch.configure(url, true, false, interval, false, root_ca);
Serial.print("dESPatch.configure() returned with code ");
Serial.println(x);
#endif
}
// 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
2022-05-21 10:28:59 +02:00
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)
}
2022-04-22 21:20:37 +02:00
} 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;
}
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;
}
2022-05-20 23:08:36 +02:00
static void updateLedsNoWifi(void) {
uint32_t ledIdx;
uint32_t ledCount;
uint32_t color;
int r, g, b, w, n;
2022-05-21 10:28:59 +02:00
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);
leds_rgb_proto_paper.setPixelColor(ledIdx, leds_rgb_proto_paper.Color(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;
leds_rgbw_proto_v1.setPixelColor(ledIdx, leds_rgbw_proto_v1.Color(g, r, b, w));
ledIdx = ledIdx + PAQI_SKIP_LED + 1;
}
}
2022-05-20 23:08:36 +02:00
}
2022-04-22 21:20:37 +02:00
static void updateLeds(void) {
uint32_t ledIdx;
uint32_t ledCount;
uint32_t color;
2022-05-21 10:28:59 +02:00
int r, g, b, w, n;
2022-04-22 21:20:37 +02:00
// 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);
2022-05-21 10:28:59 +02:00
w = (color & 0xFF000000) >> 24;
2022-04-22 21:20:37 +02:00
2022-05-21 10:28:59 +02:00
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));
}
2022-04-22 21:20:37 +02:00
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);
2022-05-21 10:28:59 +02:00
w = (color & 0xFF000000) >> 24;
2022-04-22 21:20:37 +02:00
2022-05-21 10:28:59 +02:00
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));
}
2022-04-22 21:20:37 +02:00
}
#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);
2022-04-22 21:20:37 +02:00
r = (color & 0xFF0000) >> 16;
g = (color & 0x00FF00) >> 8;
b = (color & 0x0000FF);
2022-05-21 10:28:59 +02:00
if (hw_variant == HW_PROTO_PAPER) {
leds_rgb_proto_paper.setPixelColor(AQI_LED, leds_rgb_proto_paper.Color(r, g, b));
} else if (hw_variant == HW_PROTO_V1) {
leds_rgbw_proto_v1.setPixelColor(AQI_LED, leds_rgbw_proto_v1.Color(g, r, b, w));
}
2022-04-22 21:20:37 +02:00
#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);
2022-04-22 21:20:37 +02:00
r = (color & 0xFF0000) >> 16;
g = (color & 0x00FF00) >> 8;
b = (color & 0x0000FF);
2022-05-21 10:28:59 +02:00
if (hw_variant == HW_PROTO_PAPER) {
leds_rgb_proto_paper.setPixelColor(POLLEN_LED, leds_rgb_proto_paper.Color(r, g, b));
} else if (hw_variant == HW_PROTO_V1) {
leds_rgbw_proto_v1.setPixelColor(POLLEN_LED, leds_rgbw_proto_v1.Color(g, r, b, w));
}
2022-04-22 21:20:37 +02:00
#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);
2022-05-21 10:28:59 +02:00
if (hw_variant == HW_PROTO_PAPER) {
leds_rgb_proto_paper.setPixelColor(UVI_LED, leds_rgb_proto_paper.Color(r, g, b));
} else if (hw_variant == HW_PROTO_V1) {
leds_rgbw_proto_v1.setPixelColor(UVI_LED, leds_rgbw_proto_v1.Color(g, r, b, w));
}
2022-04-22 21:20:37 +02:00
#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);
2022-05-21 10:28:59 +02:00
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));
}
}
if (hw_variant == HW_PROTO_PAPER) {
leds_rgb_proto_paper.setPixelColor(IAQI_LED, leds_rgb_proto_paper.Color(r, g, b));
} else if (hw_variant == HW_PROTO_V1) {
leds_rgbw_proto_v1.setPixelColor(IAQI_LED, leds_rgbw_proto_v1.Color(g, r, b, w));
}
}
void readSensors(void) {
if (hw_variant == HW_PROTO_PAPER) {
return;
}
// Tell BME680 to begin measurement.
unsigned long endTime = bme.beginReading();
if (endTime == 0) {
Serial.println(F("Failed to begin reading :("));
return;
}
Serial.print(F("Reading started at "));
Serial.print(millis());
Serial.print(F(" and will finish at "));
Serial.println(endTime);
Serial.println(F("You can do other work during BME680 measurement."));
delay(50); // This represents parallel work.
// There's no need to delay() until millis() >= endTime: bme.endReading()
// takes care of that. It's okay for parallel work to take longer than
// BME680's measurement time.
// Obtain measurement results from BME680. Note that this operation isn't
// instantaneous even if milli() >= endTime due to I2C/SPI latency.
if (!bme.endReading()) {
Serial.println(F("Failed to complete reading :("));
return;
2022-04-22 21:20:37 +02:00
}
2022-05-21 10:28:59 +02:00
Serial.print(F("Reading completed at "));
Serial.println(millis());
Serial.print(F("Temperature = "));
Serial.print(bme.temperature);
Serial.println(F(" *C"));
Serial.print(F("Pressure = "));
Serial.print(bme.pressure / 100.0);
Serial.println(F(" hPa"));
Serial.print(F("Humidity = "));
Serial.print(bme.humidity);
Serial.println(F(" %"));
2022-04-22 21:20:37 +02:00
2022-05-21 10:28:59 +02:00
Serial.print(F("Gas = "));
Serial.print(bme.gas_resistance / 1000.0);
Serial.println(F(" KOhms"));
Serial.print(F("Approx. Altitude = "));
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(F(" m"));
Serial.println();
delay(2000);
2022-04-22 21:20:37 +02:00
}
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
2022-05-21 10:28:59 +02:00
if (hw_variant == HW_PROTO_PAPER) {
leds_rgb_proto_paper.show();
} else if (hw_variant == HW_PROTO_V1) {
leds_rgbw_proto_v1.show();
}
readSensors();
2022-04-22 21:20:37 +02:00
delay(100);
#ifndef DISABLE_WIFI
dESPatch.checkForUpdate(true);
#endif
}