a sensor hub for monitoring home environment
Dependencies: HTS221 LIS3MDL LPS22HB LSM303AGR LSM6DSL VL53L0X picojson
Fork of HelloWorld_ST_Sensors by
main.cpp
- Committer:
- jaafaryn
- Date:
- 2017-12-19
- Revision:
- 13:f8e84b12665c
- Parent:
- 12:058b012dbebe
- Child:
- 14:0c8967e20f93
File content as of revision 13:f8e84b12665c:
/*------------------------------------------------------------------------------ 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 --> done - add light sensor to monitor illuminance --> low priority - improve reading by either: reduce power on time of WiFi module (batch logging) or by compensating for board own temperature --> WiP - 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"); RESET_NEXTION; 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; NO_WAKEUP_ON_SERIALIN;// no wakeup on serial in SLEEP_ON_NOTOUCH_30S;// sleep after 30sec no touch WAKEUP_ON_TOUCH;// wake up on touch /*Initialize WIFI module */ WiFi_on = connectWiFi(); if (WiFi_on) { led3 = 1; //WiFi_led_ticker.attach(&toggle_led3_cb, 0.25); rtc_synced = sync_rtc(); } // 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() { time_t rawtime; tm *pTime; 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_val); // 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_val); 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; 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; } if (rtc_synced) { time(&rawtime); pTime = localtime(&rawtime); printf ("Current local time and date: %s", asctime(pTime)); //printf("> %d:%d:%d\n", pTime->tm_hour, pTime->tm_min, pTime->tm_sec); } else { sync_rtc(); } 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) { if (dist_val < 500) { nextion.printf("sleep=0\xff\xff\xff");// send wake up command } distance_val = dist_val; } else { distance_val = 9999; } // since this is a 1-sec period ticker, we do clock display refresh in here too // get a formatted local time to be displayed if (rtc_synced) { time(&rawtime); pTime = localtime(&rawtime); nextion.printf("hour.txt=\"%d\"\xff\xff\xff", pTime->tm_hour); nextion.printf("minute.txt=\"%d\"\xff\xff\xff", pTime->tm_min); //nextion.printf("vis sec,%d\xff\xff\xff", pTime->tm_sec % 2 == 0 ? 1 : 0); } 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"); char fwVer[32]; if(WIFI_GetModuleFwRevision(fwVer) == WIFI_STATUS_OK) { printf("> Firmware version: %s\n", fwVer); } 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_SetPowerSaveMode(1, 1000) == WIFI_STATUS_OK) { printf("> es-wifi entered power save mode\n"); } else { printf("> ERROR: es-wifi did not enter power save mode\n"); } if( WIFI_Connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, WIFI_ECN_WPA2_PSK) == WIFI_STATUS_OK) { 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]); WIFI_ICON_ON; 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"); } WIFI_ICON_OFF; 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, "TCP_Client", 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; } /** * @brief get current unix timestamp and use it to sync rtc * @retval True if successful, False if failed */ bool sync_rtc() { // 1- establish connection to time server (socket 2) uint8_t socketid = 2; uint16_t dataLen; if (checkWiFi()) { if (connectToServer(TIME_SERVER_URL, TIME_SERVER_PORT, socketid)) { sprintf((char *)http_request, "GET %s HTTP/1.1\r\nHost: %s \r\n", TIME_SERVER_QUERY, TIME_SERVER_URL); strcat((char *)http_request, "Connection: Close\r\n\r\n"); reqLen = strlen((char *)http_request); if (WIFI_SendData(socketid, http_request, reqLen, &dataLen, WIFI_WRITE_TIMEOUT) != WIFI_STATUS_OK) { printf("> ERROR: Could not send request to %s\n", TIME_SERVER_URL); } else { printf("> TS: Sent %d bytes\n", dataLen); } // 2- get server response and parse the json WIFI_ReceiveData(socketid, http_resp, sizeof(http_resp), &dataLen, WIFI_READ_TIMEOUT); if(dataLen > 0) { printf("> TS: Received %d bytes\n", dataLen); // extract the body (json payload) from the response char *resp_body = strstr((char *)http_resp, "\r\n\r\n"); // get the body + "OK" resp_body = strtok(resp_body, "\r\n"); // get rid of 'OK' picojson::value json_val; string err = picojson::parse(json_val, resp_body, resp_body + strlen(resp_body)); if(err.empty()) { // 3- convert timestamp to local time and sync rtc uint32_t timestamp_val = (unsigned)json_val.get("timestamp").get<double>(); printf("> utc_ts = %u \n",timestamp_val); // print utc timestamp_val -= 3600*5; // EST: utc - 5h set_time(timestamp_val); WIFI_CloseClientConnection(socketid); // close socket on success return true; } else { printf("> ERROR: TS json parsing\n"); } } else { printf("> ERROR: Did not receive data from TS server\n"); } WIFI_CloseClientConnection(socketid); // close socket on failure to retrieve time } else { printf("> ERROR: Cannot establish connection to %s \n", TIME_SERVER_URL); } } return false; }