Home automation using Xbee radios
Dependencies: EthernetNetIf HTTPServer RPCInterface mbed C12832_lcd
main.cpp
- Committer:
- chrisisthefish
- Date:
- 2013-12-09
- Revision:
- 11:03ff417d0d5d
- Parent:
- 10:de0be690b3c0
File content as of revision 11:03ff417d0d5d:
/* Analog Types: 0 = No connection 1 = Analog Devices TMP36 Temperature Sensor Digital Types: 0 = No connection 1 = Light Control (Digital Output) 2 = Motion Sense (Digital Input) 3 = Button (Digital Input) */ #include "mbed.h" #include "EthernetNetIf.h" #include "HTTPServer.h" #include "SerialRPCInterface.h" #include "XbeeCommLib.h" #include "C12832_lcd.h" DigitalIn pb(p8); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); Serial xbeeSerial(p9, p10); C12832_LCD lcd; unsigned char data[500]; int dataCounter = 0; bool clear = false; int motionDetector0 = 1; int motionDetector1 = 1; int button0 = 1; int button1 = 1; //Create port variables float ReadTemperatureSensor0 = 0.0; float ReadTemperatureSensor1 = 0.0; float ReadTemperatureSensor2 = 0.0; int ReadMotionEnable0 = 0; int ReadMotionEnable1 = 0; int WriteMotionEnable0 = 0; int WriteMotionEnable1 = 0; int ReadLightSwitch0 = 0; int ReadLightSwitch1 = 0; int ReadLightSwitch2 = 0; int WriteLightSwitch0 = 0; int WriteLightSwitch1 = 0; int WriteLightSwitch2 = 0; //Make these variables accessible over RPC by attaching them to an RPCVariable RPCVariable<float> RPCTemperatureSensor0(&ReadTemperatureSensor0, "Temp0"); //RPCVariable<float> RPCTemperatureSensor1(&ReadTemperatureSensor1, "Temp1"); RPCVariable<float> RPCTemperatureSensor2(&ReadTemperatureSensor2, "Temp2"); RPCVariable<int> RPCReadMotionEnable0(&ReadMotionEnable0, "RMotion0"); RPCVariable<int> RPCReadMotionEnable1(&ReadMotionEnable1, "RMotion1"); RPCVariable<int> RPCWriteMotionEnable0(&WriteMotionEnable0, "WMotion0"); RPCVariable<int> RPCWriteMotionEnable1(&WriteMotionEnable1, "WMotion1"); RPCVariable<int> RPCReadLightSwitch0(&ReadLightSwitch0, "RLight0"); RPCVariable<int> RPCReadLightSwitch1(&ReadLightSwitch1, "RLight1"); RPCVariable<int> RPCWriteLightSwitch0(&WriteLightSwitch0, "WLight0"); RPCVariable<int> RPCWriteLightSwitch1(&WriteLightSwitch1, "WLight1"); EthernetNetIf eth; HTTPServer svr; IpAddr Ip; struct xbee { // radio prototype with addresss, location, pointer to sensor list unsigned int addrHigh; // upper 16 bits address of sensor unsigned int addrLow; // lower address of sensor unsigned short digitalData; unsigned short digitalDataOutput; bool digitalDataValid; bool firstDigitalData; int digitalType[10]; float analogData[4]; int analogType[4]; float* analogRpcDataPointer[4]; int* rpcDataPointer[10]; int* writeRpcDataPointer[10]; int* prevData[10]; Timer* timerList[10]; struct xbee * next; // pointer to next struct }; struct xbee xbeeList[3]; int xbeeCount = 3; void xbeeSerialHandler() { //printf("Xbee\n"); if(clear){ dataCounter = 0; clear = false; } if(dataCounter < 500){ while(xbeeSerial.readable() == true && dataCounter < 500){ // led4 = 1; data[dataCounter] = xbeeSerial.getc(); dataCounter++; // led4 = 0; } } else{ printf("Serial data buffer overflow. Resetting buffer...\n"); dataCounter = 0; data[dataCounter] = xbeeSerial.getc(); } } int main() { printf("\n\nBeginning Setup\n"); // Ethernet Setup EthernetErr ethErr = eth.setup(); if(ethErr){ printf("Error %d in setup.\n", ethErr); return -1; } printf("Setup OK\n"); Ip = eth.getIp(); lcd.cls(); lcd.printf("IP Address: %d.%d.%d.%d\r\n", Ip[0], Ip[1], Ip[2], Ip[3]); // Add RPCHandler svr.addHandler<RPCHandler>("/rpc"); // Show that the server is ready and listening svr.bind(80); printf("RPC Server Ready\n"); xbeeList[0].addrHigh = 0x0013a200; xbeeList[0].addrLow = 0x4079d00b; //Router0 xbeeList[0].analogType[1] = 1; //Analog Devices TMP36 Temp Sensor xbeeList[0].digitalType[0] = 1; //Light control (output) xbeeList[0].digitalType[2] = 2; //Motion sensor (input) xbeeList[0].digitalType[3] = 3; //Button (input) xbeeList[0].analogRpcDataPointer[1] = &ReadTemperatureSensor0; xbeeList[0].rpcDataPointer[0] = &ReadLightSwitch0; xbeeList[0].writeRpcDataPointer[0] = &WriteLightSwitch0; xbeeList[0].rpcDataPointer[2] = &ReadMotionEnable0; xbeeList[0].writeRpcDataPointer[2] = &WriteMotionEnable0; xbeeList[0].prevData[2] = &motionDetector0; Timer motionTimer0; xbeeList[0].timerList[2] = &motionTimer0; xbeeList[0].prevData[3] = &button0; xbeeList[1].addrHigh = 0x0013a200; xbeeList[1].addrLow = 0x4079d023; //Router1 xbeeList[1].digitalType[0] = 1; //Light control (output) xbeeList[1].digitalType[2] = 2; //Motion sensor (input) xbeeList[1].digitalType[3] = 3; //Button (input) xbeeList[1].rpcDataPointer[0] = &ReadLightSwitch1; xbeeList[1].writeRpcDataPointer[0] = &WriteLightSwitch1; xbeeList[1].rpcDataPointer[2] = &ReadMotionEnable1; xbeeList[1].writeRpcDataPointer[2] = &WriteMotionEnable1; xbeeList[1].prevData[2] = &motionDetector1; Timer motionTimer1; xbeeList[1].timerList[2] = &motionTimer1; xbeeList[1].prevData[3] = &button1; xbeeList[2].addrHigh = 0x0013a200; xbeeList[2].addrLow = 0x406874c6; //Router2 xbeeList[2].analogType[1] = 1; //Analog Devices TMP36 Temp Sensor xbeeList[2].analogRpcDataPointer[1] = &ReadTemperatureSensor2; printf("Initialization finished\n\n"); // TODO: Read sensors and set RPC variables to initial values Timer tm; tm.start(); //Main program loop while(true){ Net::poll(); xbeeSerialHandler(); monitorXbee(); compareDigitalReadWrite(); monitorTimers(); // TODO: Poll sensors and reset RPC variables. if(tm.read() > 1){ led1 = !led1; tm.start(); lcdDisplay(); } } } int getDigitalValue(int i, short pins){ return ((pins>>i)&1); } float analogInputFormat(float data, int type){ // Incoming data is in volts: // Example: data = 0.7 -> 0.7 Volts switch (type){ case 1: //Analog Devices TMP36 Temp Sensor: 1 deg F per 10mV return data * 100; //Multiply voltage by 100 to get Temperature case 2: return data; case 3: return data; default: return data; } } void digitalInputHandle(unsigned int addrHigh, unsigned int addrLow, unsigned short data){ if(DEBUG) printf("Digital input handler: Address: %x %x\nDigital Data = %d\n", addrHigh, addrLow, data); unsigned short tmp = data; for(int i = 0; i < xbeeCount; i++){ if(xbeeList[i].addrHigh == addrHigh && xbeeList[i].addrLow == addrLow){ //Addresses match match //Place the digital data in the appropriate position in the struct xbeeList[i].digitalData = data; for(int j = 0; j < 10; j++){ if(xbeeList[i].digitalType[j] != 2){ //Make sure we don't overwrite the motion enable RPC variable //Update RPC variable, if present if(xbeeList[i].rpcDataPointer[j] != NULL){ *xbeeList[i].rpcDataPointer[j] = tmp & 1; tmp = tmp >> 1; } } } //if(xbeeList[i].firstDigitalData == false && xbeeList[i].digitalDataValid == false){ // xbeeList[i].firstDigitalData = true; // }else if(xbeeList[i].firstDigitalData == true && xbeeList[i].digitalDataValid == false){ xbeeList[i].digitalDataValid = true; // xbeeList[i].firstDigitalData = false; // } break; } if(i == (xbeeCount - 1)){ printf("No matching addresses found\n"); } } } void analogInputHandle(unsigned int addrHigh, unsigned int addrLow, int index, float data){ float analogData; if(DEBUG) printf("Analog input handler: Address: %x %x\nAnalog Index = %d Analog Value = %f\n", addrHigh, addrLow, index, data); if(index < 0){ printf("ERROR: Analog input index is negative\n"); return; } for(int i = 0; i < xbeeCount; i++){ if(xbeeList[i].addrHigh == addrHigh && xbeeList[i].addrLow == addrLow){ //Addresses match match if(DEBUG) printf("Xbee %d radio address match\n", i); if(xbeeList[i].analogType[index]){ //Verify that analog input is actually enabled. If not, ignore the data //Place the analog data in the appropriate position in the struct analogData = analogInputFormat(data, xbeeList[i].analogType[index]); xbeeList[i].analogData[index] = analogData; if(xbeeList[i].analogRpcDataPointer[index] != NULL){ //Also push the analog data to the RPC variable *xbeeList[i].analogRpcDataPointer[index] = analogData; //printf("Storing value %f into RPC pointer. Value stored is %f\n", analogData, *xbeeList[i].analogRpcDataPointer[index]); }else printf("No valid RPC variable found\n"); } break; } if(i == (xbeeCount - 1)){ printf("No matching addresses found\n"); } } } /* This is bad code I need to replace this Possibly change name to monitorRpcValues */ void compareDigitalReadWrite(){ int mask = 1; int i, digiIndex; bool rpcValue = false; bool pinValue = false; for(i = 0; i < xbeeCount; i++){ //Loop through all xbees mask = 1; if(xbeeList[i].digitalDataValid){ for(digiIndex = 0; digiIndex < 10; digiIndex++){ //Loop through all digital inputs to see if they do not match the corresponding RPC variable if(xbeeList[i].digitalData & mask) pinValue = true; else pinValue = false; //Check for both the motion enable value changes as well as actual motion sensor activations if(xbeeList[i].digitalType[digiIndex] == 2){ //Is this digital I/O a motion detector (digital input)? if(xbeeList[i].writeRpcDataPointer[digiIndex] != NULL && xbeeList[i].rpcDataPointer[digiIndex] != NULL){ //Determine if user changed value of motion enable. If so, update read RPC variable if(*xbeeList[i].writeRpcDataPointer[digiIndex] != *xbeeList[i].rpcDataPointer[digiIndex]){ *xbeeList[i].rpcDataPointer[digiIndex] = *xbeeList[i].writeRpcDataPointer[digiIndex]; } if(*xbeeList[i].rpcDataPointer[digiIndex]){ //Is motion enabled? if(pinValue != *xbeeList[i].prevData[digiIndex]){ //See if the motion detection pin has changed value if(pinValue == 0){ //Motion has been detected //turn on the light & restart timer printf("Xbee%d: Motion detected\n", i); *xbeeList[i].writeRpcDataPointer[0] = 1; xbeeList[i].timerList[digiIndex]->start(); } //update motion detector value with new state *xbeeList[i].prevData[digiIndex] = pinValue; } } } } //Check for button state if present if(xbeeList[i].digitalType[digiIndex] == 3){ //Is this digital I/O a button (digital input)? if(xbeeList[i].prevData[digiIndex] != NULL){ if(pinValue != *xbeeList[i].prevData[digiIndex]){ //See if the button pin has changed value if(pinValue == 0){ //Button press detected if(xbeeList[i].rpcDataPointer[0] != NULL){ if(*xbeeList[i].rpcDataPointer[0]) rpcValue = true; else rpcValue = false; } //turn the light on or off printf("Xbee%d: Button pressed\n", i); if(rpcValue) *xbeeList[i].writeRpcDataPointer[0] = 0; else *xbeeList[i].writeRpcDataPointer[0] = 1; } //update value with new state *xbeeList[i].prevData[digiIndex] = pinValue; } } } if(xbeeList[i].digitalType[digiIndex] == 1){ //Is this digital I/O a light control (digital output)? if(xbeeList[i].writeRpcDataPointer[digiIndex] != NULL){ if(*xbeeList[i].writeRpcDataPointer[digiIndex]) rpcValue = true; else rpcValue = false; if(pinValue != rpcValue){ if(DEBUG) printf("Xbee%d: Writing %d to digital output %d\n", i, rpcValue, digiIndex); //This means that the digital output is in the incorrect state, Therefore write out the RPC state to the radio digitalWriteXbee(xbeeList[i].addrHigh, xbeeList[i].addrLow, digiIndex, rpcValue); xbeeList[i].digitalData = (xbeeList[i].digitalData & ~mask) | (rpcValue << digiIndex); //Update the digitalData value with the new output value } //Otherwise, it matches if(xbeeList[i].rpcDataPointer[digiIndex] != NULL) *xbeeList[i].rpcDataPointer[digiIndex] = rpcValue; //Update the read RPC variable to reflect the actual value } } mask = mask << 1; } } } } void monitorTimers(){ for(int i = 0; i < xbeeCount; i++){ //Loop through all xbees for(int digiIndex = 0; digiIndex < 10; digiIndex++){ //Loop through all digital I/O if(xbeeList[i].digitalType[digiIndex] == 2){ //See if I/O is a motion detector input if(xbeeList[i].rpcDataPointer[digiIndex] != NULL){ //Make sure RPC value is valid if(*xbeeList[i].rpcDataPointer[digiIndex]){ //Check if motion detection is enabled if(xbeeList[i].timerList[digiIndex]->read() > 15){ //Check if timer has expired if(xbeeList[i].rpcDataPointer[0] != NULL) *xbeeList[i].writeRpcDataPointer[0] = 0; //If timer has expired, turn light off } } } } } } } void lcdDisplay(){ int tempCount = 0; int lightCount = 0; // lcd.cls(); // lcd.locate(0,0); // lcd.printf("IP Address: %d.%d.%d.%d\r\n", Ip[0], Ip[1], Ip[2], Ip[3]); for(int i = 0; i < xbeeCount; i++){ for(int j = 0; j < 4; j++){ if(xbeeList[i].analogRpcDataPointer[j] != NULL){ lcd.locate(0,(tempCount*10)+10); lcd.printf(" "); lcd.locate(0,(tempCount*10)+10); lcd.printf("Temp%d: %4.2fF", i, *xbeeList[i].analogRpcDataPointer[j]); tempCount++; break; } } if(xbeeList[i].rpcDataPointer[0] != NULL && xbeeList[i].digitalType[0] == 1){ lcd.locate(70,(lightCount*10)+10); lcd.printf(" ", i); lcd.locate(70,(lightCount*10)+10); if(*xbeeList[i].rpcDataPointer[0]){ lcd.printf("Light%d: On", i); }else{ lcd.printf("Light%d: Off", i); } lightCount++; } } }