Translate

Tuesday 27 May 2014

Room Management System – Adding a little more control to the AC's part 3


Today we are programming mode 3 of the AC control sequence and I have a couple of changes in the rest of the ac_read() function.
As usual, we start at the top of the sketch in the declaration part. Since we have added quite a bit of functionality since we started and the processor has to go through quite a bit of code, we make the unit a little more responsive again and reduce the default sensitivity value from 400 to 300.

/////////////////////Declaring the Variables/////////////////

///////////Timer and Sensitivity Settings to be changed to individual needs////////////////

//>>>>>>>>>>>>>CHANGE the sensitivity value to 300<<<<<<<<<<<<<

unsigned int sensitivity = 300; //should be between 0 and 500 as

//lower the number as more responsive

//the system will be

unsigned int photoCellCutOn = 320; //var holding the switching limit for the photocell

unsigned int photoCellCutOff = 280; //var holding the value where the photocell cuts off

unsigned int photoOutsideOn = 220; //var holding the value which the photocell reading

unsigned int photoOutsideOff = 260;

After that, we stay in the same section and move just a little down where we have to add the time value we want to pulse the momentary switch of the AC.

int dAC3 = 120; //delay time in seconds for AC 3 (bed3)

int dAC4 = 120; //delay time in seconds for AC 4 (living)

int dMaster = 240; //delay time in seconds for Master Off

//>>>>>>>>>>>>>ADD the line below<<<<<<<<<<<<<<

byte acSwitchDelay = 3; //ac pulse delay for mode 3

byte ac_op_mode = 3; //ac mode 1) read switches only

//ac mode 2) limited control using ac switch or auto restart of AC

//ac mode 3) limited control using ac momentary switch (push button)

byte ac_set_temp = 28; //temperature at which the AC switches on

byte ac_periode[4][2] = {

{1, 5}, //time periode between January and May

{6, 9}, //time periode between June and September

{10, 10}, //October

{11, 12} //time periode between November and December

};

byte ac_master_bypass[4] = {0}; //array holding values to bypass master relay

//////////////////////holiday and AC timer settings//////////////////////

Now we move down to the “All the other Variables” section and add the output values for the AC to the outputValues[] array. We also need to alter the reserved spaces in the roomLight[] array from roomLight[10] = {0}; to roomLight[14] = {0};

byte lightLevel[17] ={0}; //array holding the switch state

//checking timer and photocell (0, 1)

byte roomLight[14] = {0}; //array holding the switch on command in holiday lighting

//and in AC operating mode 3

//>>>>>>>>>>>>>REPLACE the existing outputValues[10] with the line below<<<<<<<<<<<<<

unsigned int outputValues[14] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};

unsigned int roomTimer[17] = {0}; //array holding the time when the PIR was last activated

unsigned int currentTime = 0; //var to hold a reference time to calculate the up time

Now we move down into the main loop to the “AC read switches” section.

lightStatus[16] = check_master(12);

lightOutput[8] = check_light_N(12, 8, 256);

delay(5);

lightStatus[16] = check_master(13);

lightOutput[9] = check_light_N(13, 9, 512);

/////////////////////Ac Read Switches////////////////////////

//>>>>>>>>>>>>To be replaced<<<<<<<<<<<<<

lightOutput[10] = ac_read(14, 10, 1024);

lightOutput[11] = ac_read(15, 11, 2048);

lightOutput[12] = ac_read(16, 12, 4096);

lightOutput[13] = ac_read(17, 13, 8192);

//>>>>>>>>>>>>>Replacement ends here<<<<<<<<<<<<

/////////////Door switch control ////////////////////

//Serial.print("switchState 18 :");

The section above reads after replacement:

lightStatus[16] = check_master(12);

lightOutput[8] = check_light_N(12, 8, 256);

delay(5);

lightStatus[16] = check_master(13);

lightOutput[9] = check_light_N(13, 9, 512);

/////////////////////Ac Read Switches////////////////////////

lightOutput[10] = ac_read(14, 10);

lightOutput[11] = ac_read(15, 11);

lightOutput[12] = ac_read(16, 12);

lightOutput[13] = ac_read(17, 13);

/////////////Door switch control ////////////////////

//Serial.print("switchState 18 :");

Since we added the output values to the outputValues[] array, we don't need to pass them on into the ac_read() function.
Time to jump down into the ac_read() function. First, we remove the variable “unsigned long light” in the functions initializing line. Second, we replace all the “light” variables in the function with outputValues[room].

unsigned long ac_read(byte readSw, byte room, unsigned long light){ //<<<<<<<<<<REMOVE “unsigned long light”

byte periode = get_ac_periode(); //function call to check time periode (season)

//check if a forced switch on is defined

if(ac_forced_on[room-10][0] != 99 && checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],

room_timers[room][periode][2], room_timers[room][periode][3]) == 1 &&

temperatur1 >= ac_set_temp){

priorityStatus[room] = 1; //set priority status to 1 if yes

}

else{

priorityStatus[room] = 0; //set priority status to 0 if no

}

if(ac_op_mode == 1){

if(switchState[readSw] == 1 && lightStatus[14] == 1){ //Checking if readswitches are activated

//and the master relay is on AC room 1 (bed1)

lightOutput[room] = light; //<<<<<<<<<<<<REPLACE all lightOutput[room] = light

//statements with lightOutput[room] = outputValues[room];

//switch on the AC

Now we move down to the end of the function and replace the end part:

lightStatus[room] = 0; //resetting the light (AC) status

roomTimer[room] = 0; //resetting the timer

}

}

}

}

else if(ac_op_mode == 3){

//still being worked on

}

return lightOutput[room];

}

with

          lightStatus[room] = 0;                            //resetting the light (AC) status
          roomTimer[room] = 0;                              //resetting the timer
        }
      }
    }
    return lightOutput[room];
  }
  else if(ac_op_mode == 3){                       //AC operating mode 3
    lightOutput[room] = 0;                        //Setting the lightOutput to 0
    if(roomLight[room] == 1){                     //if a "on" command was given
      currentTime = millis()/1000;                //set timer for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set time
      if(endTime >= acSwitchDelay){               //check if it matches allowed difference
        lightStatus[room] = 1;                    //set AC status to on
        roomLight[room] = 0;                      //cancel "on" command
        return 0;                                 //return 0
      }
      else{
        return outputValues[room];                //pulse the switch while "on" command active
      }
    }
    if(roomLight[room] == 2){                     //if an "off" command was given check delay timer
      currentTime = millis()/1000;                //set time for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set off delay
      if(endTime >= delayTime[room]){             //check if it matches allowed difference
        roomLight[room] = 3;                      //final command to switch off
        return 0;                                 //return 0
      }
      else{
        roomLight[room] = 2;                      //keep the status
        return 0;                                 //return 0
      }
    }
    if(roomLight[room] == 3){                     //final off command given
      currentTime = millis()/1000;                //set time for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set time  
      if(endTime >= acSwitchDelay){               //check if it matches allowed difference
        lightStatus[room] = 0;                    //reset command status
        roomLight[room] = 0;                      //reset AC status
        return 0;                                 //return 0
      }
      else{
        return outputValues[room];                //pulse the switch
      }
    }
      
    if(ac_master_bypass[room-10] == 0){
      if(lightStatus[room] == 0 && roomLight[room] == 0){
        if(switchState[readSw] == 1 && lightStatus[14] == 1 && 
           temperatur1 >= ac_set_temp && priorityStatus[room] == 0){
          if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                         room_timers[room][periode][2], room_timers[room][periode][3]) == 1){
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
        if(switchState[readSw] == 1 && priorityStatus[room] == 1 &&
           temperatur1 >= ac_set_temp){
          if(currentHour >= ac_forced_on[room-10][0] && 
             currentMinute >= ac_forced_on[room-10][1]){ //check if it's time to start
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
      }
      if(lightStatus[room] == 1 && roomLight[room] == 0){
        if(currentHour == room_timers[room][periode][2] &&   //if the allowed running limit is reached
           currentMinute >= room_timers[room][periode][3]){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 1 &&  switchState[readSw] == 0){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;  
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 0){
          if(switchState[readSw] == 0 | lightStatus[14] == 0){
            roomLight[room] = 2;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else{
            return 0;
          }
        }
      }
    }
  }
  return 0;
}
   

Let's have a quick look what's going on in this part. Since we are switching the AC by using the AC's On/Off button, we do not want a constant output throughout the running time. We need to simulate the “button press”. Therefore we need to check our events like is the switch on or switch off time reached, is the master relay activated or not or is one of the corresponding windows open and is the AC running. If one of the events is true, depending on a switch on or switch off command, the system will either got into the on sequence, giving the output value for a predefined time or into the off sequence running through a preprogrammed off delay and going again into the on sequence to activate the “button” for a predefined time to switch the system off.

In checking if the AC is running, we have to be a little careful, since we do not have a feedback from the AC itself what it's doing. We have to rely on the fact, that the user is programming the AC's timers and thermostat to stay within the programmed limits of this approach in the room management system. If the AC is programmed differently from it's internal controls, it might override the given on or off command from the room management system. Maybe at a later state, I will check if it is possible to check the AC's current draw to determine a off or on state off the AC and implement a little check routine. But that is on my to do list for further development.

Since we have done a few changes, here the full code of our ac_read() function.


unsigned long check_light_N(byte pir, byte room, unsigned long light){
  if(switchState[pir] == 1) {                                     //checking S9 PIR of bathroom 1 
                                                                 //(room 5)
    //Serial.println("We switch on the lights");                 //Debug only
    lightOutput[room] = light;                                       //switching on the lights
    lightStatus[room] = 1;                                    //setting the light status
    lightOutput[14] = 16384;                                   //make sure the master relay
                                                               //stays on
    lightStatus[14] = 1;                                       //setting the master yelay status
    roomTimer[room] = millis()/1000;                                   //setting the room timer
  }
  else if(switchState[pir] == 0 && lightStatus[room] == 1) {       //if no PIR was activated and 
                                                              //the lights are on
    //Serial.println("We are checking the timer");              //Debug only
    currentTime = millis()/1000;                                   //setting time reference
    endTime = currentTime - roomTimer[room];                     //calculating the inactive time
    if(endTime >= delayTime[room]) {                             //comparing inactive time with 
                                                              //delay time
      //Serial.println("We are switching off the lights");      //debug only 
      lightOutput[room] = 0;                                     //switching off the lights
      lightStatus[room] = 0;                                    //resetting the light status
      roomTimer[room] = 0;                                       //resetting the room timer
    }
  }
  return lightOutput[room];
}

unsigned long ac_read(byte readSw, byte room){
  byte periode = get_ac_periode();        //function call to check time periode (season)
  //check if a forced switch on is defined and the set temperature
  if(ac_forced_on[room-10][0] != 99 && checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],
                                                   room_timers[room][periode][2], room_timers[room][periode][3]) == 1 &&
     temperatur1 >= ac_set_temp){
     priorityStatus[room] = 1;            //set priority status to 1 if yes
  }
  else{
     priorityStatus[room] = 0;            //set priority status to 0 if no
  }
  if(ac_op_mode == 1){
    if(switchState[readSw] == 1 && lightStatus[14] == 1){              //Checking if readswitches are activated
                                                                 //and the master relay is on AC room 1 (bed1)
      lightOutput[room] = outputValues[room];                                   //providing the ability to
                                                               //switch on the AC
      lightStatus[room] = 1;                                       //setting the light (AC) status
      roomTimer[room] = millis()/1000;                                  //setting the timer
    }
    else if(switchState[readSw] == 0 && lightStatus[14] == 1){       //if a door is opened and the master
                                                               //relay is on
      currentTime = millis()/1000;                                    //setting time reference
      endTime = currentTime - roomTimer[room];                     //calculating the inactive time
      if(endTime >= delayTime[room]){                              //comparing inactive time with
                                                               //delay time
        lightOutput[room] = 0;                                     //canceling ability to switch on the 
                                                               //AC
        lightStatus[room] = 0;                                     //resetting the light (AC) status
        roomTimer[room] = 0;                                       //resetting the timer
      }
    }
    return lightOutput[room];
  }
  else if(ac_op_mode == 2){
    if(ac_master_bypass[room - 10] == 0){   //check if the master bypass is set
      if(switchState[readSw] == 1 && lightStatus[14] == 1){              //Checking if readswitches are activated
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1){
          lightOutput[room] = outputValues[room]; //switch on the AC                                                                                           
          lightStatus[room] = 1;            //setting the light (AC) status
          roomTimer[room] = millis()/1000;  //setting the timer
        }
      }
      else if(switchState[readSw] == 1 && priorityStatus[room] == 1){   //if doors and windowa are closed and priority is set
        if(currentHour >= ac_forced_on[room-10][0] && currentMinute >= ac_forced_on[room-10][1]){ //check if it's time to start
          lightOutput[room] = outputValues[room];  //switch on the AC
          lightStatus[room] = 1;            //setting the light (AC) status
          roomTimer[room] = millis()/1000;  //setting the timer
        }
        else{
          lightOutput[room] = 0;            //keep it off
          lightStatus[room] = 0;            //setting the light (AC) status
          roomTimer[room] = 0;              //resetting the room timer
        }
      }
      else if(switchState[readSw] == 0 && lightStatus[14] == 1){   //if a door is opened and the master
                                                                   //relay is on
        currentTime = millis()/1000;                               //setting time reference
        endTime = currentTime - roomTimer[room];                   //calculating the inactive time
        if(endTime >= delayTime[room]){                            //comparing inactive time with
                                                                   //delay time
          lightOutput[room] = 0;                                   //canceling ability to switch on the 
                                                                   //AC
          lightStatus[room] = 0;                                   //resetting the light (AC) status
          roomTimer[room] = 0;                                     //resetting the timer
        }
      }
    }
    else if(ac_master_bypass[room - 10] == 1){   //if master relay bypass is on
      if(switchState[readSw] == 1){              //Checking if readswitches are activated
        if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],      
                       room_timers[room][periode][2], room_timers[room][periode][3]) == 1 &&
           temperatur1 >= ac_set_temp){
                                                              
          lightOutput[room] = outputValues[room];           //providing the ability to
                                                            //switch on the AC
          lightStatus[room] = 1;                            //setting the light (AC) status
          roomTimer[room] = millis()/1000;                  //setting the timer
        }
      }
      else if(switchState[readSw] == 0){                    //if a door is opened and the master
                                                            //relay is on
        currentTime = millis()/1000;                        //setting time reference
        endTime = currentTime - roomTimer[room];            //calculating the inactive time
        if(endTime >= delayTime[room]){                     //comparing inactive time with
                                                            //delay time
          lightOutput[room] = 0;                            //canceling ability to switch on the 
                                                            //AC
          lightStatus[room] = 0;                            //resetting the light (AC) status
          roomTimer[room] = 0;                              //resetting the timer
        }
      }
    }
    return lightOutput[room];
  }
  else if(ac_op_mode == 3){                       //AC operating mode 3
    lightOutput[room] = 0;                        //Setting the lightOutput to 0
    if(roomLight[room] == 1){                     //if a "on" command was given
      currentTime = millis()/1000;                //set timer for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set time
      if(endTime >= acSwitchDelay){               //check if it matches allowed difference
        lightStatus[room] = 1;                    //set AC status to on
        roomLight[room] = 0;                      //cancel "on" command
        return 0;                                 //return 0
      }
      else{
        return outputValues[room];                //pulse the switch while "on" command active
      }
    }
    if(roomLight[room] == 2){                     //if an "off" command was given check delay timer
      currentTime = millis()/1000;                //set time for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set off delay
      if(endTime >= delayTime[room]){             //check if it matches allowed difference
        roomLight[room] = 3;                      //final command to switch off
        return 0;                                 //return 0
      }
      else{
        roomLight[room] = 2;                      //keep the status
        return 0;                                 //return 0
      }
    }
    if(roomLight[room] == 3){                     //final off command given
      currentTime = millis()/1000;                //set time for reference
      endTime = currentTime - roomTimer[room];    //compare reference with set time  
      if(endTime >= acSwitchDelay){               //check if it matches allowed difference
        lightStatus[room] = 0;                    //reset command status
        roomLight[room] = 0;                      //reset AC status
        return 0;                                 //return 0
      }
      else{
        return outputValues[room];                //pulse the switch
      }
    }
      
    if(ac_master_bypass[room-10] == 0){
      if(lightStatus[room] == 0 && roomLight[room] == 0){
        if(switchState[readSw] == 1 && lightStatus[14] == 1 && 
           temperatur1 >= ac_set_temp && priorityStatus[room] == 0){
          if(checkOnTime(room_timers[room][periode][0], room_timers[room][periode][1],     //checking if AC is allowed to run
                         room_timers[room][periode][2], room_timers[room][periode][3]) == 1){
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
        if(switchState[readSw] == 1 && priorityStatus[room] == 1 &&
           temperatur1 >= ac_set_temp){
          if(currentHour >= ac_forced_on[room-10][0] && 
             currentMinute >= ac_forced_on[room-10][1]){ //check if it's time to start
            roomLight[room] = 1;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else {
            return 0;
          }
        }
      }
      if(lightStatus[room] == 1 && roomLight[room] == 0){
        if(currentHour == room_timers[room][periode][2] &&   //if the allowed running limit is reached
           currentMinute >= room_timers[room][periode][3]){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 1 &&  switchState[readSw] == 0){
          roomLight[room] = 2;
          roomTimer[room] = millis()/1000;
          return 0;  
        }
        else{
          return 0;
        }
        if(priorityStatus[room] == 0){
          if(switchState[readSw] == 0 | lightStatus[14] == 0){
            roomLight[room] = 2;
            roomTimer[room] = millis()/1000;
            return 0;
          }
          else{
            return 0;
          }
        }
      }
    }
  }
  return 0;
}

Finally today a small description on how to connect the AC control to your unit.

First a small warning:
You are dealing with domestic electricity, 230 Volt in Europe and 110 Volt (US).
Before any attempt of opening your AC unit even only to check for the ability of connecting it to the
room management system, always disconnect it from the power supply. Failing to do so might cause serious damage to the equipment or serious personnel insure or death.
If you are not sure what you are doing, please ask for professional advise. Making wrong connections can cause damage to your equipment or personal injury or death.

  1. Running it in Mode 1 – using only read switches to check if corresponding doors or windows are opened.
    That's usually easiest part. Please check at your AC's installation manual since at least the newer units are prepared for this feature. Instead of connecting all the read switches to the connection for it on the AC unit, you connect the for this unit designated relay from the room management system to it. If you have a to way relay, please connect the cables to the NO (normally open) part of the relay. The read switches are connected as usual in series as shown in a sample drawing here:
    http://arduinopraxis.blogspot.com/2014/03/room-management-system-putting-it.html
  2. Running it in Mode 2 – controlling the AC using the AC's auto restart ability
    The readswitches are connected as described in point 1. The relay from the room management system is controlling a contactor, which is able to switch the full AC's load. The AC's power supply is running through the contactor, so we actually cut the AC's power supply when switching it off. The AC recognizes it as power cut. If we want to switch the AC back on, we reactivate the contactor through the room management systems relay. The AC recognizes the power is coming back and reactivated the Unit to the last running conditions.
    Here we need to be a little careful with programming the unit it self. We have to make sure, that the program in the AC's internal controller is programmed within the programmed limits of the room management system.
  3. Running it in Mode 2 – replacing the AC – units switch with relay contacts controlled by our room managements system.
    That's most likely on older units still having an old fashion switch and being controlled through a wired thermostat. There we just need to take out the old switch and the connections go to the NO 9normally open) part of the room managements corresponding relay.
  4. Running it in Mode 3 – using the room managements system corresponding relay to simulate the AC's on/off button (push button). That's a little bit more difficult task, since it involves taking out a circuit board and solder a couple of wires to the push button pins, which again connect to the NO part of the corresponding relay of the room management system.
    In this case, great care has to be taken in programming the AC's controller and the room management system. The AC's controller has to be programmed to work within the limits of the room management system program. Other wise the AC controller and the room management system cancelling each other out in off and on commands which might result in uncontrolled AC-switching, which again might cause serious damage to the AC unit.

In the next post we start implementing the AC control into the menu of the room management system.

No comments:

Post a Comment