Pith - aquarium_weather
aquarium_weather/aquarium_weather_arduino.ino [9.9 kb]
Modified: 17:31:29 58 026 (16 May 026)
14 Days Ago
// 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));
  }
}
Updates
Shim - Android 70.026.1
Wedge - Linux 68.026.1
Wedge - Android 68.026.1
Taper - Linux 64.026.1
Ayh Extension - Chrome 63.026.1
Dev
TVShow (227) 'CSA'
TVShow (228) 'APT'
TVProgram (83) 'BXT'
Miter Update(s)
Shim (Dictation)

Menu
Calendar
Project Tin (024/029)
Miter
RSS Feed
User Avatar
@vgmlr
=SUM(parts)