diff --git a/Lighting.cpp b/Lighting.cpp new file mode 100644 index 0000000..150a186 --- /dev/null +++ b/Lighting.cpp @@ -0,0 +1,55 @@ +#include "Lighting.h" +#include + +#define MAX_HEAT_INDEX 240.0 + +Lighting::Lighting(int ledCount, NaturalLight* naturalLight, Weather* weather, float cloudCoverLimit) { + _ledCount = ledCount; + _naturalLight = naturalLight; + _weather = weather; + _cloudCoverLimit = cloudCoverLimit; + + _leds = CRGB(_ledCount); +} + +float Lighting::getIndexMultiplier(int now, int startTime, int endTime, bool swap) { + float a = swap ? endTime - now : now - startTime; + float b = endTime - startTime; + return constrain(a / b, 0, 1); +} + +float Lighting::getHeatIndex(int now) { + float indexMultiplier = now >= _naturalLight->getSunset() + ? getIndexMultiplier(now, _naturalLight->getSunset(), _naturalLight->getAstronomicalTwilightEnd(), true) + : getIndexMultiplier(now, _naturalLight->getAstronomicalTwilightBegin(), _naturalLight->getSunrise(), false); + return MAX_HEAT_INDEX * indexMultiplier; +} + +float Lighting::getBrightness() { + float cloudCover = (float)_weather->getCloudCover() / 100.0; + float multiplier = cloudCover * (_cloudCoverLimit / 100.0); + if (_weather->getCondition() == WeatherCondition::Other) + multiplier *= 2.0; + return 255.0 - (multiplier * 255.0); +} + +void Lighting::update(int now) { + _heatIndex = getHeatIndex(now); + _brightness = getBrightness(); + + CRGB colour = ColorFromPalette(_sunrise, _heatIndex, _brightness, LINEARBLEND); + + if (_weather->getCondition() == WeatherCondition::Thunder && millis() >= _nextLightningFlash) { + int flashes = random8(2, 8); + for (int i = 0; i < flashes; i++) { + FastLED.showColor(CRGB::White); + delay(random8(10, 20)); + FastLED.showColor(colour); + delay(random8(40, 80)); + } + _nextLightningFlash = millis() + (random8(1, 60) * 1000); + } + + fill_solid(&_leds, _ledCount, colour); + FastLED.show(); +} \ No newline at end of file diff --git a/Lighting.h b/Lighting.h new file mode 100644 index 0000000..b1c1c98 --- /dev/null +++ b/Lighting.h @@ -0,0 +1,38 @@ +#include +#include "NaturalLight.h" +#include "Weather.h" + +DEFINE_GRADIENT_PALETTE(_sunrise_p) { + 0, 0, 0, 0, + 128, 255, 128, 0, + 224, 255, 255, 0, + 240, 255, 255, 255, // Hack to get around LINEARBLEND problem (for now, hopefully) + 255, 255, 255, 2552 +}; + +class Lighting { + int _ledCount; + NaturalLight* _naturalLight; + Weather* _weather; + float _cloudCoverLimit; + CRGB _leds; + CRGBPalette16 _sunrise = _sunrise_p; + long _nextLightningFlash = 0; + float _heatIndex; + float _brightness; + + float _currentHeatIndex(); + float getIndexMultiplier(int now, int startTime, int endTime, bool swap); + float getHeatIndex(int time); + float getBrightness(); + + public: + Lighting(int ledCount, NaturalLight* _naturalLight, Weather* _weather, float cloudCoverLimit); + + template void setup() { + FastLED.addLeds(&_leds, _ledCount).setCorrection(TypicalSMD5050).setTemperature(Tungsten40W); + } + void update(int time); + float getCurrentHeatIndex() { return _heatIndex; } + float getCurrentBrightness() { return _brightness; } +}; \ No newline at end of file diff --git a/NaturalLight.h b/NaturalLight.h index 149c142..9cd1ab9 100644 --- a/NaturalLight.h +++ b/NaturalLight.h @@ -1,5 +1,5 @@ -#ifndef _DAYLIGHT_h -#define _DAYLIGHT_h +#ifndef NaturalLight_h +#define NaturalLight_h #include #define SOLAR_EVENT_URL "http://api.sunrise-sunset.org/json?lat=%s&lng=%s&formatted=0" diff --git a/Weather.h b/Weather.h index 23ef4ad..88b5aff 100644 --- a/Weather.h +++ b/Weather.h @@ -1,3 +1,5 @@ +#ifndef Weather_h +#define Weather_h #include #define WEATHER_URL "http://api.openweathermap.org/data/2.5/weather?lat=%s&lon=%s&appid=%s" @@ -22,4 +24,5 @@ class Weather{ void update(); int getCloudCover() { return _cloudCover; } WeatherCondition getCondition() { return _condition; } -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/monitor.ino b/monitor.ino index ac2e9f4..87ff171 100644 --- a/monitor.ino +++ b/monitor.ino @@ -11,21 +11,20 @@ #define MQTT_SERVER "192.168.1.3" #define SSID "GCHQ Surveillance Van" #define PASSWORD "cocklol." -#define LIGHT_PIN D2 -#define LED_COUNT 36 #define PH_TOPIC "/home/sensors/fishtank/ph" #define TEMPERATURE_TOPIC "/home/sensors/fishtank/temperature" #define TEMPERATURE_PIN D5 +#define LED_PIN D2 +#define LED_COUNT 36 #define LATITUDE "20.548103" #define LONGITUDE "96.916835" #define TIMEZONE_OFFSET 27000 // 7.5 hours in seconds #define LIGHT_INDEX_TOPIC "/home/sensors/fishtank/lightindex" #define BRIGHTNESS_TOPIC "/home/sensors/fishtank/brightness" +#define CLOUD_COVER_LIMIT 50.0 // percent; #define NTP_POOL "uk.pool.ntp.org" -#define MAX_HEAT_INDEX 240.0 -#define CLOUD_COVER_LIMIT 50.0 // percent; void mqttCallback(char *topic, byte *payload, unsigned int length); @@ -35,17 +34,7 @@ PubSubClient _mqttClient = PubSubClient(MQTT_SERVER, 1883, mqttCallback, _wifiCl Sensors _sensors = Sensors(TEMPERATURE_PIN, TEMPERATURE_TOPIC, PH_TOPIC, _mqttClient); NaturalLight _naturalLight = NaturalLight(LATITUDE, LONGITUDE, TIMEZONE_OFFSET); Weather _weather = Weather(LATITUDE, LONGITUDE); - -CRGB _leds[LED_COUNT]; -long _nextLightningFlash = 0; -DEFINE_GRADIENT_PALETTE(_sunrise_p){ - 0, 0, 0, 0, - 128, 255, 128, 0, - 224, 255, 255, 0, - 240, 255, 255, 255, // Hack to get around LINEARBLEND problem (for now, hopefully) - 255, 255, 255, 255 -}; -CRGBPalette16 _sunrise = _sunrise_p; +Lighting _lighting = Lighting(LED_COUNT, &_naturalLight, &_weather, CLOUD_COVER_LIMIT); void waitForWiFi() { if (WiFi.status() == WL_CONNECTED) @@ -90,30 +79,7 @@ void setup() { _naturalLight.update(); _weather.update(); - - FastLED.addLeds(_leds, LED_COUNT).setCorrection(TypicalSMD5050).setTemperature(Tungsten40W); -} - -float getIndexMultiplier(int now, int startTime, int endTime, bool swap){ - float a = swap ? endTime - now : now - startTime; - float b = endTime - startTime; - return constrain(a / b, 0, 1); -} - -float getHeatIndex() { - time_t now = time(nullptr); - float indexMultiplier = now >= _naturalLight.getSunset() ? - getIndexMultiplier(now, _naturalLight.getSunset(), _naturalLight.getAstronomicalTwilightEnd(), true) : - getIndexMultiplier(now, _naturalLight.getAstronomicalTwilightBegin(), _naturalLight.getSunrise(), false); - return MAX_HEAT_INDEX * indexMultiplier; -} - -float getBrightness(){ - float cloudCover = (float)_weather.getCloudCover() / 100.0; - float multiplier = cloudCover * (CLOUD_COVER_LIMIT / 100.0); - if (_weather.getCondition() == WeatherCondition::Other) - multiplier *= 2.0; - return 255.0 - (multiplier * 255.0); + _lighting.setup(); } void publishFloat(char* topic, float value){ @@ -132,27 +98,9 @@ void doLighting() { } EVERY_N_SECONDS(1) { - float index = getHeatIndex(); - float brightness = getBrightness(); - - publishFloat(LIGHT_INDEX_TOPIC, index); - publishFloat(BRIGHTNESS_TOPIC, brightness); - - CRGB colour = ColorFromPalette(_sunrise, index, brightness, LINEARBLEND); - - if (_weather.getCondition() == WeatherCondition::Thunder && millis() >= _nextLightningFlash) { - int flashes = random8(2, 8); - for (int i = 0; i < flashes; i++) { - FastLED.showColor(CRGB::White); - delay(random8(10, 20)); - FastLED.showColor(colour); - delay(random8(40, 80)); - } - _nextLightningFlash = millis() + (random8(1, 60) * 1000); - } - - fill_solid(_leds, LED_COUNT, colour); - FastLED.show(); + _lighting.update(time(nullptr)); + publishFloat(LIGHT_INDEX_TOPIC, _lighting.getCurrentHeatIndex()); + publishFloat(BRIGHTNESS_TOPIC, _lighting.getCurrentBrightness()); } } diff --git a/sensors.h b/sensors.h index bae7f59..e709653 100644 --- a/sensors.h +++ b/sensors.h @@ -1,3 +1,5 @@ +#ifndef Sensors_h +#define Sensors_h #include #include #include @@ -23,4 +25,5 @@ class Sensors { float readpH(); void publishpH(); void publishTemperature(); -}; \ No newline at end of file +}; +#endif \ No newline at end of file