// 
//  WeatherStation
//
//  This outdoor weather station includes the following components
//
//  1)  BME280 - temperature, humidity, pressure (I2C) 
//  2)  Anemometer - wind speed (analog)
//  3)  RFM69 RF radio (SPI)
//  4)  IN3221 High Side DC Current Sensor Breakout (I2C)
//  5)  Moteino R4 (w/4MB on-board flash)
//
///////////////////////////////////////////////////////
//  Includes                                          /
///////////////////////////////////////////////////////
//
#include <Wire.h>
#include <SPI.h>
#include <SPIFlash.h>
#include <RFM69.h>
#include <BME280_MOD-1022.h>
#include <SDL_Arduino_INA3221.h>
#include "WeatherStation2.h"

///////////////////////////////////////////////////////
//           S E T U P                                /
///////////////////////////////////////////////////////
//
void setup()
{
  Wire.begin();                                                  // Initialize I2C  
  ina3221.begin();                                               // Initialize the current sensor object
  setupWirelessRadio();                                          // Setup and configure wireless
  setupBME280();                                                 // Configure BME280 board
  disableFlash();                                                // Put flash chip to sleep
  disableLED();                                                  // Turn off on-board LED
  timer = millis();                                              // Grab current millis 
}

///////////////////////////////////////////////////////
//           L O O P                                  /
///////////////////////////////////////////////////////
//
void loop()
{
  float windSpeed,                                               // Wind speed in meters per second (m/s)
        temp,                                                    // Temp in C
        humidity,                    
        pressure;                                                // Pressure in hecto Pascals

  if (BME280Present == false)
  {
    temp = 0.0;
    humidity = 0.0;
    pressure = 0.0;
  } else {
    while (BME280.isMeasuring()) {}
    BME280.writeMode(smForced);
    BME280.readMeasurements();
    temp = BME280.getTemperature();
    Serial.println(temp);
    humidity = BME280.getHumidity();
    Serial.println(humidity);
    pressure = BME280.getPressureMoreAccurate();
    Serial.println(pressure);
  }
  
  windSpeed = computeWindSpeed();                                // Compute wind speed in MPH
  sendWindData(&windSpeed);
  
  if ((millis() - timer) > 60000)                                // We send rest of data every 60 seconds
  {
    delay(300);
    sendTHPData(&temp, &humidity, &pressure);
    sendElecData();
    timer = millis();                                            // Reset stored milli counter
  }
 
  delay(1 * ONESECOND);
}


///////////////////////////////////////////////////////
//           computeWindSpeed                         /
///////////////////////////////////////////////////////
//
float computeWindSpeed(void)
{
  int analogWind;                                                // Reading from analog pin on anemometer
  float sensorVoltage;                                           // Voltage computed from the anemometer analog value
  float windSpeed;                                               // Wind speed in mph
  
  analogWind = analogRead(anemometerPin);                        // Read anemometer analog value, 0 <= X <= 1023
  sensorVoltage = analogWind * voltageConversionConstant;        // Convert analog value to actual voltage
  if (sensorVoltage <= voltageMin)                               // If voltage is below minimum value, set wind speed to zero
    windSpeed = 0.0; 
  else
    windSpeed = ((sensorVoltage - voltageMin) * windSpeedMax) / (voltageMax - voltageMin);
  return windSpeed;
}      

///////////////////////////////////////////////////////
//           setupWirelessRadio                       /
///////////////////////////////////////////////////////
//
void setupWirelessRadio(void)
{
  radio.initialize(FREQUENCY,OUTNODEID,NETWORKID);
  radio.encrypt(KEY);
}

///////////////////////////////////////////////////////
//           setupBME280                              /
///////////////////////////////////////////////////////
//
void setupBME280(void)
{
  uint8_t chipID;

  chipID = BME280.readChipId();                                          // We read chip ID to verify board is installed
  if (chipID == 0xFF)                                                    // 0xFF = board not installed
    BME280Present = false; 
  else {
    BME280.readCompensationParams();
    BME280.writeFilterCoefficient(fc_off);
    BME280.writeOversamplingPressure(os1x);
    BME280.writeOversamplingTemperature(os1x);
    BME280.writeOversamplingHumidity(os2x);
    BME280.writeMode(smForced);
  }
}

///////////////////////////////////////////////////////
//           sendTHPData                              /
///////////////////////////////////////////////////////
//
void sendTHPData(float* temp, float* humidity, float* pressure)
{
  WData xmitData;
  
  xmitData.type = THP;
  xmitData.data.env.temperature = *temp * 1.8 + 32.0;                    // Convert C to F
  xmitData.data.env.humidity = *humidity;                    
  xmitData.data.env.pressure = *pressure * 0.000295299830714 * 100;      // Convert to inHg
  radio.send(INNODEID, &xmitData, sizeof(xmitData), false);              // Send with no ACK requested
}

///////////////////////////////////////////////////////
//           sendWindData                             /
///////////////////////////////////////////////////////
//
void sendWindData(float* windSpeed)
{
  WData xmitData;

  xmitData.type = WIND;  
  xmitData.data.wind.windspeed = *windSpeed * 2.23694;                     // Convert m/s to mph
  radio.send(INNODEID, &xmitData, sizeof(xmitData), false);                // Send with no ACK requested
}


///////////////////////////////////////////////////////
//           sendElectData                            /
///////////////////////////////////////////////////////
//
void sendElecData(void)
{
  WData xmitData;
  float LipoVoltage, LipoCurrent;
  float SolarVoltage, SolarCurrent;
  float LoadVoltage, LoadCurrent;
  
  LipoVoltage = ina3221.getBusVoltage_V(LIPO_BATTERY_CHANNEL);
  LipoCurrent = -ina3221.getCurrent_mA(LIPO_BATTERY_CHANNEL);
  SolarVoltage = ina3221.getBusVoltage_V(SOLAR_CELL_CHANNEL);
  SolarCurrent = -ina3221.getCurrent_mA(SOLAR_CELL_CHANNEL);
  LoadVoltage = ina3221.getBusVoltage_V(OUTPUT_CHANNEL);
  LoadCurrent = ina3221.getCurrent_mA(OUTPUT_CHANNEL);
  
  xmitData.type = ELEC;
  xmitData.data.elec.LipoVoltage = LipoVoltage;
  xmitData.data.elec.LipoCurrent = LipoCurrent;
  xmitData.data.elec.SolarVoltage = SolarVoltage;
  xmitData.data.elec.SolarCurrent = SolarCurrent;
  xmitData.data.elec.LoadVoltage = LoadVoltage;
  xmitData.data.elec.LoadCurrent = LoadCurrent;  
  radio.send(INNODEID, &xmitData, sizeof(xmitData), false);      // Send with no ACK requested
}


///////////////////////////////////////////////////////
//           disableLED                               /
///////////////////////////////////////////////////////
//
void disableLED(void)
{
  pinMode(9,OUTPUT);                                             // Set LED pin for output
  digitalWrite(9,0);                                             // Turn off LED
}  


///////////////////////////////////////////////////////
//           disableFlash                             /
///////////////////////////////////////////////////////
//
void disableFlash(void)
{
  flash.initialize();                                            // Initialize flash
  flash.sleep();                                                 // Put on-board flash to sleep
}
