iot_water_monitor_v2

Dependencies:   easy-connect-v16 Watchdog FP MQTTPacket RecordType-v-16 watersenor_and_temp_code

Application/main.cpp

Committer:
DuyLionTran
Date:
2018-04-03
Revision:
57:898fcb6692cd
Parent:
56:3729bedac5ab

File content as of revision 57:898fcb6692cd:

/**
  * Revision
  * version 1.0
  * ....
  * version 2.5 	02-14-2018: 3rd relay and remote time setting are added
  * version 2.6 	02-14-2018: DO Sensor added, calibration is still on the way
  * version 2.6.3 	02-19-2018: developing calibration. the average voltage is ok
  * version 2.6.5 	02-21-2018: developing calibration. Sensor read is completely ok
  * version 2.6.8 	02-27-2018: developing DO calibration. DS18B20 temperature sensor is added
  * version 2.7 	03-04-2018: DO calibration complete. IWDG is added
  * version 2.7.5 	03-08-2018: DS18B20 & IWDG is being developed
  * version 2.7.5a	03-08-2018: DS18B20 problem discovered at line 42th ReadSensor.cpp
                                Upload RTC time converted to epoch
  * version 2.8  	03-18-2018: DS18B20 problem solved
  * version 2.8.5  	03-19-2018: Set time to turn on/off the relay
  * version 2.9  	03-22-2018: Watchdog worked. Some hardware bugs found
  * version 2.9.7  	03-29-2018: Try to upload 1 more time if upload fail
  * version 2.9.7  	03-30-2018
  * version 2.9.8  	03-04-2018  Minor changes. Time frame updated to IBM Watson every 60s
  */

/***************************************************************
 * Includes
 ***************************************************************/
#include "mbed.h"

#include "ReadSensor.h"
#include "SimpleMQTT.h"
#include "CommandExecution.h"
#include "flash_programming.h"

#include "Watchdog.h"

/***************************************************************
 * Definitions
 ***************************************************************/
//#define READ_ANALOG_SOFTTIMER 
 
#define READ_SECOND							1 	 /* Read timer every 1 second(s) */
#define INTERVAL_BETWEEN_EACH_UPLOAD_TYPE	10   /* The interval between each upload type in second */
#define RECONNECT_WIFI                      60   /* Try to reconnect to wifi */
#ifdef READ_ANALOG_SOFTTIMER
	#define READ_ANALOG_MS				    30
#endif
#define PROCESS_SENSOR_VALUE_S			    2
#define CALIB_STATE_CHANGE_PERIOD_S         5
#define ALARM_TIME_ODD                      20

#define SEND_TIME_INTERVAL                  60  /* Send Time frame every 60s */
/***************************************************************
 * Variables
 ***************************************************************/
bool        isUploading         = false;
bool		isSendingData       = false;
bool        isUploadImmediately = false;
bool 		isFirstUpload       = true;
uint8_t 	uploadType          = SENSOR_VALUE;
uint8_t     currentCalibMode    = 1;
uint8_t     calibStateCounter   = 0;

uint32_t 	lastRead        		= 0;
uint32_t    noWiFilastRead 			= 0;
uint16_t    intervalSecondCounter   = 0;  
uint32_t    uploadPeriodCounter 	= 0;

#ifdef READ_ANALOG_SOFTTIMER
	uint32_t 	lastReadAnalog			= 0;
#endif

struct UploadValue DataStruct;
Watchdog           wd;

extern float doValue;
extern float temperature;
extern bool  isCalibrating;

/***************************************************************
 * Structs/Classess
 ***************************************************************/
static Serial pc(SERIAL_TX, SERIAL_RX); 

//DigitalOut 	myled(LED1);
DigitalOut 	myled(A6);
DigitalOut  espEn(D2);
DigitalOut  espRs(D7);

Timer 		UploadTimer;
#ifdef READ_ANALOG_SOFTTIMER
	Timer 		ReadAnalogTimer;
#endif
Ticker 		DisplayDO;

/***************************************************************
 * Unity function definitions
 ***************************************************************/
void ReadAllFlashValues();
void SensorRun(); 
void enableESP();

void BinkLEDStart();

void AutomaticHandle();
void TimeAlarmHandle();

/***************************************************************
 * Unity function declarations
 ***************************************************************/ 
void ReadAllFlashValues() {
	DataStruct.ADC_TEMPVal 					= 0;
	DataStruct.ADC_DOVal 					= 0;
	DataStruct.SENSOR_TEMPVal      			= 0;
	DataStruct.SENSOR_DOVal                 = 0;
	DataStruct.RELAY_State_1				= FP_ReadValue(RELAY1_ADDRESS);
	DataStruct.RELAY_State_2				= FP_ReadValue(RELAY2_ADDRESS);
	DataStruct.RELAY_State_3				= FP_ReadValue(RELAY3_ADDRESS);
	DataStruct.CONFIG_Mode					= FP_ReadValue(MODE_ADDRESS);
	DataStruct.CONFIG_OxyThreshold			= FP_ReadValue(OXY_THRES_ADDRESS);
	DataStruct.CONFIG_TemperatureThreshold	= FP_ReadValue(TEMP_THRES_ADDRESS);
	DataStruct.CONFIG_UploadInterval		= FP_ReadValue(UPLOAD_PERIOD_ADDRESS);
	DataStruct.CONFIG_AlarmTime             = FP_ReadValue(ALARM_TIME_ADDRESS);
	DataStruct.CONFIG_SetRelayState_1       = FP_ReadValue(SET_RELAY_1_ADDRESS);
	DataStruct.CONFIG_SetRelayState_2       = FP_ReadValue(SET_RELAY_2_ADDRESS);
	printf("All values: %d %d %d %d %d %d %d %d %d\r\n", DataStruct.RELAY_State_1, DataStruct.RELAY_State_2,
	                                            DataStruct.CONFIG_Mode,   DataStruct.CONFIG_OxyThreshold, 	
	                                            DataStruct.CONFIG_TemperatureThreshold, DataStruct.CONFIG_UploadInterval,
	                                            DataStruct.CONFIG_AlarmTime, 
	                                            DataStruct.CONFIG_SetRelayState_1, DataStruct.CONFIG_SetRelayState_2);
	if (DataStruct.CONFIG_Mode == 0xFFFFFFFF) {
		DataStruct.CONFIG_Mode = 0;
	}
	if (DataStruct.CONFIG_OxyThreshold == 0xFFFFFFFF) {
		DataStruct.CONFIG_OxyThreshold = 50;
	}
	if (DataStruct.CONFIG_TemperatureThreshold == 0xFFFFFFFF) {
		DataStruct.CONFIG_TemperatureThreshold = 25;
	}
	if (DataStruct.CONFIG_UploadInterval == 0xFFFFFFFF) {
		DataStruct.CONFIG_UploadInterval = 300;
	}
	CE_HandleRelays(DataStruct.RELAY_State_1, DataStruct.RELAY_State_2, DataStruct.RELAY_State_3);
}

void SensorRun() {
	if (!isSendingData) {
		wd.Service();
		for (uint8_t j = 0; j < SCOUNT; j++) {
			SENSOR_AnalogRead();
		}
		SENSOR_GetDOValue();
		DataStruct.SENSOR_DOVal = doValue;
		DataStruct.SENSOR_TEMPVal = temperature;
		if (isCalibrating) {
			SENSOR_DoCalibration(currentCalibMode);
			if (currentCalibMode == 3) {
				currentCalibMode = 1;
				isCalibrating    = false;
			}
			calibStateCounter++;
			
			/* Change calibration mode every PROCESS_SENSOR_VALUE_S*CALIB_STATE_CHANGE_PERIOD_S second(s) */
			if ((calibStateCounter % CALIB_STATE_CHANGE_PERIOD_S) == 0) {      
				currentCalibMode++;
			}
		}			
	}
	else {
		printf("No sensor reading because uploading data\r\n");	
	}
}

void enableESP() {
   	espRs = 0;	
   	espEn = 0;
   	wait(2);
   	espEn = 1;
   	espRs = 1;	
   	printf("ESP enabled\r\n");
}

void BinkLEDStart() {
   	myled = 1;
	for (uint8_t j = 0; j < 8; j++) {
		myled = !myled;	
		wait(0.2);
	}
   	myled = 0;	
}

void AutomaticHandle() {
	if (DataStruct.CONFIG_Mode == 1) {            /* Automatic mode */
//		printf("DataStruct.SENSOR_DOVal*100 %d\r\n",(uint32_t)(DataStruct.SENSOR_DOVal*100));
		if ((uint32_t)(DataStruct.SENSOR_DOVal*10) >= DataStruct.CONFIG_OxyThreshold) {
			/* Turn on the pumps */
			DataStruct.RELAY_State_1 = 1;      
			DataStruct.RELAY_State_2 = 1;  
			DataStruct.RELAY_State_3 = 1;   
			 
		}
		else {
			/* Turn off the pumps */
			DataStruct.RELAY_State_1 = 0;      
			DataStruct.RELAY_State_2 = 0;
			DataStruct.RELAY_State_3 = 0;   			
		}
		CE_HandleRelays(DataStruct.RELAY_State_1, DataStruct.RELAY_State_2, DataStruct.RELAY_State_3);   
		FP_WriteRelayStates(DataStruct.RELAY_State_1, DataStruct.RELAY_State_2, DataStruct.RELAY_State_3);
	}	
}

void TimeAlarmHandle(time_t CurrentTime) {
	if (CurrentTime == (DataStruct.CONFIG_AlarmTime)) {
		DataStruct.RELAY_State_1 = DataStruct.CONFIG_SetRelayState_1; 
		DataStruct.RELAY_State_2 = DataStruct.CONFIG_SetRelayState_2;
		CE_HandleRelays(DataStruct.RELAY_State_1, DataStruct.RELAY_State_2, DataStruct.RELAY_State_3);   
		FP_WriteRelayStates(DataStruct.RELAY_State_1, DataStruct.RELAY_State_2, DataStruct.RELAY_State_3);		
	}
}
/***************************************************************
 * Main
 ***************************************************************/ 
int main() {   
   	pc.baud(115200);
   	printf("PROGRAM STARTS\r\n");
   	set_time(1514768400);                //01-01-2018 8:30AM
	enableESP();
   	UploadTimer.start();
   	
   	#ifdef READ_ANALOG_SOFTTIMER
   		ReadAnalogTimer.start();
   	#endif
   	
   	BinkLEDStart();
   	
   	lastRead = 0;
   	pc.printf("\r\nViKa IoT Water Monitor mbed Application\r\n");     
   	pc.printf("\r\nconnecting to AP\r\n");   
   	         
	wd.Configure(24.8);
	wd.Service();
	
   	NetworkInterface* network = easy_connect(true);
   	if (!network) {
       	printf ("Error easy_connect\n\r");
       	wifiConnected = false;
   	} 
   	wd.Service();
	printf ("ATTEMPT CONNECT\n\r");
	MQTTNetwork mqttNetwork(network);	
	MQTT::Client<MQTTNetwork, Countdown, MQTT_MAX_PACKET_SIZE> client(mqttNetwork);	
	wd.Service();
	MQTT_AttemptConnect(&client, &mqttNetwork, network, DataStruct);
	wd.Service();
	if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) {
		printf ("---ERROR line : %d, error type %d\n\r", __LINE__, connack_rc);
	    wifiConnected = false;
//	    while (true)
//	    	wait(1.0); // Permanent failures - don't retry
	}
	if (wd.WatchdogCausedReset()) {
		printf("Watchdog caused reset.\r\n");
	}
	wd.Service();
	DisplayDO.attach(&SensorRun, PROCESS_SENSOR_VALUE_S);
	ReadAllFlashValues();
	SENSOR_ReadDoCharacteristicValues();
	BinkLEDStart();
	wd.Service();
	lastRead = UploadTimer.read();	
	
   	myled = 1;   
	while (true) {
		time_t seconds = time(NULL);	
		AutomaticHandle();
		TimeAlarmHandle(seconds);
		#ifdef READ_ANALOG_SOFTTIMER
			if ((uint32_t)(ReadAnalogTimer.read_ms() - lastReadAnalog) > READ_ANALOG_MS) {
				SENSOR_AnalogRead();
				lastReadAnalog = ReadAnalogTimer.read_ms();
			}
		#endif
		if (wifiConnected) {
			if(connected == true) {
				/* Upload for the first time */
				if (isFirstUpload) {
					if (MQTT_PublishAll(&client, seconds, SENSOR_VALUE, DataStruct) != MQTT::SUCCESS) {
						wait(2);
						MQTT_PublishAll(&client, seconds, SENSOR_VALUE, DataStruct);
						wait(2);
						uint32_t uploadTimeFramePeriod = SEND_TIME_INTERVAL;
						if (MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod) ==  MQTT::SUCCESS) {
						}
						else {
							MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod);
						}
					}
					else {
						wait(2);
						uint32_t uploadTimeFramePeriod = SEND_TIME_INTERVAL;
						if (MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod) ==  MQTT::SUCCESS) {
						}
						else {
							MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod);
						}						
					}
					wait(2);
					isFirstUpload = false;
				}
					/* Periodic upload */
			       	if ((uint32_t)(UploadTimer.read() - lastRead) >= READ_SECOND) {               // Read timer every readSecond(s)					       		
			       		/* Start uploading data */	
						if (!isUploading) {
							wd.Service();
							uploadPeriodCounter++;
							if (uploadPeriodCounter == DataStruct.CONFIG_UploadInterval) {	
								uploadPeriodCounter 	= 0;
								isUploading         	= true;
								intervalSecondCounter 	= INTERVAL_BETWEEN_EACH_UPLOAD_TYPE;
							}
							else if ((uploadPeriodCounter % SEND_TIME_INTERVAL) == 0) {
								uint32_t uploadTimeFramePeriod = SEND_TIME_INTERVAL;
								if (MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod) ==  MQTT::SUCCESS) {
									myled = 1;
								}
								else {
									if (MQTT_PublishDeviceManage(&client, seconds, DataStruct.CONFIG_UploadInterval, uploadTimeFramePeriod) ==  MQTT::SUCCESS) {
										myled = 1;
									}
									else {
										myled = 0;	
									}
								}
							}					
						}
						else {
							wd.Service();
							if (intervalSecondCounter == INTERVAL_BETWEEN_EACH_UPLOAD_TYPE) {
								isSendingData = true;
								if (MQTT_PublishAll(&client, seconds, uploadType, DataStruct) ==  MQTT::SUCCESS) {
									myled = 1;
									uploadType++;
									if (uploadType > CONFIG_VALUE) {
										isUploading = false;
										uploadType  = SENSOR_VALUE;
										commandID++;
										UploadTimer.reset();
									}
								}
								else {
									/* Try to reupload */
									if (MQTT_PublishAll(&client, seconds, uploadType, DataStruct) ==  MQTT::SUCCESS) {
										myled = 1;
										uploadType++;
										if (uploadType > RELAY_STATE) {
											isUploading = false;
											uploadType  = SENSOR_VALUE;
											commandID++;
											UploadTimer.reset();
										}										
									}
									else {
										myled = 0;
										client.disconnect();
										mqttNetwork.disconnect();
										/* if we have lost the connection */ 
										MQTT_AttemptConnect(&client, &mqttNetwork, network, DataStruct);   										
									}
								}
								isSendingData = false;						
								intervalSecondCounter = 0;		
							}
							else {
								intervalSecondCounter++;
							}
						}
						lastRead = UploadTimer.read();
			    	}					       
		    	/* allow the MQTT client to receive subscribe messages and manage keep alive */
		    	wd.Service();
		    	client.yield(500);                                                        
			} 
			else if (connected == false) {
				connected = true;
			} 			
		}
		else {
			wd.Service();
			if ((uint32_t)(UploadTimer.read() - noWiFilastRead) >= RECONNECT_WIFI) {
			   	wifiConnected = true;
			   	network = easy_connect(true);
			   	MQTT_AttemptConnect(&client, &mqttNetwork, network, DataStruct);
			   	if (connack_rc == MQTT_NOT_AUTHORIZED || connack_rc == MQTT_BAD_USERNAME_OR_PASSWORD) {
			       	printf ("---ERROR line : %d, error type %d\n\r", __LINE__, connack_rc);
			       	wifiConnected = false;
			//       	while (true)
			//       		wait(1.0); // Permanent failures - don't retry
			   	}				
				noWiFilastRead = UploadTimer.read();
			}
		}
	}
}