/*  BATTERY CUTOUT

   Measures an analogue value and converts it to a voltage based on the values R1 and R2 of the voltage divider.
   If the voltage exceeds the cutout, the relay output is set high and the LED illuminated green.
   The cutout value is able to be adjusted via reading a second analogue input.
   Pressing the button causes the cutout voltage then the measured voltage to be displayed.  Cutout in red, voltage
   in blue.  A series of flashes is used to represent each number with a short flash being zero.
*/

#include <FastLED.h>

// Define voltage variables and voltage divider
float input_voltage = 0.0;
float input_value = 0.0;
float cutout_voltage;
const float r2 = 15000.0;
const float r1 = 47000.0;

// Define input/output pins
const int voltage_measure = A2;
const int cutout_measure = A1;
const int button = 0;
const int LED = 1;
const int relay = 3;

// Define indicator LED
CRGB leds[1];

void setup()
{
  // initialise digital I/O
  pinMode(button, INPUT_PULLUP);
  pinMode(relay, OUTPUT);

  // initialise LED
  FastLED.addLeds<WS2812B, LED, GRB>(leds, 1);  // my LEDs use GRB rather than RGB, change as required
  LEDS.setBrightness (100);
  leds[1] = CRGB::Black;
  FastLED.show();

  //  Serial.begin(9600);     //  opens serial port, sets data rate to 9600 bps
}

void output_voltage (float value, CRGB colour)
{
  const int pause = 600;
  const int flash = 300;
  int temp = value * 100;  // multiply by 100 to account for 2 decimal places
  int output [3];  // array to hold deserialised number

  leds[0] = CRGB::Black;   // turn off indicator LED
  LEDS.setBrightness (150);  // increase intensity
  FastLED.show();
  delay (pause);

  for (int i = 3; i >= 0; i--) {  // break voltage into individual values
    output[i] = temp % 10;        // and store in array
    temp /= 10;
  }

  for (int i = 0; i <= 3; i++) {  // step through the value and flash each value
    if (output[i] == 0) {   // use a quick flash to indicate a zero
      leds[0] = colour;
      FastLED.show();
      delay (flash / 3);
      leds[0] = CRGB::Black;
      FastLED.show();
      delay (flash);
    }
    else {
      for (int x = 1; x <= output[i]; x++) {  // use a number of slower flashers to indicate value
        leds[0] = colour;
        FastLED.show();
        delay (flash);
        leds[0] = CRGB::Black;
        FastLED.show();
        delay (flash);
      }
    }
    delay (pause);
  }
  LEDS.setBrightness (100);
}

void loop()
{
  int analogvalue = analogRead(voltage_measure);  // read the analogue voltage input
  input_value = (analogvalue * 5.0) / 1023.0;     // convert input into a 5v reference value
  input_voltage = input_value * ((r1 + r2) / r2);  // convert according to voltage divider used
  //  Serial.print("v= ");
  //  Serial.println(input_voltage);
  delay(300);

  float raw_cutout = analogRead(cutout_measure);   // read the analogue cutout input
  cutout_voltage = 12 + (raw_cutout / 1023);       // add to a base value of 12 to get a cutout in the range of 12 - 13v
  //  Serial.print("c= ");
  //  Serial.print(cutout_voltage);

  if (input_voltage > cutout_voltage + 0.2) {   // The input voltage should be a little higher than the cutout to prevent toggling
    leds[0] = CRGB::Green;                       // indicate cutout is exceeded
    FastLED.show();
    digitalWrite (relay, HIGH);                  // switch the relay on
  }
  if (input_voltage < cutout_voltage) {
    leds[0] = CRGB::Black;                       // indicate the voltage is low
    FastLED.show();
    digitalWrite (relay, LOW);                   // switch the relay off
  }

  if (digitalRead (button) == false) {
    output_voltage(cutout_voltage, CRGB::Red);   // output the cutout value in red
    output_voltage(input_voltage, CRGB::Blue);   // output the input voltage in blue
  }
}
