Home automation using Xbee radios

Dependencies:   EthernetNetIf HTTPServer RPCInterface mbed C12832_lcd

Link to Notebook Page

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++;
        }
    }
}