a sensor hub for monitoring home environment

Dependencies:   HTS221 LIS3MDL LPS22HB LSM303AGR LSM6DSL VL53L0X picojson

Fork of HelloWorld_ST_Sensors by ST

main.cpp

Committer:
jaafaryn
Date:
2017-12-12
Revision:
11:1e0b9a529ee0
Parent:
8:39ecd15538f9
Child:
12:058b012dbebe

File content as of revision 11:1e0b9a529ee0:

/*------------------------------------------------------------------------------
                Home Environment Monitoring with STM32 Discovery IOT Node
                                Disco_HomeEnv
Features:
  - Monitor temperature, relative humidity and air pressure
  - Connects to a local TSDB server (over http) to log this data
  - Display the data on a Nextion smart display with 30s autosleep and proximity
    or touch detection wake up
Next:
  - add RTC sync and time display
  - add light sensor to monitor illuminance
  - improve reading by either: reduce power on time of WiFi module (batch logging)
    or by compensating for board own temperature
  - add option to choose location from a list and update location tag
  - incrementally convert the project to electric energy monitoring:
        - read 2x simultaneous adc channels using DMA
        - save daily power readings to QSP mem for batch logging and recovey?
        - add screen to display current power drawing, daily and monthly cumulatives
------------------------------------------------------------------------------*/

#include "main.h"

/* ---------- SETUP ------------- */
void setup()
{
    printf("\n***************************************************************\n");
    printf("***      Home Env on STM32 IoT Discovery                    ***\n");
    printf("***************************************************************\n");

    printf("> Initializing sensors and WiFi... \n");
    
    int range_status;

    /* Init all sensors with default params */
    hum_temp.init(NULL);
    press_temp.init(NULL);
    magnetometer.init(NULL);
    acc_gyro.init(NULL);
    range_status = range.init_sensor(VL53L0X_DEFAULT_ADDRESS);

    /* Enable all sensors */
    hum_temp.enable();
    press_temp.enable();
    acc_gyro.enable_x();
    acc_gyro.enable_g();
    
    uint8_t id;
    hum_temp.read_id(&id);
    printf("HTS221  humidity & temperature id  = 0x%X\r\n", id);
    press_temp.read_id(&id);
    printf("LPS22HB pressure & temperature id  = 0x%X\r\n", id);
    magnetometer.read_id(&id);
    printf("LIS3MDL magnetometer id            = 0x%X\r\n", id);
    acc_gyro.read_id(&id);
    printf("LSM6DSL accelerometer&gyroscope id = 0x%X\r\n", id);
    printf("VL53L0x status                     = %d \r\n", range_status);

    sense_enabled = true;

    /* Setup display */
    WIFI_ICON_OFF;
    UPLOAD_ICON_OFF;
    nextion.printf("usup=0\xff\xff\xff");// no wakeup on serial in
    nextion.printf("thsp=30\xff\xff\xff");// sleep after 30sec no touch
    nextion.printf("thup=1\xff\xff\xff");// wake up on touch


    /*Initialize WIFI module */
    WiFi_on = connectWiFi();
    if (WiFi_on) {
        led3 = 1;
        WIFI_ICON_ON;
        //WiFi_led_ticker.attach(&toggle_led3_cb, 0.25);
        // sync_time();
    }

    // start event tickers
    getMeasurementsTicker.attach(&time_to_sense_cb, SENSE_PERIOD_S);
    sendMeasurementsTicker.attach(&time_to_send_cb, UPLOAD_PERIOD_S);
    checkProximityTicker.attach(&time_to_check_distance_cb, CHECK_PROXIMITY_PERIOD_S);

} // Setup


/* ---------- LOOP ------------- */
void loop() {
    if (take_measurements) {
        // Environment data
        hum_temp.get_temperature(&tempC_val);
        tempF_val = tempC_val*(9.0/5.0) + 32;
        hum_temp.get_humidity(&RH_val);

        press_temp.get_pressure(&Patm_val);
        press_temp.get_temperature(&tempC_val2);

        // Inertial data
        /*
        magnetometer.get_m_axes(axes);
        printf("LIS3MDL [mag/mgauss]:    %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);

        acc_gyro.get_x_axes(axes);
        printf("LSM6DSL [acc/mg]:        %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);

        acc_gyro.get_g_axes(axes);
        printf("LSM6DSL [gyro/mdps]:     %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
        */

        // print results to terminal
        /*
        printf("HTS221:  temp= %.2f C, hum= %.2f%%\r\n", tempC_val, RH_val);
        printf("         temp= %.2f F\n", tempF_val);
        printf("LPS22HB: patm= %.2f mbar, temp= %.2f C\r\n", Patm_val, tempC_val2);
        printf("VL53L0X [mm] = %6ld\r\n", distance);
        */

        // refresh screen with updated measurements
        nextion.printf("valC.txt=\"%.1f\"\xff\xff\xff", tempC_val);
        nextion.printf("valF.txt=\"%.1f\"\xff\xff\xff", tempF_val);
        nextion.printf("valRH.txt=\"%.1f\"\xff\xff\xff", RH_val);
        nextion.printf("valAtm.val=%.0f\xff\xff\xff", Patm_val);
        nextion.printf("valRange.val=%d\xff\xff\xff", distance);

        take_measurements = false;
    }// take measurements

    if (send_measurements) {

        //printf("HTS221:  temp= %.2f C, hum= %.2f%%\r\n", tempC_val, RH_val);

        // body of the request
        char request_body[256];
        sprintf(request_body, "disco_iot,loc=%s temperature=%.2f,humidity=%.1f,pressure=%.1f \n","playroom", tempC_val, RH_val, Patm_val);

        // build header of the request
        sprintf((char *)http_request, "POST %s HTTP/1.1\r\nHost: %s \r\n", influx_query, InfluxServerUrl);
        strcat((char *)http_request, "Accept: */*\r\n");
        strcat((char *)http_request, "User-agent: ES-WIFI TcpClient\r\n");
        strcat((char *)http_request, "Connection: Close\r\n"); //"Connection: Keep-Alive\r\n"
        char buffer[64];
        sprintf(buffer, "Content-Length: %d \r\n\r\n", strlen(request_body));
        strcat((char *)http_request, buffer);

        // append body to the header of the request
        strcat((char *)http_request, request_body);
        reqLen = strlen((char *)http_request);

        // Establish a connection to DB server
        uint8_t socketid = 1;
        if (checkWiFi()) {
            led3 = 1;
            WIFI_ICON_ON;
            if (connectToServer(InfluxServerUrl, InfluxServerPort, socketid)) {
                ledhttp =1;
                // submit POST request
                printf("> Sending a POST request with length=%d including a body length=%d\n", reqLen, strlen(request_body));
                printf((char *)http_request);
                uint16_t dataLen;
                if (WIFI_SendData(socketid, http_request, reqLen, &dataLen, WIFI_WRITE_TIMEOUT) != WIFI_STATUS_OK) {
                    printf("> ERROR: Could not send request to %s", InfluxServerUrl);
                    UPLOAD_ICON_OFF;
                } else {
                    request_sent++;
                    UPLOAD_ICON_ON;
                }
                // get server response
                // memset(&http_resp[0], 0, sizeof(http_resp));
                WIFI_ReceiveData(socketid, http_resp, sizeof(http_resp), &dataLen, WIFI_READ_TIMEOUT);
                if(dataLen > 0) {
                    /*
                    printf("> Server response:\n");
                    printf((char *)http_resp);
                    printf("\n> Response length: %d \n", dataLen);
                    */
                    memset(&buffer[0], 0, sizeof(buffer));
                    // get the first line of the response
                    strcpy(buffer, strtok((char *)http_resp, "\r\n"));
                    // extract the response code
                    int response_code = 0;
                    sscanf(buffer, "HTTP/1.1 %d", &response_code);
                    printf("> Response code: %d \n", response_code);
                    /* c ommon response codes from InfluxDB API:
                    HTTP/1.1 204 No Content
                    HTTP/1.1 400 Bad Request
                    HTTP/1.1 404 Not Found
                    HTTP/1.1 500 Internal Server Error
                    */
                    if (response_code == 204) request_acked++;
                } else {
                    UPLOAD_ICON_OFF;
                    printf("> Error: No response from the server %s.\n", InfluxServerUrl);
                }
                printf("> Requests sent: %d, ack'ed: %d\n", request_sent, request_acked);
                ledhttp = 0;
                WIFI_CloseClientConnection(socketid);
            } else {
                printf("> ERROR: Could not connect to %s \n", InfluxServerUrl);
            }
        } else {
            printf("> ERROR: Could not connect to WiFi \n");
            led3 = 0;
            WIFI_ICON_OFF;
        }
        send_measurements = false;
    } // sendMeasurement()

    if (check_proximity) {
        // make sure display is awake when somebody get close to the screen
        // Proximity value
        uint32_t dist_val = 0;
        int status = range.get_distance(&dist_val);
        if (status == VL53L0X_ERROR_NONE) {
            distance = (int)dist_val;
        } else {
            distance = -1;
        }
        if (distance < 400) {
            nextion.printf("sleep=0\xff\xff\xff");// send wake up command
        }
        check_proximity = false;
    } // check proximity
} // Loop


int main() {
    setup();
    while(1) {
        loop();
    }
}


/*                                         */
/* Interrupts servicing callback functions */
/*                                         */

// ISR for flashing WiFi LED
/*
void toggle_led3_cb()
{
    led3 = !led3;
}*/

// ISR to enable taking measurements (and refresh display)
void time_to_sense_cb(void)
{
    if (sense_enabled) {
        take_measurements = true;
    }
}

// ISR to enable handling sending data
void time_to_send_cb(void)
{
    if (sense_enabled) {
        send_measurements = true;
    }
}

// ISR to enable checking distance
void time_to_check_distance_cb(void)
{
    check_proximity = true;
}

/**
  * @brief  Connect to the WiFi network with credentials in mbed_app.json
  * @param  None
  * @retval True for WiFi connected, False if there was an error
  */
bool connectWiFi(void)
{
    uint8_t  IP_Addr[4];
    uint8_t  MAC_Addr[6];

    if(WIFI_Init() ==  WIFI_STATUS_OK) {
        // printf("> WiFi module initialized.\n");
        //if(WIFI_GetModuleName(moduleName) == WIFI_STATUS_OK) {
        //  printf("> Module name: %s\n", moduleName);
        //}
        if(WIFI_GetMAC_Address(MAC_Addr) == WIFI_STATUS_OK) {
            printf("> WiFi module MAC Address : %X:%X:%X:%X:%X:%X\n",
                   MAC_Addr[0],
                   MAC_Addr[1],
                   MAC_Addr[2],
                   MAC_Addr[3],
                   MAC_Addr[4],
                   MAC_Addr[5]);
        } else {
            printf("> ERROR : CANNOT get MAC address\n");
        }

        if( WIFI_Connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, WIFI_ECN_WPA2_PSK) == WIFI_STATUS_OK) {
            // printf("> WiFi connected \n");
            if(WIFI_GetIP_Address(IP_Addr) == WIFI_STATUS_OK) {
                printf("> IP Address : %d.%d.%d.%d\n",
                       IP_Addr[0],
                       IP_Addr[1],
                       IP_Addr[2],
                       IP_Addr[3]);
                return true;
            } else {
                printf("> ERROR : es-wifi module CANNOT get IP address\n");
            }
        } else {
            printf("> ERROR : es-wifi module NOT connected\n");
        }
    } else {
        printf("> ERROR : WIFI Module cannot be initialized.\n");
    }
    return false;
}


/**
  * @brief  check WiFi connection status, retry once if it's offline
  * @param  None
  * @retval True for WiFi (re)connected, False if reconnection failed
  */

bool checkWiFi(void)
{
    uint8_t  ip_addr[4];
    if(WIFI_GetIP_Address(ip_addr) == WIFI_STATUS_OK) return true;
    else {
        return connectWiFi();
    }
}

/**
  * @brief  create a TCP session on a server
  * @param  serverUrl : TCP server URL
  * @param  serverPort : port TCP server is listening on
  * @retval true if connection established
  */
bool connectToServer(char *serverUrl, uint16_t serverPort, uint8_t socket_id)
{
    uint8_t  serverIP[] = {0, 0, 0, 0};
    uint16_t trials = CONNECTION_TRIAL_MAX;

    while (trials--) {
        // get the server IP through a (local) DNS resolve
        if (WIFI_GetHostAddress(serverUrl, serverIP) == WIFI_STATUS_OK) {

            printf("> %s resolved to: %d.%d.%d.%d\n", serverUrl,
                   serverIP[0],
                   serverIP[1],
                   serverIP[2],
                   serverIP[3]);
            // establish TCP connection to server
            if( WIFI_OpenClientConnection(socket_id, WIFI_TCP_PROTOCOL, "InfluxDB", serverIP, serverPort, 0) == WIFI_STATUS_OK) {
                printf("> Connected to %s .\n", serverUrl);
                return true;
            }
        } else {
            printf("> ERROR : Cannot resolve URL: %s\n", serverUrl);
        }
    }
    if(!trials) {
        printf("> ERROR : Cannot establish connection\n");
    }
    return false;
}