// Aquarium Weather
// vgmlr
// Arduino Code
#include "VarSpeedServo.h"
#include "FastLED.h"
#include "SoftwareSerial.h"
// Serial
SoftwareSerial com(5, 6); // Rx, Tx
// Light
VarSpeedServo light_servo;
const int light_servo_pin = 2;
const int light_dimmer = A0; // 0-255
// Cloud
VarSpeedServo cloud_servo;
const int cloud_servo_pin = 3;
// Pump
const int pump = A1; // 0-255
// lever switch kills power to pump
const int tank_level = 16;
// Lightning (Neopixels)
// FastLED Lightning --> James Bruce
// Tip: Actually 20 but 50+ Spreads Effect
#define NUM_LEDS 50
#define DATA_PIN 4
CRGB leds[NUM_LEDS];
// Valves
VarSpeedServo rain_valve_servo;
const int rain_valve = 7;
VarSpeedServo snow_valve_servo;
const int snow_valve = 8;
VarSpeedServo tank_valve_servo;
const int tank_valve = 9;
// Snow
VarSpeedServo snow_maker_servo;
const int snow_maker = 10;
const int snow = 11;
// Fog
const int fog = 12;
// Wind (meters/sec)
const int fan = A3; // 0-255
// Values
String rec; // Weather Data
String last; // Saved Weather
const int off = 0; // MOSFET Controllers OFF
const int top = 255; // Peak
const int start = 0; // light + cloud
const int middle = 65; // light + cloud
const int full = 130; // light + cloud
String light_percent;
String cloud_percent;
String wind_speed; // m/s
String event;
int light_value;
int cloud_value;
int wind_value;
int event_value;
int light_pos;
int light_mos;
int cloud_pos;
int wind_pos;
unsigned long who;
unsigned long what;
unsigned long when;
int tank_level_state;
int tide_state = 0;
void setup() {
Serial.begin(9600);
com.begin(9600);
// Declare and Set Defaults
// Light
light_servo.attach(light_servo_pin);
light_servo.write(0, 80, false);
pinMode(light_dimmer, OUTPUT);
analogWrite(light_dimmer, off);
// Cloud
cloud_servo.attach(cloud_servo_pin);
cloud_servo.write(130, 80, false);
// Rain
rain_valve_servo.attach(rain_valve);
rain_valve_servo.write(0, 80, false);
// Snow
snow_valve_servo.attach(snow_valve);
snow_valve_servo.write(0, 80, false);
pinMode(snow, OUTPUT);
digitalWrite(snow, LOW);
// Pump
tank_valve_servo.attach(tank_valve);
tank_valve_servo.write(0, 80, true);
pinMode(pump, OUTPUT);
digitalWrite(pump, off);
pinMode(tank_level, INPUT);
// Fog
pinMode(fog, OUTPUT);
digitalWrite(fog, LOW);
// Lightning
FastLED.addLeds< WS2812B, DATA_PIN, GRB >(leds, NUM_LEDS);
// Wind
pinMode(fan, OUTPUT);
analogWrite(fan, off);
}
void loop() {
// Clean House
com.flush();
// Wait for Serial from NodeMCU
while (!com.available()) {
; // do nothing
}
// What did they say?!
rec = com.readString();
Serial.println(rec);
// Check if string is 10 characters
// 0000000000
if (rec.length() != 10) {
// Check if different than last data
if (rec != last) {
// Process Data
// 000-000-000-0
// 1 Light %
// 2 Cloud %
// 3 Wind Speed
// 4 Event
// Parse Light
light_percent = rec.substring(0, 2);
light_value = light_percent.toInt();
Serial.println(light_value);
// Parse Cloud
cloud_percent = rec.substring(3, 5);
cloud_value = cloud_percent.toInt();
Serial.println(cloud_value);
// Parse Wind
wind_speed = rec.substring(6, 8);
wind_value = wind_speed.toInt();
Serial.println(wind_value);
// Parse Event
event = rec.substring(9, 9);
event_value = event.toInt();
Serial.println(event_value);
// Fire Functions
light_okay();
cloud_what();
tide();
wind_sure();
event_dunno();
// Save Last Data
last = String(rec);
} else {
// Status Quo
light_okay();
cloud_what();
tide();
wind_sure();
event_dunno();
} // parse and event call
} // if not 10 characters
} // loop
void light_okay() {
// 130 = East 0 = West
light_pos = map(light_value, 0, 100, 130, 0);
light_servo.write(light_pos, 80, true);
// Sunrise and Sunset
if (light_pos > 115) {
light_mos = map(light_pos, 130, 115, 0, 255);
analogWrite(light_dimmer, light_mos);
} if (light_pos < 15) {
light_mos = map(light_pos, 15, 0, 255, 0);
analogWrite(light_dimmer, light_mos);
} else {
analogWrite(light_dimmer, 255);
}
}
void cloud_what() {
if (event_value == 7) {
// if clear --> position opposite after 50% light
if (light_pos < 50) {
cloud_servo.write(start, 80, true);
} else if (light_pos >= 50) {
cloud_servo.write(full, 80, true);
}
} else if (event_value == 6) {
// if clouds then position percent
// then percent relative to light position
// 65 = 100%
if (light_pos < 50) {
cloud_pos = map(cloud_value, 0, 100, 130, 65);
cloud_servo.write(cloud_pos, 80, true);
} else if (light_pos >= 50) {
cloud_pos = map(cloud_value, 0, 100, 0, 65);
cloud_servo.write(cloud_pos, 80, true);
}
} else {
// if event then cloud at peak
cloud_servo.write(middle, 80, true);
}
}
void wind_sure() {
// m/s to percent-ish
// 15 m/s = 33.6 mph
if (wind_value <= 15) {
wind_pos = map(wind_value, 0, 15, 0, 255);
analogWrite(fan, wind_pos);
} else if (wind_value > 15) {
analogWrite(fan, 255);
}
}
void event_dunno() {
if (event_value == 1) {
thunderstorm_boom();
} else if (event_value == 2) {
drizzle_fizz();
} else if (event_value == 3) {
rain_game();
} else if (event_value == 4) {
snow_man();
} else if (event_value == 5) {
fog_bottom();
}
}
void tide() {
// Every 6 Hours Change
// Uses Arduino Active As Time
// This is cheating! No data!
// get time since program began
when = millis();
// first time or time reset?
if (what < 1000) {
what = when;
// no action
} else {
// math difference
who = when - what;
// is it 6 hours ago?
if (who >= 21600000) {
// low or high tide?
// 0 = high tide 1 = low tide
if (tide_state == 0) {
// open tank valve
tank_valve_servo.write(90, 80, true);
delay(1000);
while (tank_level_state == LOW) {
digitalWrite(pump, HIGH);
// check float level
tank_level_state = digitalRead(tank_level);
}
digitalWrite(pump, LOW);
tank_valve_servo.write(0, 80, true);
tide_state = 1;
what = when;
} else if (tide_state == 1) {
// open tank valve to dump tank
tank_valve_servo.write(90, 80, true);
delay(20000); // adj
tank_valve_servo.write(0, 80, true);
tide_state = 0;
what = when;
}
}
}
}
void thunderstorm_boom() {
// open rain valve
analogWrite(light_dimmer, 120);
rain_valve_servo.write(90, 80, true);
delay(1000);
// let it pour
for (int x = 0; x < 25; x++) {
digitalWrite(pump, HIGH);
// call lightning for delay
for (int bolt = 0; bolt < 10; bolt++) {
lightning();
delay(500);
}
digitalWrite(pump, LOW);
// lightning again (so smart!)
for (int bolt = 0; bolt < 10; bolt++) {
lightning();
delay(500);
}
}
rain_valve_servo.write(0, 80, true);
digitalWrite(pump, LOW);
}
void drizzle_fizz() {
analogWrite(light_dimmer, 120);
// open rain valve
rain_valve_servo.write(90, 80, true);
delay(1000);
// less than rain
for (int x = 0; x < 20; x++) {
digitalWrite(pump, HIGH);
delay(3000);
digitalWrite(pump, LOW);
delay(6000);
}
rain_valve_servo.write(0, 80, true);
digitalWrite(pump, LOW);
}
void rain_game() {
analogWrite(light_dimmer, 120);
// open rain valve
rain_valve_servo.write(90, 80, true);
delay(1000);
// let it pour
for (int x = 0; x < 20; x++) {
digitalWrite(pump, HIGH);
delay(5000);
digitalWrite(pump, LOW);
delay(5000);
}
rain_valve_servo.write(0, 80, true);
digitalWrite(pump, LOW);
}
// This requires tweaking!
void snow_man() {
analogWrite(light_dimmer, 120);
// relay peltier elements + fan (2)
digitalWrite(snow, HIGH);
delay(5000);
// open snow valve
snow_valve_servo.write(90, 80, true);
delay(1000);
for (int redundant = 0; redundant = 50; redundant++) {
// intermittent pump (drip)
for (int x = 0; x < 20; x++) {
digitalWrite(pump, HIGH);
delay(3000);
digitalWrite(pump, LOW);
delay(5000);
}
// grate the snow
for (int y = 0; y < 10; y++) {
snow_maker_servo.write(45, 100, true);
delay(500);
snow_maker_servo.write(0, 100, true);
delay(500);
}
}
digitalWrite(snow, LOW);
digitalWrite(pump, LOW);
snow_valve_servo.write(0, 80, true);
}
void fog_bottom() {
analogWrite(light_dimmer, 120);
// turn on fog maker (relay)
digitalWrite(fog, HIGH);
// run for 60 seconds
delay(60000);
digitalWrite(fog, LOW);
// return
}
void lightning() {
switch (random(1, 3)) {
case 1:
thunderburst();
delay(random(10, 500));
break;
case 2:
rolling();
break;
case 3:
crack();
delay(random(50, 250));
break;
}
}
void reset() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV( 0, 0, 0);
}
FastLED.show();
}
void rolling() {
for (int r = 0; r < random(2, 10); r++) {
for (int i = 0; i < NUM_LEDS; i++) {
if (random(0, 100) > 90) {
leds[i] = CHSV( 0, 0, 255);
}
else {
leds[i] = CHSV(0, 0, 0);
}
}
FastLED.show();
delay(random(5, 100));
reset();
}
}
void crack() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV( 0, 0, 255);
}
FastLED.show();
delay(random(10, 100));
reset();
}
void thunderburst() {
int rs1 = random(0, NUM_LEDS / 2);
int rl1 = random(10, 20);
int rs2 = random(rs1 + rl1, NUM_LEDS);
int rl2 = random(10, 20);
for (int r = 0; r < random(3, 6); r++) {
for (int i = 0; i < rl1; i++) {
leds[i + rs1] = CHSV( 0, 0, 255);
}
if (rs2 + rl2 < NUM_LEDS) {
for (int i = 0; i < rl2; i++) {
leds[i + rs2] = CHSV( 0, 0, 255);
}
}
FastLED.show();
delay(random(10, 50));
reset();
delay(random(10, 50));
}
}