Weather station project updated display and sensors

Dependencies:   BH1750 BMP280 DS1820 HMC5983 Helios MAX17043 MPU6050 SHTx SSD1306_I2C A4988_stepper mbed

Fork of weather_station_project by Daniel David

main.cpp

Committer:
daniel_davvid
Date:
2018-07-04
Revision:
3:44517d2520e1
Parent:
2:bc1c1f395e9a

File content as of revision 3:44517d2520e1:

#include "mbed.h"

#define DONT_MOVE 0
#define UPDATE_RTC_TIME 0
#define RTC_TIME 1530462446
#define DISPLAY_INTERVAL 0.5f
#define SUN_POS_INTERVAL 10// one minute for sun position update using
                            // the Helios algorithm
#define PLATFORM_POSITION_POLL_INTERVAL 1 // read platform position sensors
#define WEATHER_STATE_UPDATE_INTERVAL 1


#ifndef M_PI
#define M_PI           3.1415926535897932384626433832795028841971693993751058209749445923078164f
#endif
// DS1820 temp sens pin
#define MAX_PROBES      16
#define DATA_PIN        A1
//#define MULTIPLE_PROBES

#include "BH1750.h"         //Light sensor lib
#include "BMP280.h"         //Pressure sensor lib
#include "DS1820.h"         //Temp sensor lib (One wire)
#include "Helios.h"         //Sun tracking algorithm
#include "HMC5983.h"        //Compass lib
#include "MAX17043.h"       //Fuel gauge sens lib
#include "MPU6050.h"        //Accelerometer sensor lib
#include "SHTx/sht15.hpp"     //Humidity sens lib
#include "SSD1306.h"        //Display lib
#include "stepper.h"        //Stepping motor lib.

Serial pc(USBTX, USBRX);
//Serial pi(D1, D0);
//Digital pins
DigitalIn maxAngleLimit(PC_8);
DigitalIn minAngleLimit(PC_6);
DigitalOut swPi(PC_5);
DigitalIn pir(PB_12);
//Analog pins
AnalogIn waterLevel(A2);
AnalogIn crtConsumption(A3); 

// Stepper motor setup
stepper stpCirc(PA_12, NC, NC, NC, PB_1, PB_2);
stepper stpAngle(PA_11, NC, NC, NC, PB_14, PB_15);

//DS1820 setup
DS1820* probe[MAX_PROBES];

//Helios algorithm
Helios sun;

// I2C communication setup
I2C i2c1(D14, D15);
I2C i2c2(D3, D6);
//I2C i2c3(D5, D7);

// Maybe change the format
SHTx::SHT15 sht(D5, D7);

//I2C 1 sensors
BH1750 bh(i2c1);
BMP280 bmp(i2c1);
HMC5983 compass(i2c1);
MAX17043 fuelGauge(i2c1);
SSD1306 lcd1(&i2c1, 0x78);

//I2C 2 sensors
SSD1306 lcd2(&i2c2, 0x78);
MPU6050 mpu(i2c2);

// Timers 
Timer sunPosUpdateTimer;
Timer platformPositionPollTimer;
Timer platformRotateTimer;
Timer panelTiltTimer;
Timer pirPollTimer;
Timer weatherStateUpdateTimer;
Timer displayTimer;


// platform rotate & panel tilt
// timer intervals
float platformRotateInterval;
float panelTiltInterval;

// Accelerometer readings
Vector scaledAccel; 
float vertG;  // Z axis component of the g
float accelDesiredAngle, accelActualAngle;

//Compass
float compassDesiredAngle, compassActualAngle;


// PIR state variable and update interval
bool pirDetectionOccured = false;
// 60 seconds warm-up for first update
int pirUpdateInterval = 60;

// LCD displays current shown page
int crtPage = 0;

// Auxiliary variables for RTC time
// readings
time_t seconds;
char buffer[32];


//Function forward declarations
void init();                           // setup all devices

float compassAngleDiff(float a, float b);  // compute angle difference between
                                           // the compass read angle and the
                                           // desired angle
                                              
float accelAngleDiff(float a, float b);

int getWaterLevel();                   // read the water level sensor

void updatePirState();                 // read the PIR state and update
                                       // state variable
                                       
float getCrtConsumption();             // read the current sensor

int main()
{
    //Sensor variable names
    float lightIntensity;
    float bmpTemp, pressure;
    float humidity, shtTemp;
    float crtConsumption;
    float VCell, SOC;
    float temperature;
    int maxAngle, minAngle;
    // initialize all devices
    init();

    while (1) {
        
        //Helios
        if (sunPosUpdateTimer.read() > SUN_POS_INTERVAL) {
            seconds = time(NULL);
            strftime(buffer, 32, "%H:%M:%S", localtime(&seconds));
            sun.updatePosition();
            compassDesiredAngle = sun.azimuth();
            accelDesiredAngle = sun.elevation();
        }
                               
        if (pirPollTimer.read() > pirUpdateInterval) {
            pirPollTimer.reset();
            pirUpdateInterval = 1;
            updatePirState();
        }
        
        if (platformPositionPollTimer.read() > PLATFORM_POSITION_POLL_INTERVAL) {
            platformPositionPollTimer.reset();
            // read compass
            compassActualAngle = 360-compass.read();
            
            // read accelerometer
            scaledAccel = mpu.readScaledAccel();
            vertG = scaledAccel.ZAxis;
            vertG = vertG > 2.0f ? 3.9f - vertG : vertG;
            vertG = vertG < 1.0f ? vertG : 1.0f;
            vertG = vertG > -1.0f ? vertG : -1.0f;
            accelActualAngle = acos(vertG)/M_PI*180.0f;
        }
        
        if (weatherStateUpdateTimer.read() > WEATHER_STATE_UPDATE_INTERVAL) {
            weatherStateUpdateTimer.reset();
            //DS1820 sensor
            probe[0]->convertTemperature(true, DS1820::all_devices);  
            for (int i = 0; i<1; i++)
                pc.printf("Device %d returns %3.1foC\r\n", i, probe[i]->temperature());   
            //SHT15
            sht.update();
            sht.setScale(false);
            
            //Sensor data to variables
            lightIntensity = bh.lux()/1.2f;
            bmpTemp = bmp.getTemperature();
            pressure = bmp.getPressure();
            shtTemp = sht.getTemperature();
            humidity = sht.getHumidity();
            crtConsumption = getCrtConsumption()*1000;
            probe[0]->convertTemperature(true, DS1820::all_devices);  
            temperature = probe[0]->temperature(); 
            VCell = fuelGauge.getFloatVCell();
            SOC = fuelGauge.getFloatSOC();
            maxAngle = maxAngleLimit.read();
            minAngle = minAngleLimit.read();
            azimuth = sun.azimuth();
            elevation = sun.elevation();
        }
        
        if (platformRotateTimer.read() > platformRotateInterval) {
            platformRotateTimer.reset();
            // rotate the platform to reach the desired compass
            // indication
            float angleDiff = compassAngleDiff(compassActualAngle, compassDesiredAngle);
            if (abs(angleDiff) > 5) {
                if (!DONT_MOVE) {
                    if (angleDiff > 0) {
                        stpCirc.step(0, 1, 30000);  
                    }
                    else {
                        stpCirc.step(0, 0, 30000);    
                    }
                }
            }

            // change the rotate interval according to angle difference
            // for large differences, make the update interval shorter
            if (abs(angleDiff) > 10) {
                platformRotateInterval = 0.1f;
            }
            else {
                platformRotateInterval = 1.0f;
            } 
        }
        
        if (panelTiltTimer.read() > panelTiltInterval) {
            panelTiltTimer.reset();
            // tilt the panel to reach the desired accelerometer
            // indication
            
            float angleDiff = accelAngleDiff(accelActualAngle, accelDesiredAngle);
            if (abs(angleDiff) > 2) {
                if (!DONT_MOVE) {
                    if (angleDiff > 0 && !maxAngleLimit.read()) {
                        stpAngle.step(0, 1, 30000);  
                    }
                    else if (!minAngleLimit.read()) {
                        stpAngle.step(0, 0, 30000);    
                    }
                }
            }
            // change the rotate interval according to angle difference
            // for large differences, make the update interval shorter
            if (abs(angleDiff) > 5) {
                panelTiltInterval = 0.1f;
            }
            else {
                panelTiltInterval = 1.0f;
            } 
        }
        if (displayTimer.read() > DISPLAY_INTERVAL) {
            displayTimer.reset();
            pc.printf("UTC time is: %s\n", buffer);
            pc.printf("Sun azimuth: %.2f, elevation: %.2f\n", sun.azimuth(), sun.elevation());
            pc.printf("Vcell: %.2f\n", VCell);
            pc.printf("Battery: %.2f\n", SOC);
            pc.printf("Temperature [ %3.2f C ]\r\n", shtTemp);
            pc.printf("Humdity     [ %3.2f %% ]\r\n\n", humidity);
            pc.printf("Compass: %2.3f\n", compassActualAngle);
            pc.printf("Vertical angle: %1.3f\n", accelActualAngle);
            pc.printf("Intensity: %5.2f lux\n", lightIntensity);            
            pc.printf("Temp = %f\t Pres = %f\n", bmpTemp,pressure);
            if (crtPage == 0) {
                lcd1.setPageAddress(0,0);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Compass: %3.0f", compassActualAngle);
                //lcd.printf("Difference: %f\n", compassAngleDiff(compassActualAngle, compassDesiredAngle));
                
                lcd1.setPageAddress(1,1);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Angle: %2.0f", accelActualAngle); 
                lcd1.setPageAddress(2,2);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("LUX: %4.0f", lightIntensity);
                lcd1.setPageAddress(3,3);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Temp: %.1f", bmpTemp);
                lcd1.setPageAddress(4,4);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Press: %4.f", pressure);
                lcd1.setPageAddress(5,5);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Max: %d", maxAngle);
                lcd1.setPageAddress(6,6);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("Min: %d", minAngle);
                lcd1.setPageAddress(7,7);
                lcd1.setColumnAddress(0,127);
                lcd1.printf("PIR: %s", pirDetectionOccured ? "DETECTED" : "NOTHING ");

                lcd2.setPageAddress(0,0);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("AZMT: %.2f", azimuth);
                lcd2.setPageAddress(1,1);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("ELV: %.2f", elevation);
                
                //MAXI17043
                lcd2.setPageAddress(2,2);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("Vcell: %.2f\n", VCell);
                lcd2.setPageAddress(3,3);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("Battery: %.2f\n",SOC);
                
                //SHT15
                lcd2.setPageAddress(4,4);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("Temp: %3.2f C", shtTemp);
                lcd2.setPageAddress(5,5);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("Hum: %3.2f%%", humidity);
                lcd2.setPageAddress(6,6);
                lcd2.setColumnAddress(0,127);
                lcd2.printf("Crt: %03.1fmA", crtConsumption);
                lcd2.setPageAddress(7,7);
                lcd2.setColumnAddress(0,127); 
                lcd2.printf("Temp %2.1f C",temperature);  

            }
            else {
            }
            crtPage = (crtPage + 1) & 1;
        }
    }
}

void init()
{
    maxAngleLimit.mode(PullUp);
    minAngleLimit.mode(PullUp);

    if (UPDATE_RTC_TIME) {
        set_time(RTC_TIME);
    }

    // Stepper drivers setup
    if (DONT_MOVE) {
        stpAngle.disable();
        stpCirc.disable();
    }
    else {
        stpAngle.enable();
        stpCirc.enable();
    }
    swPi = 0;
    //SHT15 setup
    sht.setOTPReload(false);
    sht.setResolution(true);

    // DS1820 setup
    int num_devices = 0;
    while(DS1820::unassignedProbe(DATA_PIN)) {
        probe[num_devices] = new DS1820(DATA_PIN);
        num_devices++;
        if (num_devices == MAX_PROBES)
            break;
    }
    //MPU setup
    while(!mpu.begin(MPU6050_SCALE_2000DPS, MPU6050_RANGE_2G)) {
        pc.printf("Could not find a valid MPU6050 sensor, check wiring!\n");
        wait(0.5);
    }
    mpu.calibrateGyro();
    mpu.setThreshold(3);
    
    //BMP setup
    bmp.initialize();
    //BH setup
    bh.init();
    //
    compass.init();
    compassDesiredAngle = 0.0f;  
    accelDesiredAngle = 45.0f;
    
    platformRotateInterval = 0.1f;
    panelTiltInterval = 0.1f;
    
    //Timers Start
    platformRotateTimer.start();
    panelTiltTimer.start();
    weatherStateUpdateTimer.start();
    displayTimer.start();
    platformPositionPollTimer.start();
    pirPollTimer.start();
    sunPosUpdateTimer.start();
}

float accelAngleDiff(float a, float b)
{
    float diff = a - b;
    return diff;    
}

float compassAngleDiff(float a, float b)
{
    float diff = a - b;
    
    if (diff > 180)
        diff -= 360;
    if (diff < -180)
        diff += 360;
    return diff;
}


int getWaterLevel(){
    float value;
    value = waterLevel.read() *1000;
        if (value<=150) {
            value=0;
        } else if (value>150 && value<=210) {
            value=1/4;
        } else if (value>210 && value<=250) {
            value=1/2;
        } else if (value>250 && value<=350) {
            value=3/4;;
        } else if (value>350) {
            value=1;
        }
    value=value*100; //final data in x%
    return value;
}

float getCrtConsumption(){
    //VOUT=Vcc/2+i*VCC/36.7
    //i=36.7*Vout/Vcc-18.3
    
    float result = 36.7f * crtConsumption.read() - 18.3f;
    result = result < 0 ? 0.0f : result;
    
    return result;
}

void updatePirState() {
    pirDetectionOccured = pir.read() != 0;
}