IoT_watering project - watering unit

Dependencies:   DHT11 mbed-rtos mbed ssWi

main.cpp

Committer:
mariob
Date:
2017-02-16
Revision:
2:0b51e6d879df
Parent:
1:7f4af0d73836

File content as of revision 2:0b51e6d879df:

#include "mbed.h"
#include "rtos.h"

#include "config.hpp"

#include "DHT11.h"

#include "xbee.hpp"
#include "ssWiSocket.hpp"

#ifndef DEBUG
#define     printf(fmt,...)     
#endif

LocalFileSystem local("local");

// global configuration
watering_unit_config_t global_config;

// ssWi sockets
ssWiSocket* socket_moisture = NULL;
ssWiSocket* socket_temperature = NULL;
ssWiSocket* socket_humidity = NULL;
ssWiSocket* socket_response = NULL;
ssWiSocket* socket_water = NULL;
ssWiSocket* socket_command = NULL;

// thread functions
void thread_sensing_fcn();
void thread_watering_fcn();

// return true if a new message has been received, false otherwise
bool read_from_port(ssWiSocket *socket, int *value);

int main() {
    Timer t;
    t.start();
    
    printf("MAIN - configuration\r\n");
    
    // read configuration    
    FILE *fp = fopen("/local/cfg.txt", "r");
    if (fp == NULL)
        error("missing configuration file\r\n");
    fscanf(fp, "%d", &global_config.address);
    fclose(fp);
    global_config.moisture_port = GET_MOISTURE_PORT(global_config);
    global_config.temperature_port = GET_TEMPERATURE_PORT(global_config);
    global_config.humidity_port = GET_HUMIDITY_PORT(global_config);
    global_config.response_port = GET_RESPONSE_PORT(global_config);
    global_config.water_port = GET_WATER_PORT(global_config);

    // configure network
    XBeeModule xbee(XBEE_PIN_TX, XBEE_PIN_RX, PAN_ID, CHANNEL_ID);
    xbee.init(XBEE_TX_PER_SECOND, XBEE_RX_PER_SECOND);
    socket_moisture = ssWiSocket::createSocket(global_config.moisture_port);
    socket_temperature = 
                       ssWiSocket::createSocket(global_config.temperature_port);
    socket_humidity = ssWiSocket::createSocket(global_config.humidity_port);
    socket_response = ssWiSocket::createSocket(global_config.response_port);
    socket_water = ssWiSocket::createSocket(global_config.water_port);
    socket_command = ssWiSocket::createSocket(PORT_COMMANDS);

    // threads
    Thread thread_sensing(osPriorityAboveNormal);
    thread_sensing.start(&thread_sensing_fcn);
    Thread thread_watering(osPriorityHigh);
    thread_watering.start(&thread_watering_fcn);

    // wait 10 seconds since the board started
    while(t.read() < TIMEOUT_CONF);
    t.stop();

    printf("MAIN - board ready\r\n");

    // handle messages
    bool recv_start_sampling = false;
    bool recv_stop_sampling = false;
    bool recv_watering = false;
    int msg = COMM_NO_VALUE;
    while(true) {
        if (!read_from_port(socket_command, &msg))
            continue;
        if (!recv_start_sampling && msg == COMM_START_SAMPLING) {
            recv_start_sampling = true;
            printf("MAIN - sampling start command\r\n");
            thread_sensing.signal_set(SIGNAL_START_ARRIVED);
            continue;
        }
        if (!recv_stop_sampling && msg == COMM_STOP_SAMPLING) {
            recv_stop_sampling = true;
            printf("MAIN - sampling stop command\r\n");
            thread_sensing.signal_set(SIGNAL_STOP_ARRIVED);
            continue;
        }
        if (!recv_watering &&  msg == GET_WATERING_COMMAND(global_config)) {
            recv_watering = true;
            printf("MAIN - watering start command\r\n");
            thread_watering.signal_set(SIGNAL_WATERING_ARRIVED);
            continue;
        }
        if (msg == COMM_SHUTDOWN) {
            printf("MAIN - shutdown command\r\n");
            recv_start_sampling = false;
            recv_stop_sampling = false;
            recv_watering = false;
            socket_moisture->write(COMM_NO_VALUE);
            socket_temperature->write(COMM_NO_VALUE);
            socket_humidity->write(COMM_NO_VALUE);
            socket_response->write(COMM_NO_VALUE);
            continue;
        }
    }

    printf("MAIN - join threads and end\r\n");

    thread_sensing.join();
    thread_watering.join();

    return 0;
}

void thread_sensing_fcn () {
    AnalogIn sensor_moisture(HW_PIN_MOISTURE);

    while (1) {
        int msg = COMM_SAMPLING_OK;
        DHT11 sensor_dht(HW_PIN_TEMPERATURE);
        printf("SAMP - waiting...\r\n");

        // wait supervisor message
        Thread::signal_wait(SIGNAL_START_ARRIVED);
        printf("SAMP - start\r\n");

        DigitalOut l(LED3);
        l = 1;

        Timer t;
        t.start();
        // wait two seconds for HDT sensor
        wait(2.0);
        
        // sample values
        double sens_mois = 0.0;
        double sens_temp = 0.0;
        double sens_humi = 0.0;
        for (int i = 0; i < NUM_SAMPLES; i++) {
            if (sensor_dht.readData() != 0) {
                printf("SAMP - error %d\r\n", error);
                msg = COMM_SAMPLING_KO;
                break;
            }
            sens_temp += sensor_dht.readTemperature();
            sens_humi += sensor_dht.readHumidity();
            sens_mois += sensor_moisture.read() * 100;
            if (t.read() > TIMEOUT_SAMPLING) {
                // timeout expired, exit
                msg = COMM_SAMPLING_OUT;
                break;
            }
            Thread::wait(INTERVAL_SAMPLING);
        }
        t.stop();
        
        // compute averages
        sens_mois = (sens_mois / NUM_SAMPLES) * 10.0;
        sens_temp = (sens_temp / NUM_SAMPLES) * 10.0;
        sens_humi = (sens_humi / NUM_SAMPLES) * 10.0;
        printf("SAMP - %f, %f, %f\r\n", sens_mois, sens_temp, sens_humi);

        // wait supervisor stop message
        Thread::signal_wait(SIGNAL_STOP_ARRIVED);

        // write averages and response
        int value = (int)sens_mois;
        socket_moisture->write(value == 0 ? 1 : value);
        value = (int)sens_temp;
        socket_temperature->write(value == 0 ? 1 : value);
        value = (int)sens_humi;
        socket_humidity->write(value == 0 ? 1 : value);
        socket_response->write(msg);
        printf("SAMP - end\r\n");
        
        l = 0;
    }
}

void thread_watering_fcn() {
    DigitalOut pump(HW_PIN_PUMP);
    DigitalIn level_sens(HW_PIN_LOW_WATER_LEVEL);

    while (1) {
        pump = 0;
        printf("WATR - waiting...\r\n");

        // wait watering command
        Thread::signal_wait(SIGNAL_WATERING_ARRIVED);
        printf("WATR - start\r\n");
        Timer t;
        t.start();

        DigitalOut l(LED2);
        l = 1;

        // read total second to water
        int seconds = COMM_NO_VALUE;
        while(!read_from_port(socket_water, &seconds) &&
                                                     t.read()<TIMEOUT_WATERING);
        t.stop();
        if (t.read() >= TIMEOUT_WATERING) {
            socket_response->write(COMM_WATERING_KO);
            continue;
        }
        printf("WATR - required time %ds\r\n", seconds);

        // start watering
        int msg = COMM_WATERING_OK;
        double actual_seconds = 0.0;
        while (actual_seconds < seconds) {
            if (!level_sens) {
                // low water, stop pump and exit
                pump = 0;
                printf("WATR - watering level error\r\n");
                msg = COMM_LOW_WATER_LEVEL;
                break;
            }
            // water for 1 second
            t.reset(); t.start();
            double scale = seconds > (actual_seconds + 1.0) ? 1.0 : seconds -
                                                                 actual_seconds;
            pump = 1;
            Thread::wait((unsigned int)(scale * INTERVAL_WATERING));
            t.stop();
            actual_seconds += t.read();
        }
        pump = 0;
        printf("WATR - elapsed time %fs\r\n", actual_seconds);
        socket_response->write(msg);
        
        l = 0;
    }
}

bool read_from_port(ssWiSocket *socket, int *value) {
    int prev = *value;
    *value = socket->read();
    return (*value) != prev;
}