Home automation using Xbee radios

Dependencies:   EthernetNetIf HTTPServer RPCInterface mbed C12832_lcd

Link to Notebook Page

main.cpp

Committer:
chrisisthefish
Date:
2013-12-04
Revision:
9:4b1e3531dd00
Parent:
8:e32fcca16102
Child:
10:de0be690b3c0

File content as of revision 9:4b1e3531dd00:

/*

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)

*/


#include "mbed.h"
#include "EthernetNetIf.h"
#include "HTTPServer.h"
#include "SerialRPCInterface.h"
#include "XbeeCommLib.h"

DigitalIn pb(p8);
DigitalOut led1(LED1);
DigitalOut led4(LED4);

Serial xbeeSerial(p9, p10);

unsigned char data[500];
int dataCounter = 0;
bool clear = false;

//Create port variables
float ReadTemperatureSensor0 = 0.0;
float ReadTemperatureSensor1 = 0.0;
int ReadMotionDetector0 = 1; //Motion detector is low-active
int ReadMotionDetector1 = 1; //Motion detector is low-active
int ReadLightSwitch0 = 0;
int ReadLightSwitch1 = 0;
int WriteLightSwitch0 = 0;
int WriteLightSwitch1 = 0;

//Make these variables accessible over RPC by attaching them to an RPCVariable
RPCVariable<float> RPCTemperatureSensor0(&ReadTemperatureSensor0, "TemperatureSensor0");
RPCVariable<float> RPCTemperatureSensor1(&ReadTemperatureSensor1, "TemperatureSensor1");
RPCVariable<int> RPCMotionDetector0(&ReadMotionDetector0, "MotionDetector0");
RPCVariable<int> RPCMotionDetector1(&ReadMotionDetector1, "MotionDetector1");
RPCVariable<int> RPCReadLightSwitch0(&ReadLightSwitch0, "ReadLightSwitch0");
RPCVariable<int> RPCReadLightSwitch1(&ReadLightSwitch1, "ReadLightSwitch1");
RPCVariable<int> RPCWriteLightSwitch0(&WriteLightSwitch0, "WriteLightSwitch0");
RPCVariable<int> RPCWriteLightSwitch1(&WriteLightSwitch1, "WriteLightSwitch1");

EthernetNetIf eth;  
HTTPServer svr;



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;
    int digitalType[10];
    float analogData[4];
    int analogType[4];
    float* analogRpcDataPointer[4];
    int* digitalOutRpcDataPointer[10];
    int* digitalInRpcDataPointer[10];
    Timer* timerList[10];
    struct xbee * next;    // pointer to next struct
};

struct xbee *root;

struct xbee xbeeList[3];
int xbeeCount = 3;




void xbeeSerialCallback() {
    //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() {
    
    //xbeeSerial.attach(&xbeeSerialCallback);
    
    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");
    
    // Add RPCHandler
    svr.addHandler<RPCHandler>("/rpc");
    
    // Show that the server is ready and listening
    svr.bind(80);
    printf("RPC Server Ready\n");
  
    /* This won't change, or we would lose the list in memory */
    //struct xbee *root;
    root = (struct xbee *) malloc( sizeof(struct xbee) );
    root->next = NULL;
    /* The node root points to has its next pointer equal to a null pointer 
    set */
    //struct xbee* xbee1;
//    struct xbee* xbee2;
//    struct xbee* xbee3;
    
//    printf("Beginning Xbee Radio Struct Setup\n");
//    xbee1 = addnode(root, 0x0013a200, 0x4079d00b); //Router0
//    xbee1->analogType[1] = 1;   //Analog Devices TMP36 Temp Sensor
//    xbee1->digitalType[0] = 1;  //Light control (output)
//    xbee1->digitalType[3] = 1;  //Motion sensor (input)
//    xbee1->analogRpcDataPointer[1] = &ReadTemperatureSensor1;
//    printf("xbee1 setup\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].analogRpcDataPointer[1] = &ReadTemperatureSensor0;
//    printf("Xbee0: Storing RPC variable address %d\nStored address is %d\n", &ReadTemperatureSensor1, xbeeList[0].analogRpcDataPointer[1]);
    xbeeList[0].digitalOutRpcDataPointer[0] = &ReadLightSwitch0;
    xbeeList[0].digitalInRpcDataPointer[2] = &ReadMotionDetector0;
    Timer motionTimer0;
    xbeeList[0].timerList[2] = &motionTimer0;
    
    
//    xbee2 = addnode(root, 0x0013a200, 0x4079d023); //Router1
//    xbee2->analogType[1] = 1;   //Analog Devices TMP36 Temp Sensor
//    xbee2->digitalType[0] = 1;  //Light control (output)
//    printf("xbee2 setup\n");
    xbeeList[1].addrHigh = 0x0013a200;
    xbeeList[1].addrLow = 0x4079d023; //Router1
    xbeeList[1].analogType[1] = 1;   //Analog Devices TMP36 Temp Sensor
    xbeeList[1].digitalType[0] = 1;  //Light control (output)
    xbeeList[1].digitalType[2] = 2;  //Motion sensor (input)
    xbeeList[1].analogRpcDataPointer[1] = &ReadTemperatureSensor1;
//    printf("Xbee1: Storing RPC variable address %d\nStored address is %d\n", &ReadTemperatureSensor2, xbeeList[1].analogRpcDataPointer[1]);
    xbeeList[1].digitalOutRpcDataPointer[0] = &ReadLightSwitch1;
    xbeeList[1].digitalInRpcDataPointer[2] = &ReadMotionDetector1;
    Timer motionTimer1;
    xbeeList[1].timerList[2] = &motionTimer1;
    
    
    //xbee3 = addnode(root, 0, 3);
//    xbee3->digitalType[3] = 1;  //Motion sensor (input)
    
    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();
        xbeeSerialCallback();
        monitorXbee();
        compareDigitalReadWrite();
        
        
        // TODO: Poll sensors and reset RPC variables. 
        
        if(tm.read() > 1){
            led1 = !led1;
            tm.start();
            
            monitorTimers();
        }
    }
}

struct xbee* addnode(struct xbee* root, unsigned int addrHigh, unsigned int addrLow){
    struct xbee* node;
    node = root;
    
    if ( node != 0 ) {
        while ( node->next != 0){
            node = node->next;
        }
    }
    node = (struct xbee *) malloc( sizeof(struct xbee) );
    node->next = NULL;
    node->addrHigh = addrHigh;
    node->addrLow = addrLow;
    return node;
}


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;
    }
//    return(data);
}



void digitalInputHandle(struct xbee* root, unsigned int addrHigh, unsigned int addrLow, unsigned short data){
    //struct xbee* node;
//    node = root;
    
    //printf("Digital input handler: Address: %x %x\nDigital Data = %d\n", addrHigh, addrLow, 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;
            
            //Need to update appropriate RPC variables
            break;
        }
        if(i == (xbeeCount - 1)){
            printf("No matching addresses found\n");
        }
    }
    
    
    /*
        Add code here to check for digital input changes.
        This is important to be able to detect motion
    */
    
 
    /*if ( node != 0 ) {
        while ( node->addrHigh != addrHigh){          
           node = node->next;
        }
        while(node->addrLow !=addrLow){
            node = node->next;
        }
    }
    else {
        printf("There is no node in the list");
    }
    
    if(node != 0){
        node->digitalData = data;
    }
    else{
        printf("Node is not in the list");
    }*/
    
}


void analogInputHandle(struct xbee* root,unsigned int addrHigh, unsigned int addrLow, int index, float data){
    //struct xbee* node;
//    node = root;
    float analogData;
    
    //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);
            
            //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");
        }
    }
    
    
    
    
    
    
    
    /*if ( node != 0 ) {
        printf("Comparing addrHigh %x to %x\n", node->addrHigh, addrHigh);
        while ( node->addrHigh != addrHigh){
            if(node->next != NULL){
                node = node->next;
            }else{
                printf("Reached end of search with no addrHigh match\n");
                break;
            }
            printf("Comparing addrHigh %x to %x\n", node->addrHigh, addrHigh);
        }
    
        printf("Comparing addrLow %x to %x\n", node->addrLow, addrLow);
        while(node->addrLow != addrLow){
            if(node->next != NULL){
                node = node->next;
            }else{
                printf("Reached end of search with no addrLow match\n");
                break;
            }
            printf("Comparing addrLow %x to %x\n", node->addrLow, addrLow);
        }
    }else {
        printf("There is no node in the list");
    }
    
    if(node != 0 && index >= 0){
        //Place the analog data in the appropriate position in the struct
        analogData = analogInputFormat(data, node->analogType[index]);
        node->analogData[index] = analogData;
        
        if(node->analogRpcDataPointer[index] != NULL){
            //Also push the analog data to the RPC variable
            *node->analogRpcDataPointer[index] = analogData;
            printf("Storing value %f into RPC pointer. Value stored is %f\n", analogData, *node->analogRpcDataPointer[index]);
        }
    }
    else{
        printf("Node is not in the list");
    }*/
}




void compareDigitalReadWrite(){
    int mask = 1;
    int i, digiIndex;
    int rpcValue = 0;
    int digiValue = 0;
    
    for(i = 0; i < xbeeCount; i++){ //Loop through all xbees
        mask = 1;
        
        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].digitalType[digiIndex] == 1){    //Is this digital I/O a light control (digital output)?
                
                if(*xbeeList[i].digitalOutRpcDataPointer[digiIndex])
                    rpcValue = 1;
                else
                    rpcValue = 0;
                
                if((xbeeList[i].digitalData & mask) != rpcValue){
                    printf("Xbee%d: Digital output %d = %d doesn't match RPC variable = %d  Updating Xbee...\n", i, digiIndex, xbeeList[i].digitalData & mask, rpcValue);
                    //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);
                    //printf("Old digitalData = %d\t", xbeeList[i].digitalData);
                    xbeeList[i].digitalData = (xbeeList[i].digitalData & ~mask) | (rpcValue << digiIndex); //Update the digitalData value with the new output value
                    //printf("Updated digitalData = %d, mask = %d, rpcValue = %d, digiIndex = %d\n", xbeeList[i].digitalData, mask, rpcValue, digiIndex);
                }
                //Otherwise, it matches
            }
            
            if(xbeeList[i].digitalType[digiIndex] == 2){    //Is this digital I/O a motion detector (digital input)?
                digiValue = (xbeeList[i].digitalData & mask);
                
                //Get the RPC value
                if(*xbeeList[i].digitalInRpcDataPointer[digiIndex])
                    rpcValue = 1;
                else
                    rpcValue = 0;
                    
                if(digiValue != rpcValue){  //This means there has been a state change, either motion detected, or sensor returning to normal
                    
                    if(digiValue == 0 || rpcValue == 0){     //Motion detected
                    
//                        printf("Motion detected on Xbee%d\n", i);
                        //if(digiValue)
//                            rpcValue = 1;
//                        else
//                            rpcValue = 0;

                        rpcValue = 1;
                        *xbeeList[i].digitalInRpcDataPointer[digiIndex] = rpcValue;
                    
                        *xbeeList[i].digitalOutRpcDataPointer[0] = 1;   //Turn on the light
                        xbeeList[i].timerList[digiIndex]->start();       //Restart timer
                    }
                }
                
            }
            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].timerList[digiIndex]->read() > 15){   //Check if timer has expired
                    *xbeeList[i].digitalOutRpcDataPointer[0] = 0;   //If timer has expired, turn light off
                }
            }
        }
    }
}