feat: brightness scaling depending on photoresistor value
This commit is contained in:
parent
b872de9d25
commit
009025f858
2 changed files with 236 additions and 62 deletions
|
@ -17,6 +17,7 @@ lib_deps =
|
|||
bblanchon/ArduinoJson@^7.1.0
|
||||
sstaub/NTP@^1.6
|
||||
tzapu/WiFiManager@^2.0.17
|
||||
khoih-prog/ESP32_C3_TimerInterrupt@^1.8.0
|
||||
build_flags =
|
||||
-D ARDUINO_USB_MODE=1
|
||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
|
|
@ -6,16 +6,29 @@
|
|||
#include <NTP.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESP32_C3_TimerInterrupt.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
|
||||
#include "spacemap.h"
|
||||
|
||||
#define WS2812_PIN 0
|
||||
#define WS2812_LEN (sizeof(spaces)/sizeof(char*))
|
||||
#define WS2812_BS 5
|
||||
|
||||
#define SPACEAPI_HOST "api.spaceapi.io"
|
||||
#define SPACEAPI_PORT 443
|
||||
#define SPACEAPI_PATH "/"
|
||||
|
||||
#define BOOT_READ_PIN 5
|
||||
#define BOOT_GND_PIN 6
|
||||
|
||||
#define BRIGHTNESS_PIN 3
|
||||
#define DEFAULT_BRIGHTNESS_THRESH_LOWER 1000
|
||||
#define DEFAULT_BRIGHTNESS_THRESH_UPPER 400
|
||||
#define DEFAULT_BRIGHTNESS_MIN 10
|
||||
#define DEFAULT_BRIGHTNESS_MAX 10
|
||||
|
||||
|
||||
WiFiManager wifiManager;
|
||||
WiFiClientSecure client;
|
||||
|
@ -24,9 +37,96 @@ NTP ntp(wifiUdp);
|
|||
|
||||
Adafruit_NeoPixel pixels(WS2812_LEN, WS2812_PIN, NEO_RGB | NEO_KHZ800);
|
||||
JsonDocument json, filter;
|
||||
DeserializationError error = DeserializationError::EmptyInput;
|
||||
ESP32Timer ITimer0(0);
|
||||
|
||||
volatile bool wmp_needs_config_save;
|
||||
volatile bool timerExpired;
|
||||
|
||||
enum SpaceState {
|
||||
Closed,
|
||||
Open,
|
||||
Invalid,
|
||||
Outdated,
|
||||
};
|
||||
|
||||
|
||||
const uint8_t config_version = 2;
|
||||
struct __attribute__ ((packed)) Config {
|
||||
uint8_t version;
|
||||
uint16_t brightness_thresh_lower;
|
||||
uint16_t brightness_thresh_upper;
|
||||
uint16_t brightness_min;
|
||||
uint16_t brightness_max;
|
||||
} spiffs_config;
|
||||
|
||||
SpaceState states[WS2812_LEN];
|
||||
|
||||
bool timer0_isr(void *data) {
|
||||
timerExpired = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeConfig() {
|
||||
File f = SPIFFS.open("/spaceapi.bin", FILE_WRITE);
|
||||
f.write((uint8_t *) &spiffs_config, sizeof(spiffs_config));
|
||||
f.close();
|
||||
Serial.println("Wrote config to SPIFFS:/spaceapi.bin");
|
||||
}
|
||||
|
||||
void writeDefaultConfig() {
|
||||
spiffs_config.version = config_version;
|
||||
spiffs_config.brightness_thresh_lower = DEFAULT_BRIGHTNESS_THRESH_LOWER;
|
||||
spiffs_config.brightness_thresh_upper = DEFAULT_BRIGHTNESS_THRESH_UPPER;
|
||||
spiffs_config.brightness_min = DEFAULT_BRIGHTNESS_MIN;
|
||||
spiffs_config.brightness_max = DEFAULT_BRIGHTNESS_MAX;
|
||||
writeConfig();
|
||||
}
|
||||
|
||||
void loadConfig() {
|
||||
Serial.println("Loading config from SPIFFS:/spaceapi.bin");
|
||||
File f = SPIFFS.open("/spaceapi.bin", FILE_READ);
|
||||
if (!f) {
|
||||
writeDefaultConfig();
|
||||
f = SPIFFS.open("/spaceapi.bin", FILE_READ);
|
||||
}
|
||||
f.read((uint8_t *) &spiffs_config.version, sizeof(spiffs_config.version));
|
||||
if (spiffs_config.version != config_version) {
|
||||
f.close();
|
||||
writeDefaultConfig();
|
||||
f = SPIFFS.open("/spaceapi.bin", FILE_READ);
|
||||
}
|
||||
f.seek(0);
|
||||
f.read((uint8_t *) &spiffs_config, sizeof(spiffs_config));
|
||||
f.close();
|
||||
Serial.println("Loaded config from SPIFFS:/spaceapi.bin");
|
||||
Serial.print(" version: ");
|
||||
Serial.println(spiffs_config.version);
|
||||
Serial.print(" brightness_thresh_lower: ");
|
||||
Serial.println(spiffs_config.brightness_thresh_lower);
|
||||
Serial.print(" brightness_thresh_upper: ");
|
||||
Serial.println(spiffs_config.brightness_thresh_upper);
|
||||
Serial.print(" brightness_min: ");
|
||||
Serial.println(spiffs_config.brightness_min);
|
||||
Serial.print(" brightness_max: ");
|
||||
Serial.println(spiffs_config.brightness_max);
|
||||
}
|
||||
|
||||
void wmp_save_config_callback() {
|
||||
wmp_needs_config_save = true;
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(BOOT_READ_PIN, INPUT_PULLUP);
|
||||
pinMode(BOOT_GND_PIN, OUTPUT);
|
||||
digitalWrite(BOOT_GND_PIN, LOW);
|
||||
if (!SPIFFS.begin(true)) {
|
||||
Serial.println("SPIFFS mount failed");
|
||||
return;
|
||||
}
|
||||
loadConfig();
|
||||
|
||||
pixels.begin();
|
||||
pixels.clear();
|
||||
|
@ -39,9 +139,36 @@ void setup() {
|
|||
wifiManager.setDebugOutput(true);
|
||||
wifiManager.setConnectTimeout(60);
|
||||
wifiManager.setConfigPortalTimeout(300);
|
||||
if (!wifiManager.autoConnect("spaceapimap", "12345678")) {
|
||||
ESP.restart();
|
||||
while (true);
|
||||
wifiManager.setSaveConfigCallback(wmp_save_config_callback);
|
||||
wmp_needs_config_save = false;
|
||||
|
||||
WiFiManagerParameter wmp_brightness_thresh_lower("brightness_thresh_lower", "Lights out at ", String(spiffs_config.brightness_thresh_lower).c_str(), 6);
|
||||
wifiManager.addParameter(&wmp_brightness_thresh_lower);
|
||||
WiFiManagerParameter wmp_brightness_thresh_upper("brightness_thresh_upper", "Max brightness at ", String(spiffs_config.brightness_thresh_upper).c_str(), 6);
|
||||
wifiManager.addParameter(&wmp_brightness_thresh_upper);
|
||||
WiFiManagerParameter wmp_brightness_min("brightness_min", "Min brightness ", String(spiffs_config.brightness_min).c_str(), 4);
|
||||
wifiManager.addParameter(&wmp_brightness_min);
|
||||
WiFiManagerParameter wmp_brightness_max("brightness_max", "Max brightness (Warning: Too high might blow fuses) ", String(spiffs_config.brightness_max).c_str(), 4);
|
||||
wifiManager.addParameter(&wmp_brightness_max);
|
||||
|
||||
if (!digitalRead(BOOT_READ_PIN)) {
|
||||
if (!wifiManager.startConfigPortal("spaceapimap", "12345678")) {
|
||||
ESP.restart();
|
||||
while (true);
|
||||
}
|
||||
} else {
|
||||
if (!wifiManager.autoConnect("spaceapimap", "12345678")) {
|
||||
ESP.restart();
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
|
||||
if (wmp_needs_config_save) {
|
||||
spiffs_config.brightness_thresh_lower = atol(wmp_brightness_thresh_lower.getValue());
|
||||
spiffs_config.brightness_thresh_upper = atol(wmp_brightness_thresh_upper.getValue());
|
||||
spiffs_config.brightness_min = atol(wmp_brightness_min.getValue());
|
||||
spiffs_config.brightness_max = atol(wmp_brightness_max.getValue());
|
||||
writeConfig();
|
||||
}
|
||||
|
||||
ntp.begin();
|
||||
|
@ -51,74 +178,120 @@ void setup() {
|
|||
filter[0]["lastSeen"] = true;
|
||||
filter[0]["data"]["state"]["open"] = true;
|
||||
filter[0]["data"]["state"]["lastchange"] = true;
|
||||
|
||||
analogSetPinAttenuation(BRIGHTNESS_PIN, ADC_11db);
|
||||
ITimer0.attachInterruptInterval(300 * 1000 * 1000, timer0_isr);
|
||||
timerExpired = true;
|
||||
memset(states, 0, sizeof(uint8_t) * WS2812_LEN);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint32_t color0 = pixels.getPixelColor(0);
|
||||
pixels.setPixelColor(0, color0);
|
||||
|
||||
ntp.update();
|
||||
Serial.println(ntp.formattedTime("\nIt is %d.%m.%Y %H:%M UTC"));
|
||||
time_t now = ntp.epoch();
|
||||
Serial.println("Starting connection to server...");
|
||||
client.setInsecure();
|
||||
if (!client.connect(SPACEAPI_HOST, SPACEAPI_PORT)) {
|
||||
Serial.println("Connection failed!");
|
||||
} else {
|
||||
Serial.println("Connected to server!");
|
||||
client.print("GET ");
|
||||
client.print(SPACEAPI_PATH);
|
||||
client.println(" HTTP/1.0");
|
||||
client.print("Host: ");
|
||||
client.println(SPACEAPI_HOST);
|
||||
client.println("Connection: close");
|
||||
client.println();
|
||||
if (timerExpired) {
|
||||
timerExpired = false;
|
||||
Serial.println("Timer expired!");
|
||||
ntp.update();
|
||||
now = ntp.epoch();
|
||||
Serial.println(ntp.formattedTime("\nIt is %d.%m.%Y %H:%M UTC"));
|
||||
Serial.println("Starting connection to server...");
|
||||
client.setInsecure();
|
||||
if (!client.connect(SPACEAPI_HOST, SPACEAPI_PORT)) {
|
||||
Serial.println("Connection failed!");
|
||||
} else {
|
||||
Serial.println("Connected to server!");
|
||||
client.print("GET ");
|
||||
client.print(SPACEAPI_PATH);
|
||||
client.println(" HTTP/1.0");
|
||||
client.print("Host: ");
|
||||
client.println(SPACEAPI_HOST);
|
||||
client.println("Connection: close");
|
||||
client.println();
|
||||
|
||||
while (client.readStringUntil('\n') != "\r");
|
||||
}
|
||||
DeserializationError error = deserializeJson(json, client, DeserializationOption::Filter(filter));
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.f_str());
|
||||
} else {
|
||||
pixels.clear();
|
||||
for (uint16_t i = 0; i < json.size(); ++i) {
|
||||
int16_t pi = -1;
|
||||
for (uint16_t j = 0; j < WS2812_LEN; ++j) {
|
||||
if (spaces[j] == json[i]["url"]) {
|
||||
pi = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pi < 0) {
|
||||
continue;
|
||||
}
|
||||
if (json[i]["data"] == nullptr || json[i]["data"]["state"] == nullptr || json[i]["data"]["state"]["open"] == nullptr || !json[i]["data"]["state"]["open"].is<bool>()) {
|
||||
pixels.setPixelColor(pi, pixels.Color(WS2812_BS*2, WS2812_BS, 0));
|
||||
Serial.println(": invalid!");
|
||||
} else {
|
||||
Serial.print(spaces[pi]);
|
||||
time_t last = json[i]["lastSeen"].as<time_t>();
|
||||
time_t last2 = last;
|
||||
if (json[i]["data"]["state"]["lastchange"] != nullptr) {
|
||||
last2 = json[i]["data"]["state"]["lastchange"].as<time_t>();
|
||||
}
|
||||
if (now - last > 24*3600) {
|
||||
pixels.setPixelColor(pi, pixels.Color(0, 0, WS2812_BS*2));
|
||||
Serial.println(": outdated!");
|
||||
} else {
|
||||
if (json[i]["data"]["state"]["open"].as<bool>()) {
|
||||
pixels.setPixelColor(pi, pixels.Color(0, WS2812_BS*2, 0));
|
||||
Serial.println(": open");
|
||||
} else {
|
||||
pixels.setPixelColor(pi, pixels.Color(WS2812_BS*2, 0, 0));
|
||||
Serial.println(": closed");
|
||||
while (client.readStringUntil('\n') != "\r");
|
||||
}
|
||||
error = deserializeJson(json, client, DeserializationOption::Filter(filter));
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.f_str());
|
||||
} else {
|
||||
for (uint16_t i = 0; i < json.size(); ++i) {
|
||||
int16_t pi = -1;
|
||||
for (uint16_t j = 0; j < WS2812_LEN; ++j) {
|
||||
if (spaces[j] == json[i]["url"]) {
|
||||
pi = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pi < 0) {
|
||||
continue;
|
||||
}
|
||||
if (json[i]["data"] == nullptr || json[i]["data"]["state"] == nullptr || json[i]["data"]["state"]["open"] == nullptr || !json[i]["data"]["state"]["open"].is<bool>()) {
|
||||
states[pi] = SpaceState::Invalid;
|
||||
Serial.println(": invalid!");
|
||||
} else {
|
||||
Serial.print(spaces[pi]);
|
||||
time_t last = json[i]["lastSeen"].as<time_t>();
|
||||
time_t last2 = last;
|
||||
if (json[i]["data"]["state"]["lastchange"] != nullptr) {
|
||||
last2 = json[i]["data"]["state"]["lastchange"].as<time_t>();
|
||||
}
|
||||
if (now - last > 24*3600) {
|
||||
states[pi] = SpaceState::Outdated;
|
||||
Serial.println(": outdated!");
|
||||
} else {
|
||||
if (json[i]["data"]["state"]["open"].as<bool>()) {
|
||||
states[pi] = SpaceState::Open;
|
||||
Serial.println(": open");
|
||||
} else {
|
||||
states[pi] = SpaceState::Closed;
|
||||
Serial.println(": closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
client.stop();
|
||||
} // endif timerExpired
|
||||
|
||||
if (!error) {
|
||||
uint16_t brightness = analogRead(BRIGHTNESS_PIN);
|
||||
Serial.print("brightness: ");
|
||||
Serial.print(brightness);
|
||||
pixels.clear();
|
||||
if (brightness < spiffs_config.brightness_thresh_lower) {
|
||||
uint16_t clamped = min(max(brightness, spiffs_config.brightness_thresh_upper), spiffs_config.brightness_thresh_lower);
|
||||
uint8_t power = spiffs_config.brightness_min + (spiffs_config.brightness_max - spiffs_config.brightness_min) * pow(1.0f * (spiffs_config.brightness_thresh_lower - clamped) / (spiffs_config.brightness_thresh_lower - spiffs_config.brightness_thresh_upper), 2);
|
||||
Serial.print(", clamped: ");
|
||||
Serial.print(clamped);
|
||||
Serial.print(", power: ");
|
||||
Serial.println(power);
|
||||
// safeguard!
|
||||
if (power > spiffs_config.brightness_max) {
|
||||
power = spiffs_config.brightness_max;
|
||||
}
|
||||
//power = 10;
|
||||
for (uint16_t i = 0; i < WS2812_LEN; ++i) {
|
||||
switch(states[i]) {
|
||||
case SpaceState::Closed:
|
||||
pixels.setPixelColor(i, pixels.Color(power, 0, 0));
|
||||
break;
|
||||
case SpaceState::Open:
|
||||
pixels.setPixelColor(i, pixels.Color(0, power, 0));
|
||||
break;
|
||||
case SpaceState::Invalid:
|
||||
pixels.setPixelColor(i, pixels.Color(power, power/2, 0));
|
||||
break;
|
||||
case SpaceState::Outdated:
|
||||
pixels.setPixelColor(i, pixels.Color(0, 0, power));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pixels.show();
|
||||
Serial.println();
|
||||
}
|
||||
client.stop();
|
||||
delay(300 * 1000);
|
||||
delay(10);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue