TeensyPi Networked Temperature Controller

Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum

Help Support Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
Starting to build out the full electronics.
I picked up a terminal strip for my 5V/5A DC power supply. This will power the TeensyPi and the 8 device relay board.

I also bought an additional Arduino shield (think it was for a Mega) to wire the switch and temp probe circuits. Right now I just have the switches wired up, but it is working as planned. I will have 8 switches for 3 solenoids, 3 heat wraps, 1 pump, and an AC unit for a glycol bath.

ijJKId4.jpg


3EIS9G3.jpg


I have XLR connectors that I am going to use for the temp probes, which I will wire to the larger proto area on the board.

I will be putting everything in this case:
lg_NBE130906-KIT01.JPG
 
Depends on how complicated you want to make it. Looking at the Relay Output Example, it seems to me that you could put the code in the loop() into a function that's called in the Teensy 3.0 loop() replacing the
Code:
Input = analogRead(0);
with
Code:
Input = (double) chip[x].status;

and

Code:
if(Output > now - windowStartTime) digitalWrite(RelayPin,HIGH);
  else digitalWrite(RelayPin,LOW);

with

Code:
if(Output > now - windowStartTime) setSwitchState(x,ds2406PIOAoff);
  else setSwitchState(x,ds2406PIOAon);

Just as a test you could hard code the values for the thermometer and switch, put all of the setup in the setup() and let it rip.

Just tried this. When I went to build, it got caught at:
Code:
Input = (double) chip[x].status;
saying that Chip X wasn't defined, so I changed to chip[0], then it said "status" was not defined.
 
What I would like to try is to replace the created action with creating a PID, so I could have multiple PIDs running. But I am not sure where to add and how the chips are read/updated.
 
What I would like to try is to replace the created action with creating a PID, so I could have multiple PIDs running. But I am not sure where to add and how the chips are read/updated.

Post your variables, function, and the parameters you placed in setup(), and I'll take a look at it.
 
Post your variables, function, and the parameters you placed in setup(), and I'll take a look at it.

OK, will do in a bit. Do I still include the original code and just add the PID stuff (which I did), or were you suggesting getting rid of the rest in the setup()/loop()?
 
Code:
#include <PID_v1.h>

#include <math.h>
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include "OneWire.h"

// #include <MemoryFree.h>

/*
  General Setup
*/

// define DEBUG options
// #define __SERIAL_DEBUG__
// #define __SERIAL1_DEBUG__
// #define __CHIP_DEBUG__
// #define __EEPROM_DEBUG__
// #define __ALL_DEBUG__

  
// *** Define PID Variables
//Define Variables we'll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;


// *** End PID Veriables

// define serial commands

const uint8_t getMaxChips        = '1';
const uint8_t showChip           = getMaxChips + 1;
const uint8_t getChipCount       = showChip + 1;
const uint8_t getChipAddress     = getChipCount + 1;
const uint8_t getChipStatus      = getChipAddress + 1;
const uint8_t setSwitchState     = getChipStatus + 1;
const uint8_t getAllStatus       = setSwitchState + 1;
const uint8_t getChipType        = getAllStatus + 1;
const uint8_t getAllChips        = getChipType + 1; // last in this series

const uint8_t getActionArray     = 'A'; // start of new serial command list
const uint8_t updateActionArray  = getActionArray + 1;
const uint8_t getActionStatus    = updateActionArray + 1;
const uint8_t getMaxActions      = getActionStatus + 1;
const uint8_t setActionSwitch    = getMaxActions + 1;
const uint8_t saveToEEPROM       = setActionSwitch + 1;
const uint8_t getEEPROMstatus    = saveToEEPROM + 1;
const uint8_t getNewSensors      = getEEPROMstatus + 1;
const uint8_t masterStop         = getNewSensors + 1;
// end of serial commands

const uint8_t softSerialError  = 'X';
const uint8_t setSwitchON      = 'N';
const uint8_t setSwitchOFF     = 'F';
const uint8_t switchStatusON   = 'N';
const uint8_t switchStatusOFF  = 'F';
const uint8_t tooHotSwitch     = 'H';
const uint8_t tooColdSwitch    = 'C';
const uint8_t noChipPresent    = 0xFF;


const long baudRate = 115200;
const uint8_t waitPin = 8;
const uint8_t waitLED = 13;

char softSerialBuffer[1024], c;
uint8_t cnt = 0;
uint8_t chipSelected;
uint8_t actionSelected;
uint8_t setChipState;
uint8_t *chipAddrPtr;
bool serialMessageReady = FALSE;
bool actionPtrMatch = FALSE;
bool showCelcius = FALSE;

uint32_t timer, timer2;
const uint32_t updateTime = 250;
const uint32_t ramUpdateTime = 10000;

// OneWire Setup;
const uint8_t oneWireAddress = 9; // OneWire Bus Address
const uint8_t chipAddrSize   = 8; // 64bit OneWire Address
const uint8_t ds2406MemWr    = 0x55;
const uint8_t ds2406MemRd    = 0xaa;
const uint8_t ds2406AddLow   = 0x07;
const uint8_t ds2406AddHi    = 0x00;
const uint8_t ds2406PIOAoff  = 0x3f;
const uint8_t ds2406PIOAon   = 0x1f;
const uint8_t ds2406End      = 0xff;
const uint8_t ds18b20ID      = 0x28;
const uint8_t ds2406ID       = 0x12;
const uint8_t dsPIO_A        = 0x20;
const uint8_t dsPIO_B        = 0x40;

const uint8_t maxChips       = 36; // Maximum number of Chips
const uint8_t maxActions     = 12; // Maximum number of Actions

OneWire  ds(oneWireAddress);

const uint32_t tempReadDelay = 125;

typedef struct
{
  uint8_t   chipAddr[chipAddrSize];
  int16_t   chipStatus;
  uint32_t  tempTimer;
}chipStruct;

chipStruct chip[maxChips] =
{
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 }
};

typedef struct
{
  bool     actionEnabled;
  chipStruct *tempPtr;
  int16_t  tooCold;
  chipStruct *tcPtr;
  uint8_t  tcSwitchLastState;
  uint32_t  tcDelay;
  uint32_t tcMillis;
  int16_t  tooHot;
  chipStruct *thPtr;
  uint8_t  thSwitchLastState;
  uint32_t  thDelay;
  uint32_t thMillis;
}chipActionStruct;

chipActionStruct action[maxActions] =
{
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 }
};

uint8_t chipBuffer[12];
uint8_t chipCnt, chipX = 0, actionsCnt = 0;


//EEPROM Stuff
const int   EEPROMsize       = 2048;   // Cortex M4
const int   EEPROMidAddr     = 0x10;   // ID address to verify a previous EEPROM write
const int   EEPROMccAddr     = 0x20;   // number of chips found during findchips()
const int   EEPROMchipAddr   = 0x100;  // start address of array of chip structures
const int   EEPROMactionAddr = 0x400;  // start address of array of action structures
const byte  EEPROMidVal      = 0x55;   // Shows that an EEPROM update has occurred 
bool        eepromReady      = FALSE;
int         eepromSpace, eeResult;

void setup()
{
  int x;
  pinMode(waitPin, OUTPUT);
  pinMode(waitLED, OUTPUT);
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  Serial.begin(baudRate);
  
  #if defined (__SERIAL_DEBUG__) || defined (__SERIAL1_DEBUG__) || defined (__CHIP_DEBUG__) ||defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
 
    delay(3000);
  #endif
  
  Serial.print(F("Serial Debug running at "));
  Serial.print(baudRate);
  Serial.println(F(" baud"));


  eeResult = EEPROM.read(EEPROMidAddr);
  
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("eeResult = 0x"));
   Serial.println(eeResult, HEX);
  #endif
  
  if(eeResult != 0x55)
  {
  #if defined (__EEPROM_DEBUG__ )|| defined (__ALL_DEBUG__)
     Serial.println(F("No EEPROM Data"));
  #endif
  
    eepromReady = FALSE;
    findChips();
  }else{

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F("Getting EEPROM Data"));
  #endif

    chipCnt = EEPROM.read(EEPROMccAddr);
    EEPROM_readAnything(EEPROMchipAddr, chip); // get chip structures from EEPROM
    EEPROM_readAnything(EEPROMactionAddr, action); // get action structures from EEPROM

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F("EEPROM Data Read Completed"));
  #endif
  
    eepromReady = TRUE;
    
  }
  
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(sizeof(chipStruct) / sizeof(byte));
   Serial.println(F(" bytes in chip structure"));
   Serial.print(sizeof(chipActionStruct) / sizeof(byte));
   Serial.println(F(" bytes in action structure"));
  #endif  


  Serial1.begin(baudRate);
  Serial.print(F("Serial1 Debug running at "));
  Serial.print(baudRate);
  Serial.println(F(" baud"));
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
  timer = millis();
  timer2 = millis();
  

/// ***** Start PID Setup *****
  windowStartTime = millis();
  
  //initialize the variables we're linked to
  Setpoint = 70;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);

/// ***** End PID Setup *****
}

void loop()
{
// *** Start PID Loop ***
  Input = (double) chip[x].status;
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output > now - windowStartTime) setSwitchState(x,ds2406PIOAoff);
  else setSwitchState(x,ds2406PIOAon);
// *** End PID Loop ***

  while(Serial1.available())
  { 
     c = Serial1.read();
     if( (c >= 0x20 && c <= 0x7E) ||
         c == 0 ||
         c == 0x0d ||
         c == 0x0a
       )
     {
       if(c == 0 || c == 0x0d || c == 0x0a)
       {
          c = 0; //null terminate the string
         serialMessageReady = TRUE;
       }
       softSerialBuffer[cnt] = c;
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.write(c);
  #endif
       cnt++;
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
       delay(2);
  #endif
     }
   }
  
  if(cnt > 0 && serialMessageReady == TRUE)
  {
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
    Serial.println();
  #endif
    softSerialProcess();
  }
  
//  if(timer > (millis() + 5000)) // in case of rollover
//  {
//    timer = millis();
//  }
  
//  if(millis() > (timer + updateTime))
//  {
    updateChipStatus(chipX);
    chipX++;
    if(chipX >= maxChips){chipX = 0;}
    
    updateActions(actionsCnt);    
    actionsCnt++;
    if(actionsCnt >= maxActions){actionsCnt = 0;}
  
//    timer = millis();
//  }
/*  
  if(millis() > (timer2 + ramUpdateTime))
  {
    Serial.print(freeMemory());
    Serial.println(F(" Available"));
    timer2 = millis();
  }
*/
}


void findChips()
{
 int cntx = 0;
 
  while (ds.search(chip[cntx].chipAddr))
  {

  #if defined (__CHIP_DEBUG__) || defined (__ALL_DEBUG__)
    
     Serial.print(F("Chip "));
     Serial.print(cntx);
     Serial.print(F(" = {"));
    
    for( int i = 0; i < chipAddrSize; i++)
    {
      if(chip[cntx].chipAddr[i]>=0 && chip[cntx].chipAddr[i]<10)
      {
        Serial.print(F("0x0"));
      }else{
        Serial.print(F("0x"));
      }
      Serial.print(chip[cntx].chipAddr[i], HEX);
      if(i < 7){Serial.print(F(","));}
    }
    Serial.println(F("}"));
  #endif    
    cntx++;
    delay(750);
  }

  #if defined (__CHIP_DEBUG__) || defined (__ALL_DEBUG__)
    Serial.print(cntx);
    Serial.print(F(" Sensor"));
    if(cntx == 1)
    {
      Serial.println(F(" Detected"));
    }else{
       Serial.println(F("s Detected"));
    }
  #endif
  
  ds.reset_search();
  chipCnt = cntx;
  if(cntx < maxChips)
  {
    for(;cntx<maxChips;cntx++)
    {
      for(int y=0;y<chipAddrSize;y++)
      {
        chip[cntx].chipAddr[y]=0;
      }
    }
  }
}

void softSerialProcess()
{
  int x, ssBufOffset;
  char *result = NULL, *addrResult = NULL;
  char delim[] = " ", addrDelim[] = ",";
  int16_t actionEnableTemp;
  int16_t resultCnt = 0, addrResultCnt = 0, actionArray, actionSection;
  uint32_t actionDelayVal;
  uint8_t addrVal[chipAddrSize], addrMatchCnt, chipAddrCnt;
  
  switch(softSerialBuffer[0])
  {
    
    case getMaxChips: // "1"
    {
      Serial1.print(maxChips);
      Serial1.print(F("\n"));
    }
    break;
    
    case showChip: // "2"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      showChipInfo(x);
    } 
    break;
    
    case getAllChips: // "9"
    {
      for(x = 0; x < maxChips; x++)
      {
        showChipInfo(x);
      }
    }
    break;
    
    case getChipCount: // "3"
    {
      Serial1.print(chipCnt);
      Serial1.print(F("\n"));
    }
    break;
    
    case getChipAddress: // "4"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      showChipAddress((uint8_t *) &chip[x].chipAddr);
      break;
    }
    
    case getAllStatus: // "7"
    {
      for(int x = 0; x < maxChips; x++)
      {
        switch (chip[x].chipAddr[0])
        {
          case ds18b20ID:
          {
            Serial1.print((int) chip[x].chipStatus);
          }
          break;
          
          case ds2406ID:
          {
              Serial1.print((char) chip[x].chipStatus);
          }
          break;
          
          default:
          {
            Serial1.print(F("Z"));
          }
          break;
        }
        if(x < maxChips -1)
        {
          Serial1.print(F(","));
        }
      }
    Serial1.print(F("\n"));
    }
    break;

    case getChipType: // "8"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      switch(chip[x].chipAddr[0])
      {
        case ds18b20ID:
        {
          Serial1.print(F("T"));
        }
        break;
 
         case ds2406ID:
        {
          Serial1.print(F("S"));
        }
        break;

        default:
        {
          Serial1.print(F("Z"));
        }
        break;
     }
    }
    Serial1.print(F("\n"));
    break;

    case setSwitchState: // "6"
    {
      chipSelected = atoi((char *) &softSerialBuffer[1]);
      if(chipSelected >= 10)
      {
        ssBufOffset = 3;
      }else{
        ssBufOffset = 2;
      }
      if(softSerialBuffer[ssBufOffset] == setSwitchON)
      {
        setChipState = ds2406PIOAon;
      }else{
        setChipState = ds2406PIOAoff;
      }
      setSwitch(chipSelected, setChipState);
      updateChipStatus(chipSelected);
      Serial1.print((char) chip[chipSelected].chipStatus);
      Serial1.print(F("\0"));
    }
    break;
    
    case getChipStatus: // "5"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      updateChipStatus(x);
      switch(chip[x].chipAddr[0])
      {
        case ds18b20ID:
        {
          Serial1.print( (int) chip[x].chipStatus);
        }
        break;

        case ds2406ID:
        {
          Serial1.print( (char) chip[x].chipStatus);
        }
        break;

        default:
        {
          Serial1.print(F("Z"));
        }
        break;
      }
    }

    case getActionArray: // "A"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      Serial1.print(action[x].actionEnabled);
      Serial1.print(F(" "));
      showChipAddress((uint8_t *) &action[x].tempPtr->chipAddr);
      Serial1.print(F(" "));
      Serial1.print(action[x].tooCold);
      Serial1.print(F(" "));
      if(action[x].tcPtr == NULL)
      {
        Serial1.print(F("0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"));
      }else{
        showChipAddress((uint8_t *) &action[x].tcPtr->chipAddr);
      }
      Serial1.print(F(" "));
      Serial1.print((char) action[x].tcSwitchLastState);
      Serial1.print(F(" "));
      Serial1.print((action[x].tcDelay / 1000));
      Serial1.print(F(" "));
      Serial1.print(action[x].tcMillis);
      Serial1.print(F(" "));
      Serial1.print(action[x].tooHot);
      Serial1.print(F(" "));
      if(action[x].thPtr == NULL)
      {
        Serial1.print(F("0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"));
      }else{
        showChipAddress((uint8_t *) &action[x].thPtr->chipAddr);
      }
      Serial1.print(F(" "));
      Serial1.print((char) action[x].thSwitchLastState);
      Serial1.print(F(" "));
      Serial1.print((action[x].thDelay / 1000));
      Serial1.print(F(" "));
      Serial1.print(action[x].thMillis);
      Serial1.print(F("\0"));
      break;
    }
    
    case updateActionArray: // "B"
    {
      
      result = strtok( softSerialBuffer, delim );

      while(1)
      {
        result = strtok( NULL, delim );
        if(result == NULL){break;}
        switch (resultCnt)
        {
          case 0: // action
          {
            actionArray = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionArray = "));
             Serial.println(actionArray);
  #endif
            break;
          }
          case 1:
          {
            actionSection = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionSection = "));
             Serial.println(actionSection);
  #endif
            break;
          }
          
          case 2:
          {
            actionEnableTemp = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionEnableTemp = "));
             Serial.println(actionEnableTemp);
             Serial.print(F("action["));
             Serial.print(actionArray);
             Serial.print(F("]"));
  #endif            
            switch (actionSection)
            {
              case 1:
              {
                if(actionEnableTemp == 1)
                {
                  action[actionArray].actionEnabled = TRUE;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                   Serial.println(F(".actionEnabled is Enabled"));
  #endif
                }else{
                  action[actionArray].actionEnabled = FALSE;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 // Serial.println(F(".actionEnabled is Disabled"));
  #endif
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("action["));
                 Serial.print(actionArray);
                 Serial.print(F("].actionEnabled = "));
                 Serial.println(action[actionArray].actionEnabled);
  #endif
                break;
              }
              
              case 2:
              case 3:
              {
                if(actionSection == 2)
                {
                  action[actionArray].tooCold = actionEnableTemp;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.print(F(".tooCold is set to "));
                  Serial.println(actionEnableTemp);
  #endif
                }else if( actionSection == 3){
                  action[actionArray].tooHot = actionEnableTemp;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                   Serial.print(F(".tooHot is set to "));
                   Serial.println(actionEnableTemp);
  #endif
                }
                break;
              }
            }
            break;
          }
          
          case 3:
          {
            if(actionSection != 1)
            {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("result = "));
               Serial.println(result);
  #endif
              actionDelayVal = ((uint32_t) atoi(result));
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("actionDelayVal = "));
               Serial.println(actionDelayVal);
  #endif
              actionDelayVal *= 1000;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("actionDelayVal * 1000 = "));
               Serial.println(actionDelayVal);
               Serial.print(F("action["));
               Serial.print(actionArray);
               Serial.print(F("]."));
  #endif
              if(actionSection == 2)
              {
                action[actionArray].tcDelay = actionDelayVal;
                if(actionDelayVal > 0)
                {
                  action[actionArray].tcMillis = millis();
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("tcDelay = "));
                 Serial.println((actionDelayVal / 1000));
  #endif
              }else if (actionSection == 3){
                action[actionArray].thDelay = actionDelayVal;
                if(actionDelayVal > 0)
                {
                  action[actionArray].thMillis = millis();
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("thDelay = "));
                 Serial.println(actionDelayVal / 1000);
  #endif
              }
            }
            break;
          }
          
          case 4:
          {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.println(result);
  #endif
            addrResult = strtok( result, addrDelim );
            while(addrResult != NULL)
            {
              addrVal[addrResultCnt] = (uint8_t) strtol(addrResult, NULL, 16);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F(" "));
               Serial.print(addrVal[addrResultCnt], HEX);
  #endif
              addrResultCnt++;
              addrResult = strtok( NULL, addrDelim );
            }
            for(addrMatchCnt = 0, chipAddrCnt = 0; addrMatchCnt < chipAddrSize; addrMatchCnt++)
            {
              if(addrVal[addrMatchCnt] != chip[chipAddrCnt].chipAddr[addrMatchCnt])
              {
                addrMatchCnt = 0;
                chipAddrCnt++;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("chipAddrCnt = "));
                 Serial.println(chipAddrCnt);
                 Serial.print(F("chipCnt = "));
                 Serial.println(chipCnt);
  #endif
                continue;
              }
            }
            if(chipAddrCnt <= chipCnt)
            {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("MATCH!! - "));
  #endif
              actionPtrMatch = TRUE;
            }else{
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("NO MATCH!! - "));
  #endif
              actionPtrMatch = FALSE;
            }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.println(chipAddrCnt);
  #endif
            switch (actionSection)
            {
              case 1:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].tempPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].tempPtr = NULL;
                }
                break;
              }
              case 2:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].tcPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].tcPtr = NULL;
                }
                break;
              }
              case 3:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].thPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].thPtr = NULL;
                }
                break;
              }
            }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
              //Serial.print(addrVal, HEX);
              Serial.print(F(", "));
  #endif
            break;
          }
          break;
        }
        resultCnt++;
      }
    }
      
    case getActionStatus: // "C"
    {
      getAllActionStatus();
      break;
    }
    
    case getMaxActions: // "D"
    {
      Serial1.print(maxActions);
      Serial1.print(F("\n"));
    }
    break; 

    case setActionSwitch: // "E"
    {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.println(F("case: setActionSwitch"));
       Serial.println(softSerialBuffer);
  #endif
      actionSelected = atoi((char *) &softSerialBuffer[1]);
      if(actionSelected >= 10)
      {
        ssBufOffset = 3;
      }else{
        ssBufOffset = 2;
      }
      
      if(softSerialBuffer[ssBufOffset+1] == setSwitchON)
      {
        setChipState = ds2406PIOAon;
      }else{
        setChipState = ds2406PIOAoff;
      }
      
      switch (softSerialBuffer[ssBufOffset])
      {
        case tooColdSwitch:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Setting too Cold Switch"));
  #endif
          actionSwitchSet((uint8_t *) action[actionSelected].tcPtr->chipAddr, setChipState);
          if(setChipState == ds2406PIOAoff && action[actionSelected].tcDelay > 0)
          {
            action[actionSelected].tcMillis = millis();
          }
          Serial1.print((char) action[actionSelected].tcPtr->chipStatus);
          break;
        }
        
        case tooHotSwitch:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Setting too Hot Switch"));
  #endif
          actionSwitchSet((uint8_t *) action[actionSelected].thPtr->chipAddr, setChipState);
          if(setChipState == ds2406PIOAoff && action[actionSelected].thDelay > 0)
          {
            action[actionSelected].thMillis = millis();
          }
          Serial1.print((char) action[actionSelected].thPtr->chipStatus);
          break;
        }
        
        default:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Houston, We HAve A Switch Problem"));
  #endif        
          break;
        }
      }
      Serial1.print(F("\0"));
      break;
    }

    case saveToEEPROM: // "F"
    {
      initEEPROM();
      break;
    }
    
    case getEEPROMstatus: // "G"
    {
      if(eepromReady == FALSE)
      {
        Serial1.print(F("FALSE"));
      }else
      {
        Serial1.print(F("TRUE"));
      }
      break;
    }
    
    case getNewSensors: // "H"
    {
      // turn off all switches
      for(x=0; x<maxChips; x++)
      {
        setSwitch(x, ds2406PIOAoff);
      }
      
      // disable and clear actions
      for(x=0; x<maxActions; x++)
      {
        action[x].actionEnabled = FALSE;
        action[x].tempPtr = NULL;
        action[x].tcPtr = NULL;
        action[x].thPtr = NULL;
      }
      // find new chips
      findChips();
      //EEPROM.write(EEPROMidAddr, 0);
      break;
    }
    
    case masterStop: //"I"
    {
      // turn off all switches
      for(x=0; x<maxChips; x++)
      {
        setSwitch(x, ds2406PIOAoff);
      }
      for(x=0; x<maxActions; x++)
      {
        action[x].actionEnabled = FALSE;
      }
      break;
    }
  }
    
    Serial1.print(F("\n"));
//    break;
  
  softSerialBuffer[0]=0x00;
  cnt = 0;
  serialMessageReady = FALSE;
}

void initEEPROM(void)
{
  int x, y, address, value;
  
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  // Serial.println(F("Clearing EEPROM Space"));
/*  
  for(int x = 0; x < EEPROMsize; x++)
  {
    EEPROM.write(x, 0xff);
  }
*/
  // Serial.println(F("EEPROM Space Cleared"));
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(F("Writing EEPROM Data"));
  #endif

  EEPROM.write(EEPROMccAddr, chipCnt);
  EEPROM.write(EEPROMidAddr, EEPROMidVal);
  eeResult = EEPROM_writeAnything(EEPROMchipAddr, chip);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(eeResult);
   Serial.println(F(" bytes written to chip EEPROM"));
  #endif
  eeResult = EEPROM_writeAnything(EEPROMactionAddr, action);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(eeResult);
   Serial.println(F(" bytes written to action EEPROM"));
   Serial.println(F("EEPROM Data Write Completed"));
  #endif
  eeResult = EEPROM.read(EEPROMidAddr);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("EEPROMidAddr = 0x"));
   Serial.println(eeResult);
 
  for(y = 0, address = EEPROMchipAddr ;  y < maxChips; y++)
  {
    // read a byte from the current address of the EEPROM
     Serial.print(F("0x"));
     Serial.print(address, HEX);
     Serial.print(":\t");
    for(x = 0; x < (sizeof(chipStruct) / sizeof(byte)); x++, address++)
    {
      value = EEPROM.read(address);
      if(value >= 0 && value <= 0x0f)
      {
        Serial.print("0x0");
      }else{
        Serial.print("0x");
      }
      Serial.print(value, HEX);
      Serial.print(F(" "));
    }
    Serial.println();
  }
  
  for(y = 0, address = EEPROMactionAddr ; y < maxActions; y++)
  {
    // read a byte from the current address of the EEPROM
    Serial.print(F("0x"));
    Serial.print(address, HEX);
    Serial.print(":\t");
    for(x = 0; x < (sizeof(chipActionStruct) / sizeof(byte)); x++, address++)
    {
      value = EEPROM.read(address);
      if(value >=0 && value <= 0x0f)
      {
        Serial.print("0x0");
      }else{
        Serial.print("0x");
      }
      Serial.print(value, HEX);
      Serial.print(F(" "));
    }
    Serial.println();
  }
  #endif
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
  eepromReady = TRUE;
}

void getAllActionStatus(void)
{
  uint8_t x;
  
  // x = atoi((char *) &softSerialBuffer[1]);
  for( x = 0; x < maxActions; x++ )
  {
    Serial1.print((int) action[x].actionEnabled);
    Serial1.print(F(","));
    if(action[x].tempPtr == NULL)
    {
      Serial1.print((int) 255);
    }else{
      Serial1.print((int) action[x].tempPtr->chipStatus);
    }
    Serial1.print(F(","));
    if(action[x].tcPtr == NULL)
    {
      Serial1.print((char) noChipPresent);
    }else{
      Serial1.print((char) action[x].tcPtr->chipStatus);
    }
    Serial1.print(F(","));
    if(action[x].thPtr == NULL)
    {
      Serial1.print((char) noChipPresent);
    }else{
      Serial1.print((char) action[x].thPtr->chipStatus);
    }
    Serial1.print(F(","));
    Serial1.print((int) action[x].tooCold);
    Serial1.print(F(","));
    Serial1.print((int) action[x].tooHot);
    if( x < (maxActions - 1) )
    {
      Serial1.print(F(";"));
    }
  }
  Serial1.print(F("\n"));
}

void actionSwitchSet(uint8_t* array, uint8_t setChipState)
{
   uint8_t addrMatchCnt, chipAddrCnt;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(F("actionSwitchSet"));
  #endif
  for(addrMatchCnt = 0, chipAddrCnt = 0; addrMatchCnt < chipAddrSize; addrMatchCnt++)
  {
    if(array[addrMatchCnt] != chip[chipAddrCnt].chipAddr[addrMatchCnt])
    {
      addrMatchCnt = 0;
      chipAddrCnt++;
      
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.println(chipAddrCnt);
  #endif
  
      continue;
    }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(array[addrMatchCnt], HEX);
     Serial.print(F(","));
  #endif
  }
  if(chipAddrCnt <= chipCnt)
  {

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(F("MATCH!! - "));
  #endif

    actionPtrMatch = TRUE;
  }else{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(F("NO MATCH!! - "));
  #endif
  
    actionPtrMatch = FALSE;
  }

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(chipAddrCnt);
  #endif
  
  if(actionPtrMatch == TRUE)
  {
    setSwitch(chipAddrCnt, setChipState);
  }
}

void showChipAddress( uint8_t* array)
{
  for( int i = 0; i < chipAddrSize; i++)
  {
    Serial1.print(F("0x"));
    if(array[i]>=0x00 && array[i]<=0x0F)
    {
      Serial1.print(F("0"));
    }
    Serial1.print(array[i], HEX);
    if(i < 7){Serial1.print(F(","));}
  }
    
}

void showChipInfo(int x)
{
  showChipAddress((uint8_t *) &chip[x].chipAddr);
  Serial1.print(F(" "));
  if(chip[x].chipAddr[0] == 0x12)
  {
    Serial1.print((char) chip[x].chipStatus);
  }else{
    Serial1.print((int) chip[x].chipStatus);
  }
  Serial1.print(F(" \n"));
}

void setSwitch(uint8_t x, uint8_t setChipState)
{
  if(chip[x].chipAddr[0] == 0x12)
  {
    ds.reset();
    ds.select(chip[x].chipAddr);
    ds.write(ds2406MemWr);
    ds.write(ds2406AddLow);
    ds.write(ds2406AddHi);
    ds.write(setChipState);
    for ( int i = 0; i < 6; i++)
    {
      chipBuffer[i] = ds.read();
    }
    ds.write(ds2406End);
    ds.reset();
    updateChipStatus(x);
  }
}

void updateChipStatus(int x)
{
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  switch(chip[x].chipAddr[0])
  {
    case ds18b20ID:
    {
      if(chip[x].tempTimer == 0)
      {
        ds.reset();
        ds.select(chip[x].chipAddr);
        ds.write(0x4E); // write to scratchpad;
        ds.write(0x00); // low alarm
        ds.write(0x00); // high alarm
        ds.write(0x1F); // configuration register - 9 bit accuracy (0.5deg C)
        ds.reset();
        ds.select(chip[x].chipAddr);
        ds.write(0x44,1);         // start conversion, with parasite power on at the end
        chip[x].tempTimer = millis();
      }
/*    
      delay(125);     // for 9 bit accuracy
      // we might do a ds.depower() here, but the reset will take care of it.
*/    
      if((chip[x].tempTimer != 0) && (millis() >= chip[x].tempTimer + tempReadDelay))
      {
        ds.reset();
        ds.select(chip[x].chipAddr);    
        ds.write(0xBE);         // Read Scratchpad
  
        for (int i = 0; i < 4; i++) 
        {
          chipBuffer[i] = ds.read();
        }
  
      // convert the data to actual temperature
        unsigned int raw = (chipBuffer[1] << 8) | chipBuffer[0];
        if( showCelcius == TRUE)
        {
          chip[x].chipStatus = (int) ((float)raw / 16.0);
        }else{
          chip[x].chipStatus = (int) ((((float)raw / 16.0) * 1.8) + 31.0);
        }
        chip[x].tempTimer = 0;
      }
    }
    break;
    
    case ds2406ID:
    {
      ds.reset();
      ds.select(chip[x].chipAddr);
      ds.write(ds2406MemRd);
      ds.write(0x0); //2406 Addr Low
      ds.write(0x0); //2406 Addr Hgh
      for(int i = 0; i <  10; i++)
      {
        chipBuffer[i] = ds.read();
      }
      ds.reset();
      if(chipBuffer[7] & dsPIO_A)
      {
        chip[x].chipStatus = switchStatusOFF;
      }else{
        chip[x].chipStatus = switchStatusON;
      }
    }
    break;
    
    default:
    {
      chip[x].chipStatus = noChipPresent;
    }
  break; 
  }
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
}

void updateActions(uint8_t x)
{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("updating Action: "));
   Serial.print(x);
  #endif
  if(action[x].actionEnabled == TRUE)
  {
    if(action[x].tempPtr->chipStatus <= action[x].tooCold &&
       action[x].tcPtr->chipStatus == switchStatusOFF) // too cold
    {
      if(action[x].tcDelay == 0 || millis() > (action[x].tcMillis + action[x].tcDelay))
      {
        actionSwitchSet((uint8_t *) &action[x].tcPtr->chipAddr, ds2406PIOAon);
        
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F(" - TOO COLD"));
  #endif        
      }
    }else if(action[x].tempPtr->chipStatus > action[x].tooCold &&
             action[x].tcPtr->chipStatus == switchStatusON){
               actionSwitchSet((uint8_t *) &action[x].tcPtr->chipAddr, ds2406PIOAoff);
               action[x].tcMillis = millis();
               
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.println(F(" - NOT TOO COLD"));
  #endif
  
    }

    if(action[x].tempPtr->chipStatus >= action[x].tooHot &&
       action[x].thPtr->chipStatus == switchStatusOFF) //too hot
    {
      if(action[x].thDelay == 0 || millis() > (action[x].thMillis + action[x].thDelay))
      {
        actionSwitchSet((uint8_t *) &action[x].thPtr->chipAddr, ds2406PIOAon);
        
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F(" - TOO HOT"));
  #endif
  
      }
    }else if(action[x].tempPtr->chipStatus < action[x].tooHot &&
             action[x].thPtr->chipStatus == switchStatusON){
               actionSwitchSet((uint8_t *) &action[x].thPtr->chipAddr, ds2406PIOAoff);
               action[x].thMillis = millis();
               
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.println(F(" - NOT TOO HOT"));
  #endif
  
    }
  }else{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F(" - not enabled"));
  #endif 
  }
}
 
OK, so I gave you a few bad variables :eek:

Try this, at least it compiles :p

Set the two global variables tChip and sChip to the array that corresponds to the temp and switch you want to use.

If you want to run multiple PIDs simultaneously, you'll probably want to setup an array of structures of PID values and then setup/enable/ disable them from a web page.

Let me know if it helps.

Code:
#include <PID_v1.h>
#include <math.h>
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include "OneWire.h"

// #include <MemoryFree.h>

/*
  General Setup
*/

// define DEBUG options
// #define __SERIAL_DEBUG__
// #define __SERIAL1_DEBUG__
// #define __CHIP_DEBUG__
// #define __EEPROM_DEBUG__
// #define __ALL_DEBUG__

  
// *** Define PID Variables
//Define Variables we'll be connecting to

// set these values to the appropiate chip array
int tChip = 0; // DS18B20 temperature sensor array
int sChip = 1; // DS2406+ switch chip array

double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;


// *** End PID Veriables

// define serial commands

const uint8_t getMaxChips        = '1';
const uint8_t showChip           = getMaxChips + 1;
const uint8_t getChipCount       = showChip + 1;
const uint8_t getChipAddress     = getChipCount + 1;
const uint8_t getChipStatus      = getChipAddress + 1;
const uint8_t setSwitchState     = getChipStatus + 1;
const uint8_t getAllStatus       = setSwitchState + 1;
const uint8_t getChipType        = getAllStatus + 1;
const uint8_t getAllChips        = getChipType + 1; // last in this series

const uint8_t getActionArray     = 'A'; // start of new serial command list
const uint8_t updateActionArray  = getActionArray + 1;
const uint8_t getActionStatus    = updateActionArray + 1;
const uint8_t getMaxActions      = getActionStatus + 1;
const uint8_t setActionSwitch    = getMaxActions + 1;
const uint8_t saveToEEPROM       = setActionSwitch + 1;
const uint8_t getEEPROMstatus    = saveToEEPROM + 1;
const uint8_t getNewSensors      = getEEPROMstatus + 1;
const uint8_t masterStop         = getNewSensors + 1;
// end of serial commands

const uint8_t softSerialError  = 'X';
const uint8_t setSwitchON      = 'N';
const uint8_t setSwitchOFF     = 'F';
const uint8_t switchStatusON   = 'N';
const uint8_t switchStatusOFF  = 'F';
const uint8_t tooHotSwitch     = 'H';
const uint8_t tooColdSwitch    = 'C';
const uint8_t noChipPresent    = 0xFF;


const long baudRate = 115200;
const uint8_t waitPin = 8;
const uint8_t waitLED = 13;

char softSerialBuffer[1024], c;
uint8_t cnt = 0;
uint8_t chipSelected;
uint8_t actionSelected;
uint8_t setChipState;
uint8_t *chipAddrPtr;
bool serialMessageReady = FALSE;
bool actionPtrMatch = FALSE;
bool showCelcius = FALSE;

uint32_t timer, timer2;
const uint32_t updateTime = 250;
const uint32_t ramUpdateTime = 10000;

// OneWire Setup;
const uint8_t oneWireAddress = 9; // OneWire Bus Address
const uint8_t chipAddrSize   = 8; // 64bit OneWire Address
const uint8_t ds2406MemWr    = 0x55;
const uint8_t ds2406MemRd    = 0xaa;
const uint8_t ds2406AddLow   = 0x07;
const uint8_t ds2406AddHi    = 0x00;
const uint8_t ds2406PIOAoff  = 0x3f;
const uint8_t ds2406PIOAon   = 0x1f;
const uint8_t ds2406End      = 0xff;
const uint8_t ds18b20ID      = 0x28;
const uint8_t ds2406ID       = 0x12;
const uint8_t dsPIO_A        = 0x20;
const uint8_t dsPIO_B        = 0x40;

const uint8_t maxChips       = 36; // Maximum number of Chips
const uint8_t maxActions     = 12; // Maximum number of Actions

OneWire  ds(oneWireAddress);

const uint32_t tempReadDelay = 125;

typedef struct
{
  uint8_t   chipAddr[chipAddrSize];
  int16_t   chipStatus;
  uint32_t  tempTimer;
}chipStruct;

chipStruct chip[maxChips] =
{
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 },
  { {0,0,0,0,0,0,0,0}, 0, 0 }
};

typedef struct
{
  bool     actionEnabled;
  chipStruct *tempPtr;
  int16_t  tooCold;
  chipStruct *tcPtr;
  uint8_t  tcSwitchLastState;
  uint32_t  tcDelay;
  uint32_t tcMillis;
  int16_t  tooHot;
  chipStruct *thPtr;
  uint8_t  thSwitchLastState;
  uint32_t  thDelay;
  uint32_t thMillis;
}chipActionStruct;

chipActionStruct action[maxActions] =
{
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 },
  { FALSE, NULL, -255, NULL, 'F', 0, 0, 255, NULL, 'F', 0, 0 }
};

uint8_t chipBuffer[12];
uint8_t chipCnt, chipX = 0, actionsCnt = 0;


//EEPROM Stuff
const int   EEPROMsize       = 2048;   // Cortex M4
const int   EEPROMidAddr     = 0x10;   // ID address to verify a previous EEPROM write
const int   EEPROMccAddr     = 0x20;   // number of chips found during findchips()
const int   EEPROMchipAddr   = 0x100;  // start address of array of chip structures
const int   EEPROMactionAddr = 0x400;  // start address of array of action structures
const byte  EEPROMidVal      = 0x55;   // Shows that an EEPROM update has occurred 
bool        eepromReady      = FALSE;
int         eepromSpace, eeResult;

void setup()
{
  int x;
  pinMode(waitPin, OUTPUT);
  pinMode(waitLED, OUTPUT);
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  Serial.begin(baudRate);
  
  #if defined (__SERIAL_DEBUG__) || defined (__SERIAL1_DEBUG__) || defined (__CHIP_DEBUG__) ||defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
 
    delay(3000);
  #endif
  
  Serial.print(F("Serial Debug running at "));
  Serial.print(baudRate);
  Serial.println(F(" baud"));


  eeResult = EEPROM.read(EEPROMidAddr);
  
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("eeResult = 0x"));
   Serial.println(eeResult, HEX);
  #endif
  
  if(eeResult != 0x55)
  {
  #if defined (__EEPROM_DEBUG__ )|| defined (__ALL_DEBUG__)
     Serial.println(F("No EEPROM Data"));
  #endif
  
    eepromReady = FALSE;
    findChips();
  }else{

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F("Getting EEPROM Data"));
  #endif

    chipCnt = EEPROM.read(EEPROMccAddr);
    EEPROM_readAnything(EEPROMchipAddr, chip); // get chip structures from EEPROM
    EEPROM_readAnything(EEPROMactionAddr, action); // get action structures from EEPROM

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F("EEPROM Data Read Completed"));
  #endif
  
    eepromReady = TRUE;
    
  }
  
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(sizeof(chipStruct) / sizeof(byte));
   Serial.println(F(" bytes in chip structure"));
   Serial.print(sizeof(chipActionStruct) / sizeof(byte));
   Serial.println(F(" bytes in action structure"));
  #endif  


  Serial1.begin(baudRate);
  Serial.print(F("Serial1 Debug running at "));
  Serial.print(baudRate);
  Serial.println(F(" baud"));
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
  timer = millis();
  timer2 = millis();
  

/// ***** Start PID Setup *****
  windowStartTime = millis();
  
  //initialize the variables we're linked to
  Setpoint = 70;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);

/// ***** End PID Setup *****
}

void loop()
{
  while(Serial1.available())
  { 
     c = Serial1.read();
     if( (c >= 0x20 && c <= 0x7E) ||
         c == 0 ||
         c == 0x0d ||
         c == 0x0a
       )
     {
       if(c == 0 || c == 0x0d || c == 0x0a)
       {
          c = 0; //null terminate the string
         serialMessageReady = TRUE;
       }
       softSerialBuffer[cnt] = c;
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.write(c);
  #endif
       cnt++;
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
       delay(2);
  #endif
     }
   }
  
  if(cnt > 0 && serialMessageReady == TRUE)
  {
  #if defined (__SERIAL_DEBUG__) || defined (__ALL_DEBUG__)
    Serial.println();
  #endif
    softSerialProcess();
  }
  
//  if(timer > (millis() + 5000)) // in case of rollover
//  {
//    timer = millis();
//  }
  
//  if(millis() > (timer + updateTime))
//  {
    updateChipStatus(chipX);
    chipX++;
    if(chipX >= maxChips){chipX = 0;}
    
    updateActions(actionsCnt);    
    actionsCnt++;
    if(actionsCnt >= maxActions){actionsCnt = 0;}

    checkPID(tChip, sChip);
  
//    timer = millis();
//  }
/*  
  if(millis() > (timer2 + ramUpdateTime))
  {
    Serial.print(freeMemory());
    Serial.println(F(" Available"));
    timer2 = millis();
  }
*/
}

void checkPID(int tChip, int sChip)
{
// *** Start PID Loop ***
  Input = (double) chip[tChip].chipStatus;
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  
  unsigned long now = millis();

  if(Output > now - windowStartTime) setSwitch(sChip,ds2406PIOAoff);
    else setSwitch(sChip,ds2406PIOAon);
// *** End PID Loop ***
}

void findChips()
{
 int cntx = 0;
 
  while (ds.search(chip[cntx].chipAddr))
  {

  #if defined (__CHIP_DEBUG__) || defined (__ALL_DEBUG__)
    
     Serial.print(F("Chip "));
     Serial.print(cntx);
     Serial.print(F(" = {"));
    
    for( int i = 0; i < chipAddrSize; i++)
    {
      if(chip[cntx].chipAddr[i]>=0 && chip[cntx].chipAddr[i]<10)
      {
        Serial.print(F("0x0"));
      }else{
        Serial.print(F("0x"));
      }
      Serial.print(chip[cntx].chipAddr[i], HEX);
      if(i < 7){Serial.print(F(","));}
    }
    Serial.println(F("}"));
  #endif    
    cntx++;
    delay(750);
  }

  #if defined (__CHIP_DEBUG__) || defined (__ALL_DEBUG__)
    Serial.print(cntx);
    Serial.print(F(" Sensor"));
    if(cntx == 1)
    {
      Serial.println(F(" Detected"));
    }else{
       Serial.println(F("s Detected"));
    }
  #endif
  
  ds.reset_search();
  chipCnt = cntx;
  if(cntx < maxChips)
  {
    for(;cntx<maxChips;cntx++)
    {
      for(int y=0;y<chipAddrSize;y++)
      {
        chip[cntx].chipAddr[y]=0;
      }
    }
  }
}

void softSerialProcess()
{
  int x, ssBufOffset;
  char *result = NULL, *addrResult = NULL;
  char delim[] = " ", addrDelim[] = ",";
  int16_t actionEnableTemp;
  int16_t resultCnt = 0, addrResultCnt = 0, actionArray, actionSection;
  uint32_t actionDelayVal;
  uint8_t addrVal[chipAddrSize], addrMatchCnt, chipAddrCnt;
  
  switch(softSerialBuffer[0])
  {
    
    case getMaxChips: // "1"
    {
      Serial1.print(maxChips);
      Serial1.print(F("\n"));
    }
    break;
    
    case showChip: // "2"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      showChipInfo(x);
    } 
    break;
    
    case getAllChips: // "9"
    {
      for(x = 0; x < maxChips; x++)
      {
        showChipInfo(x);
      }
    }
    break;
    
    case getChipCount: // "3"
    {
      Serial1.print(chipCnt);
      Serial1.print(F("\n"));
    }
    break;
    
    case getChipAddress: // "4"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      showChipAddress((uint8_t *) &chip[x].chipAddr);
      break;
    }
    
    case getAllStatus: // "7"
    {
      for(int x = 0; x < maxChips; x++)
      {
        switch (chip[x].chipAddr[0])
        {
          case ds18b20ID:
          {
            Serial1.print((int) chip[x].chipStatus);
          }
          break;
          
          case ds2406ID:
          {
              Serial1.print((char) chip[x].chipStatus);
          }
          break;
          
          default:
          {
            Serial1.print(F("Z"));
          }
          break;
        }
        if(x < maxChips -1)
        {
          Serial1.print(F(","));
        }
      }
    Serial1.print(F("\n"));
    }
    break;

    case getChipType: // "8"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      switch(chip[x].chipAddr[0])
      {
        case ds18b20ID:
        {
          Serial1.print(F("T"));
        }
        break;
 
         case ds2406ID:
        {
          Serial1.print(F("S"));
        }
        break;

        default:
        {
          Serial1.print(F("Z"));
        }
        break;
     }
    }
    Serial1.print(F("\n"));
    break;

    case setSwitchState: // "6"
    {
      chipSelected = atoi((char *) &softSerialBuffer[1]);
      if(chipSelected >= 10)
      {
        ssBufOffset = 3;
      }else{
        ssBufOffset = 2;
      }
      if(softSerialBuffer[ssBufOffset] == setSwitchON)
      {
        setChipState = ds2406PIOAon;
      }else{
        setChipState = ds2406PIOAoff;
      }
      setSwitch(chipSelected, setChipState);
      updateChipStatus(chipSelected);
      Serial1.print((char) chip[chipSelected].chipStatus);
      Serial1.print(F("\0"));
    }
    break;
    
    case getChipStatus: // "5"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      updateChipStatus(x);
      switch(chip[x].chipAddr[0])
      {
        case ds18b20ID:
        {
          Serial1.print( (int) chip[x].chipStatus);
        }
        break;

        case ds2406ID:
        {
          Serial1.print( (char) chip[x].chipStatus);
        }
        break;

        default:
        {
          Serial1.print(F("Z"));
        }
        break;
      }
    }

    case getActionArray: // "A"
    {
      x = atoi((char *) &softSerialBuffer[1]);
      Serial1.print(action[x].actionEnabled);
      Serial1.print(F(" "));
      showChipAddress((uint8_t *) &action[x].tempPtr->chipAddr);
      Serial1.print(F(" "));
      Serial1.print(action[x].tooCold);
      Serial1.print(F(" "));
      if(action[x].tcPtr == NULL)
      {
        Serial1.print(F("0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"));
      }else{
        showChipAddress((uint8_t *) &action[x].tcPtr->chipAddr);
      }
      Serial1.print(F(" "));
      Serial1.print((char) action[x].tcSwitchLastState);
      Serial1.print(F(" "));
      Serial1.print((action[x].tcDelay / 1000));
      Serial1.print(F(" "));
      Serial1.print(action[x].tcMillis);
      Serial1.print(F(" "));
      Serial1.print(action[x].tooHot);
      Serial1.print(F(" "));
      if(action[x].thPtr == NULL)
      {
        Serial1.print(F("0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"));
      }else{
        showChipAddress((uint8_t *) &action[x].thPtr->chipAddr);
      }
      Serial1.print(F(" "));
      Serial1.print((char) action[x].thSwitchLastState);
      Serial1.print(F(" "));
      Serial1.print((action[x].thDelay / 1000));
      Serial1.print(F(" "));
      Serial1.print(action[x].thMillis);
      Serial1.print(F("\0"));
      break;
    }
    
    case updateActionArray: // "B"
    {
      
      result = strtok( softSerialBuffer, delim );

      while(1)
      {
        result = strtok( NULL, delim );
        if(result == NULL){break;}
        switch (resultCnt)
        {
          case 0: // action
          {
            actionArray = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionArray = "));
             Serial.println(actionArray);
  #endif
            break;
          }
          case 1:
          {
            actionSection = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionSection = "));
             Serial.println(actionSection);
  #endif
            break;
          }
          
          case 2:
          {
            actionEnableTemp = atoi(result);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.print(F("actionEnableTemp = "));
             Serial.println(actionEnableTemp);
             Serial.print(F("action["));
             Serial.print(actionArray);
             Serial.print(F("]"));
  #endif            
            switch (actionSection)
            {
              case 1:
              {
                if(actionEnableTemp == 1)
                {
                  action[actionArray].actionEnabled = TRUE;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                   Serial.println(F(".actionEnabled is Enabled"));
  #endif
                }else{
                  action[actionArray].actionEnabled = FALSE;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 // Serial.println(F(".actionEnabled is Disabled"));
  #endif
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("action["));
                 Serial.print(actionArray);
                 Serial.print(F("].actionEnabled = "));
                 Serial.println(action[actionArray].actionEnabled);
  #endif
                break;
              }
              
              case 2:
              case 3:
              {
                if(actionSection == 2)
                {
                  action[actionArray].tooCold = actionEnableTemp;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.print(F(".tooCold is set to "));
                  Serial.println(actionEnableTemp);
  #endif
                }else if( actionSection == 3){
                  action[actionArray].tooHot = actionEnableTemp;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                   Serial.print(F(".tooHot is set to "));
                   Serial.println(actionEnableTemp);
  #endif
                }
                break;
              }
            }
            break;
          }
          
          case 3:
          {
            if(actionSection != 1)
            {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("result = "));
               Serial.println(result);
  #endif
              actionDelayVal = ((uint32_t) atoi(result));
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("actionDelayVal = "));
               Serial.println(actionDelayVal);
  #endif
              actionDelayVal *= 1000;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("actionDelayVal * 1000 = "));
               Serial.println(actionDelayVal);
               Serial.print(F("action["));
               Serial.print(actionArray);
               Serial.print(F("]."));
  #endif
              if(actionSection == 2)
              {
                action[actionArray].tcDelay = actionDelayVal;
                if(actionDelayVal > 0)
                {
                  action[actionArray].tcMillis = millis();
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("tcDelay = "));
                 Serial.println((actionDelayVal / 1000));
  #endif
              }else if (actionSection == 3){
                action[actionArray].thDelay = actionDelayVal;
                if(actionDelayVal > 0)
                {
                  action[actionArray].thMillis = millis();
                }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("thDelay = "));
                 Serial.println(actionDelayVal / 1000);
  #endif
              }
            }
            break;
          }
          
          case 4:
          {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.println(result);
  #endif
            addrResult = strtok( result, addrDelim );
            while(addrResult != NULL)
            {
              addrVal[addrResultCnt] = (uint8_t) strtol(addrResult, NULL, 16);
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F(" "));
               Serial.print(addrVal[addrResultCnt], HEX);
  #endif
              addrResultCnt++;
              addrResult = strtok( NULL, addrDelim );
            }
            for(addrMatchCnt = 0, chipAddrCnt = 0; addrMatchCnt < chipAddrSize; addrMatchCnt++)
            {
              if(addrVal[addrMatchCnt] != chip[chipAddrCnt].chipAddr[addrMatchCnt])
              {
                addrMatchCnt = 0;
                chipAddrCnt++;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                 Serial.print(F("chipAddrCnt = "));
                 Serial.println(chipAddrCnt);
                 Serial.print(F("chipCnt = "));
                 Serial.println(chipCnt);
  #endif
                continue;
              }
            }
            if(chipAddrCnt <= chipCnt)
            {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("MATCH!! - "));
  #endif
              actionPtrMatch = TRUE;
            }else{
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
               Serial.print(F("NO MATCH!! - "));
  #endif
              actionPtrMatch = FALSE;
            }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
             Serial.println(chipAddrCnt);
  #endif
            switch (actionSection)
            {
              case 1:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].tempPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].tempPtr = NULL;
                }
                break;
              }
              case 2:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].tcPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].tcPtr = NULL;
                }
                break;
              }
              case 3:
              {
                if(actionPtrMatch == TRUE)
                {
                  action[actionArray].thPtr = &chip[chipAddrCnt];
                }else{
                  action[actionArray].thPtr = NULL;
                }
                break;
              }
            }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
              //Serial.print(addrVal, HEX);
              Serial.print(F(", "));
  #endif
            break;
          }
          break;
        }
        resultCnt++;
      }
    }
      
    case getActionStatus: // "C"
    {
      getAllActionStatus();
      break;
    }
    
    case getMaxActions: // "D"
    {
      Serial1.print(maxActions);
      Serial1.print(F("\n"));
    }
    break; 

    case setActionSwitch: // "E"
    {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.println(F("case: setActionSwitch"));
       Serial.println(softSerialBuffer);
  #endif
      actionSelected = atoi((char *) &softSerialBuffer[1]);
      if(actionSelected >= 10)
      {
        ssBufOffset = 3;
      }else{
        ssBufOffset = 2;
      }
      
      if(softSerialBuffer[ssBufOffset+1] == setSwitchON)
      {
        setChipState = ds2406PIOAon;
      }else{
        setChipState = ds2406PIOAoff;
      }
      
      switch (softSerialBuffer[ssBufOffset])
      {
        case tooColdSwitch:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Setting too Cold Switch"));
  #endif
          actionSwitchSet((uint8_t *) action[actionSelected].tcPtr->chipAddr, setChipState);
          if(setChipState == ds2406PIOAoff && action[actionSelected].tcDelay > 0)
          {
            action[actionSelected].tcMillis = millis();
          }
          Serial1.print((char) action[actionSelected].tcPtr->chipStatus);
          break;
        }
        
        case tooHotSwitch:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Setting too Hot Switch"));
  #endif
          actionSwitchSet((uint8_t *) action[actionSelected].thPtr->chipAddr, setChipState);
          if(setChipState == ds2406PIOAoff && action[actionSelected].thDelay > 0)
          {
            action[actionSelected].thMillis = millis();
          }
          Serial1.print((char) action[actionSelected].thPtr->chipStatus);
          break;
        }
        
        default:
        {
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F("Houston, We HAve A Switch Problem"));
  #endif        
          break;
        }
      }
      Serial1.print(F("\0"));
      break;
    }

    case saveToEEPROM: // "F"
    {
      initEEPROM();
      break;
    }
    
    case getEEPROMstatus: // "G"
    {
      if(eepromReady == FALSE)
      {
        Serial1.print(F("FALSE"));
      }else
      {
        Serial1.print(F("TRUE"));
      }
      break;
    }
    
    case getNewSensors: // "H"
    {
      // turn off all switches
      for(x=0; x<maxChips; x++)
      {
        setSwitch(x, ds2406PIOAoff);
      }
      
      // disable and clear actions
      for(x=0; x<maxActions; x++)
      {
        action[x].actionEnabled = FALSE;
        action[x].tempPtr = NULL;
        action[x].tcPtr = NULL;
        action[x].thPtr = NULL;
      }
      // find new chips
      findChips();
      //EEPROM.write(EEPROMidAddr, 0);
      break;
    }
    
    case masterStop: //"I"
    {
      // turn off all switches
      for(x=0; x<maxChips; x++)
      {
        setSwitch(x, ds2406PIOAoff);
      }
      for(x=0; x<maxActions; x++)
      {
        action[x].actionEnabled = FALSE;
      }
      break;
    }
  }
    
    Serial1.print(F("\n"));
//    break;
  
  softSerialBuffer[0]=0x00;
  cnt = 0;
  serialMessageReady = FALSE;
}

void initEEPROM(void)
{
  int x, y, address, value;
  
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  // Serial.println(F("Clearing EEPROM Space"));
/*  
  for(int x = 0; x < EEPROMsize; x++)
  {
    EEPROM.write(x, 0xff);
  }
*/
  // Serial.println(F("EEPROM Space Cleared"));
  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(F("Writing EEPROM Data"));
  #endif

  EEPROM.write(EEPROMccAddr, chipCnt);
  EEPROM.write(EEPROMidAddr, EEPROMidVal);
  eeResult = EEPROM_writeAnything(EEPROMchipAddr, chip);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(eeResult);
   Serial.println(F(" bytes written to chip EEPROM"));
  #endif
  eeResult = EEPROM_writeAnything(EEPROMactionAddr, action);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(eeResult);
   Serial.println(F(" bytes written to action EEPROM"));
   Serial.println(F("EEPROM Data Write Completed"));
  #endif
  eeResult = EEPROM.read(EEPROMidAddr);

  #if defined (__EEPROM_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("EEPROMidAddr = 0x"));
   Serial.println(eeResult);
 
  for(y = 0, address = EEPROMchipAddr ;  y < maxChips; y++)
  {
    // read a byte from the current address of the EEPROM
     Serial.print(F("0x"));
     Serial.print(address, HEX);
     Serial.print(":\t");
    for(x = 0; x < (sizeof(chipStruct) / sizeof(byte)); x++, address++)
    {
      value = EEPROM.read(address);
      if(value >= 0 && value <= 0x0f)
      {
        Serial.print("0x0");
      }else{
        Serial.print("0x");
      }
      Serial.print(value, HEX);
      Serial.print(F(" "));
    }
    Serial.println();
  }
  
  for(y = 0, address = EEPROMactionAddr ; y < maxActions; y++)
  {
    // read a byte from the current address of the EEPROM
    Serial.print(F("0x"));
    Serial.print(address, HEX);
    Serial.print(":\t");
    for(x = 0; x < (sizeof(chipActionStruct) / sizeof(byte)); x++, address++)
    {
      value = EEPROM.read(address);
      if(value >=0 && value <= 0x0f)
      {
        Serial.print("0x0");
      }else{
        Serial.print("0x");
      }
      Serial.print(value, HEX);
      Serial.print(F(" "));
    }
    Serial.println();
  }
  #endif
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
  eepromReady = TRUE;
}

void getAllActionStatus(void)
{
  uint8_t x;
  
  // x = atoi((char *) &softSerialBuffer[1]);
  for( x = 0; x < maxActions; x++ )
  {
    Serial1.print((int) action[x].actionEnabled);
    Serial1.print(F(","));
    if(action[x].tempPtr == NULL)
    {
      Serial1.print((int) 255);
    }else{
      Serial1.print((int) action[x].tempPtr->chipStatus);
    }
    Serial1.print(F(","));
    if(action[x].tcPtr == NULL)
    {
      Serial1.print((char) noChipPresent);
    }else{
      Serial1.print((char) action[x].tcPtr->chipStatus);
    }
    Serial1.print(F(","));
    if(action[x].thPtr == NULL)
    {
      Serial1.print((char) noChipPresent);
    }else{
      Serial1.print((char) action[x].thPtr->chipStatus);
    }
    Serial1.print(F(","));
    Serial1.print((int) action[x].tooCold);
    Serial1.print(F(","));
    Serial1.print((int) action[x].tooHot);
    if( x < (maxActions - 1) )
    {
      Serial1.print(F(";"));
    }
  }
  Serial1.print(F("\n"));
}

void actionSwitchSet(uint8_t* array, uint8_t setChipState)
{
   uint8_t addrMatchCnt, chipAddrCnt;
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(F("actionSwitchSet"));
  #endif
  for(addrMatchCnt = 0, chipAddrCnt = 0; addrMatchCnt < chipAddrSize; addrMatchCnt++)
  {
    if(array[addrMatchCnt] != chip[chipAddrCnt].chipAddr[addrMatchCnt])
    {
      addrMatchCnt = 0;
      chipAddrCnt++;
      
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
       Serial.println(chipAddrCnt);
  #endif
  
      continue;
    }
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(array[addrMatchCnt], HEX);
     Serial.print(F(","));
  #endif
  }
  if(chipAddrCnt <= chipCnt)
  {

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(F("MATCH!! - "));
  #endif

    actionPtrMatch = TRUE;
  }else{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.print(F("NO MATCH!! - "));
  #endif
  
    actionPtrMatch = FALSE;
  }

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.println(chipAddrCnt);
  #endif
  
  if(actionPtrMatch == TRUE)
  {
    setSwitch(chipAddrCnt, setChipState);
  }
}

void showChipAddress( uint8_t* array)
{
  for( int i = 0; i < chipAddrSize; i++)
  {
    Serial1.print(F("0x"));
    if(array[i]>=0x00 && array[i]<=0x0F)
    {
      Serial1.print(F("0"));
    }
    Serial1.print(array[i], HEX);
    if(i < 7){Serial1.print(F(","));}
  }
    
}

void showChipInfo(int x)
{
  showChipAddress((uint8_t *) &chip[x].chipAddr);
  Serial1.print(F(" "));
  if(chip[x].chipAddr[0] == 0x12)
  {
    Serial1.print((char) chip[x].chipStatus);
  }else{
    Serial1.print((int) chip[x].chipStatus);
  }
  Serial1.print(F(" \n"));
}

void setSwitch(uint8_t x, uint8_t setChipState)
{
  if(chip[x].chipAddr[0] == 0x12)
  {
    ds.reset();
    ds.select(chip[x].chipAddr);
    ds.write(ds2406MemWr);
    ds.write(ds2406AddLow);
    ds.write(ds2406AddHi);
    ds.write(setChipState);
    for ( int i = 0; i < 6; i++)
    {
      chipBuffer[i] = ds.read();
    }
    ds.write(ds2406End);
    ds.reset();
    updateChipStatus(x);
  }
}

void updateChipStatus(int x)
{
  digitalWrite(waitPin, LOW);
  digitalWrite(waitLED, LOW);
  switch(chip[x].chipAddr[0])
  {
    case ds18b20ID:
    {
      if(chip[x].tempTimer == 0)
      {
        ds.reset();
        ds.select(chip[x].chipAddr);
        ds.write(0x4E); // write to scratchpad;
        ds.write(0x00); // low alarm
        ds.write(0x00); // high alarm
        ds.write(0x1F); // configuration register - 9 bit accuracy (0.5deg C)
        ds.reset();
        ds.select(chip[x].chipAddr);
        ds.write(0x44,1);         // start conversion, with parasite power on at the end
        chip[x].tempTimer = millis();
      }
/*    
      delay(125);     // for 9 bit accuracy
      // we might do a ds.depower() here, but the reset will take care of it.
*/    
      if((chip[x].tempTimer != 0) && (millis() >= chip[x].tempTimer + tempReadDelay))
      {
        ds.reset();
        ds.select(chip[x].chipAddr);    
        ds.write(0xBE);         // Read Scratchpad
  
        for (int i = 0; i < 4; i++) 
        {
          chipBuffer[i] = ds.read();
        }
  
      // convert the data to actual temperature
        unsigned int raw = (chipBuffer[1] << 8) | chipBuffer[0];
        if( showCelcius == TRUE)
        {
          chip[x].chipStatus = (int) ((float)raw / 16.0);
        }else{
          chip[x].chipStatus = (int) ((((float)raw / 16.0) * 1.8) + 31.0);
        }
        chip[x].tempTimer = 0;
      }
    }
    break;
    
    case ds2406ID:
    {
      ds.reset();
      ds.select(chip[x].chipAddr);
      ds.write(ds2406MemRd);
      ds.write(0x0); //2406 Addr Low
      ds.write(0x0); //2406 Addr Hgh
      for(int i = 0; i <  10; i++)
      {
        chipBuffer[i] = ds.read();
      }
      ds.reset();
      if(chipBuffer[7] & dsPIO_A)
      {
        chip[x].chipStatus = switchStatusOFF;
      }else{
        chip[x].chipStatus = switchStatusON;
      }
    }
    break;
    
    default:
    {
      chip[x].chipStatus = noChipPresent;
    }
  break; 
  }
  digitalWrite(waitPin, HIGH);
  digitalWrite(waitLED, HIGH);
}

void updateActions(uint8_t x)
{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
   Serial.print(F("updating Action: "));
   Serial.print(x);
  #endif
  if(action[x].actionEnabled == TRUE)
  {
    if(action[x].tempPtr->chipStatus <= action[x].tooCold &&
       action[x].tcPtr->chipStatus == switchStatusOFF) // too cold
    {
      if(action[x].tcDelay == 0 || millis() > (action[x].tcMillis + action[x].tcDelay))
      {
        actionSwitchSet((uint8_t *) &action[x].tcPtr->chipAddr, ds2406PIOAon);
        
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F(" - TOO COLD"));
  #endif        
      }
    }else if(action[x].tempPtr->chipStatus > action[x].tooCold &&
             action[x].tcPtr->chipStatus == switchStatusON){
               actionSwitchSet((uint8_t *) &action[x].tcPtr->chipAddr, ds2406PIOAoff);
               action[x].tcMillis = millis();
               
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.println(F(" - NOT TOO COLD"));
  #endif
  
    }

    if(action[x].tempPtr->chipStatus >= action[x].tooHot &&
       action[x].thPtr->chipStatus == switchStatusOFF) //too hot
    {
      if(action[x].thDelay == 0 || millis() > (action[x].thMillis + action[x].thDelay))
      {
        actionSwitchSet((uint8_t *) &action[x].thPtr->chipAddr, ds2406PIOAon);
        
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
           Serial.println(F(" - TOO HOT"));
  #endif
  
      }
    }else if(action[x].tempPtr->chipStatus < action[x].tooHot &&
             action[x].thPtr->chipStatus == switchStatusON){
               actionSwitchSet((uint8_t *) &action[x].thPtr->chipAddr, ds2406PIOAoff);
               action[x].thMillis = millis();
               
  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
                  Serial.println(F(" - NOT TOO HOT"));
  #endif
  
    }
  }else{

  #if defined (__SERIAL1_DEBUG__) || defined (__ALL_DEBUG__)
     Serial.println(F(" - not enabled"));
  #endif 
  }
}
 
In the Action Array, what is the difference between:
Code:
uint32_t  tcDelay;
 uint32_t tcMillis;

Are they both storing the delay time, tcDelay in seconds, and tcMillis the millisecond value of tcDelay?
 
In the Action Array, what is the difference between:
Code:
uint32_t  tcDelay;
 uint32_t tcMillis;

Are they both storing the delay time, tcDelay in seconds, and tcMillis the millisecond value of tcDelay?

The Delay value is the number of miiliseconds of delay that can be set by the user in order to delay the turn on of the associated switch. This would be used in cases where you don't want the device to be constantly turning on and off, such as a refrigerator compressor. The Millis is set with the current time the first time the trigger is reached, and reset when the trigger value is no longer correct.
 
Got my TeensyPi board and RGB LCD boards back from the fabricators, both work as planned. :ban:

Also got the switch boards back, and they also are working. :rockin:

After I've wrung them out for a couple of weeks, I'll offer then to interested parties.
 
OK, I am looking to setup the array to setup multiple PIDs

I think I understand the values of the array:
Code:
typedef struct
{
  bool     pidEnabled;
  chipStruct *tempPtr;
  int16_t  pidSetPoint;
  chipStruct *tcPtr;
  uint8_t  tcSwitchLastState;
  chipStruct *thPtr;
  uint8_t  thSwitchLastState;
  uint32_t  pidKp;
  uint32_t  pidKi;
  uint32_t  pidKd;
  uint32_t  pidDirection;
  uint32_t  pidMode;
  uint32_t  pidWindowSize;
  uint32_t  windowStartTime;
}chipPIDStruct;

chipPIDStruct ePID[maxPIDs] =
{
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 },
  { FALSE, NULL, 70, NULL, 'F', NULL, 'F', 0, 0, 0, 1, 5000, 0 }
};

Would I then call 12 individual PIDs? Or is there a way to construct via the array, to replace this code
Code:
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

Something like:
Code:
PID ePID[x](&Input, &Output, &Setpoint, &kP, &kI, &kD, &Direction);

I could then call the PID like:

Code:
void updatePIDs(uint8_t x)
{

  
  if(epid[x].actionEnabled == TRUE)
  {
    Input = ePID[x].tempPtr->chipStatus;
    ePID[x].Compute();
    
  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - ePID[x].windowStartTime>ePID[x].WindowSize)
  { //time to shift the Relay Window
    ePID[x].windowStartTime += ePID[x].WindowSize;
  }
  
  unsigned long now = millis();

  if(Output > now - windowStartTime) setSwitch(epid[x].tcPtr,ds2406PIOAoff);
    else setSwitch(epid[x].tcPtr,ds2406PIOAon);
// *** End PID Loop ***
    }
 
OK here's my thoughts on the PID so far:

First, the variables and structures:

Code:
// PID Stuff

double Input, Output;
const uint8_t maxPIDs = 12;
uint8_t pidCnt = 0;

typedef struct
{
  bool       pidEnabled;
  chipStruct *tempPtr;
  double     pidSetPoint;
  chipStruct *switchPtr;
  uint8_t    switchLastState;
  double     pidKp;
  double     pidKi;
  double     pidKd;
  int        pidDirection;
  uint32_t   pidMode;
  uint32_t   pidWindowSize;
  uint32_t   pidwindowStartTime;
  PID       *myPID;
}chipPIDStruct;

chipPIDStruct ePID[maxPIDs] =
{
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL },
  { FALSE, NULL, 70, NULL, 'F', 0, 0, 0, 1, 0, 5000, 0, NULL }
};

//Specify the links and initial tuning parameters
PID PID0(&Input,  &Output,  &ePID[0].pidSetPoint,  (double) ePID[0].pidKp,  (double) ePID[0].pidKi,  (double) ePID[0].pidKd,  ePID[0].pidDirection);
PID PID1(&Input,  &Output,  &ePID[1].pidSetPoint,  (double) ePID[1].pidKp,  (double) ePID[1].pidKi,  (double) ePID[1].pidKd,  ePID[1].pidDirection);
PID PID2(&Input,  &Output,  &ePID[2].pidSetPoint,  (double) ePID[2].pidKp,  (double) ePID[2].pidKi,  (double) ePID[2].pidKd,  ePID[2].pidDirection);
PID PID3(&Input,  &Output,  &ePID[3].pidSetPoint,  (double) ePID[3].pidKp,  (double) ePID[3].pidKi,  (double) ePID[3].pidKd,  ePID[3].pidDirection);
PID PID4(&Input,  &Output,  &ePID[4].pidSetPoint,  (double) ePID[4].pidKp,  (double) ePID[4].pidKi,  (double) ePID[4].pidKd,  ePID[4].pidDirection);
PID PID5(&Input,  &Output,  &ePID[5].pidSetPoint,  (double) ePID[5].pidKp,  (double) ePID[5].pidKi,  (double) ePID[5].pidKd,  ePID[5].pidDirection);
PID PID6(&Input,  &Output,  &ePID[6].pidSetPoint,  (double) ePID[6].pidKp,  (double) ePID[6].pidKi,  (double) ePID[6].pidKd,  ePID[6].pidDirection);
PID PID7(&Input,  &Output,  &ePID[7].pidSetPoint,  (double) ePID[7].pidKp,  (double) ePID[7].pidKi,  (double) ePID[7].pidKd,  ePID[7].pidDirection);
PID PID8(&Input,  &Output,  &ePID[8].pidSetPoint,  (double) ePID[8].pidKp,  (double) ePID[8].pidKi,  (double) ePID[7].pidKd,  ePID[8].pidDirection);
PID PID9(&Input,  &Output,  &ePID[9].pidSetPoint,  (double) ePID[9].pidKp,  (double) ePID[9].pidKi,  (double) ePID[8].pidKd,  ePID[9].pidDirection);
PID PID10(&Input, &Output, &ePID[10].pidSetPoint, (double) ePID[10].pidKp, (double) ePID[10].pidKi, (double) ePID[10].pidKd, ePID[10].pidDirection);
PID PID11(&Input, &Output, &ePID[11].pidSetPoint, (double) ePID[11].pidKp, (double) ePID[11].pidKi, (double) ePID[11].pidKd, ePID[10].pidDirection);

PID *pidArray[] = {&PID0,&PID1,&PID2,&PID3,&PID4,&PID5,&PID6,&PID7,&PID8,&PID9,&PID10,&PID11};

// End PID Stuff

You're using one temp chip and one switch for each PID.

Next, you need to initialize the PIDs in the setup():
Code:
/// ***** Start PID Setup *****

  for(x =0; x < maxPIDs; x++)
  {
    ePID[x].myPID = pidArray[x];
    ePID[x].pidwindowStartTime = millis();
    ePID[x].pidSetPoint = 70;
  //tell the PID to range between 0 and the full window size
    ePID[x].myPID->SetOutputLimits(0, ePID[x].pidWindowSize);
  //turn the PID on
    ePID[x].myPID->SetMode(AUTOMATIC);
  }


/// ***** End PID Setup *****

Then test the PID's in the loop():
Code:
    updatePIDs(pidCnt);
    pidCnt++;
    if(pidCnt >= maxPIDs){pidCnt = 0;}

And finally the actual PID control function:
Code:
void updatePIDs(uint8_t pidCnt)
{
// *** Start PID Loop ***
  Input = (double) ePID[pidCnt].tempPtr->chipStatus;
  ePID[pidCnt].myPID->Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if(millis() - ePID[pidCnt].pidwindowStartTime > ePID[pidCnt].pidWindowSize)
  { //time to shift the Relay Window
    ePID[pidCnt].pidwindowStartTime += ePID[pidCnt].pidWindowSize;
  }
  
  unsigned long now = millis();

  if(Output > now - ePID[pidCnt].pidwindowStartTime) actionSwitchSet((uint8_t *) &ePID[pidCnt].switchPtr->chipAddr,ds2406PIOAoff);
    else actionSwitchSet((uint8_t *) &ePID[pidCnt].switchPtr->chipAddr,ds2406PIOAon);
// *** End PID Loop ***
}

I've plugged this code into my IDE, and it all compiles, but I haven't actually tested it. :drunk:

You might want to try a single instance of the code and see if it behaves as you expect.

What remains are the PHP code and functions to set up and enable/disable the PIDs from the Web Interface.

But that's enough for today... :D
 
Wow, thanks for the code!

Loaded it up, and the input switch came on, but it never booted the webserver so I couldn't view the temps, it didn't react when I heated and cooled.

Hooked the raspberry pi up to my monitor, and got a lot of unreadable text during boot.

The Teensy LED also stayed solid, so it looks like it wasn't reading the sensors.

Going to keep playing with it.
 
Wow, thanks for the code!

Loaded it up, and the input switch came on, but it never booted the webserver so I couldn't view the temps, it didn't react when I heated and cooled.

Hooked the raspberry pi up to my monitor, and got a lot of unreadable text during boot.

The Teensy LED also stayed solid, so it looks like it wasn't reading the sensors.

Going to keep playing with it.

It's not going to work just "yet"...

The code still needs an initialization routine similar to the "updateActionArray" case in the softSerialProcess() function. You'll also need a php program similar to ActionDataWithMySQL.php to setup and initialize the PID array. Finally you need a php program similar to ActionStatus.php and updateActionStatusWithMySQL.php to display the PID results.

I'm right in the middle of another project right now, but I'll be happy to help when and where I can. :mug:
 
Working on the UI a bit today.

I have a dark and light version using gauges for the thermometers and switches for the switches.
TYnfSCh.png


KBURjyq.png


I will post the code tomorrow.
 
Hello:
I'm very excited about this thread and have started to assemble the parts to build per your instructions. i'm completely non-technical so I'm gambling that you guys are going to take this far enough that I won't need to hire a consultant to help me debug and implement on my build. I admire the approach though and think its the right path. At least I'll be able to provide usability feedback (and of course donate!). Keep up the great work.
 
Nice UI redbenn.

I am working on the mysql and scripts to add this to the teensypi, I have the structure down, just need to connect everything.

I will probably structure it with a light and dark template, and the ability to customize the colors/ranges as well.

Got my case yesterday, so everything was down while I work on wiring everything together.
 
Hello:
I'm very excited about this thread and have started to assemble the parts to build per your instructions. i'm completely non-technical so I'm gambling that you guys are going to take this far enough that I won't need to hire a consultant to help me debug and implement on my build. I admire the approach though and think its the right path. At least I'll be able to provide usability feedback (and of course donate!). Keep up the great work.

Welcome aboard, I'll be glad to help when I can. And thanks for the donation. :ban:
 
Started putting together the case... trying to figure how I want to hook up my pump, valves, etc.

Here is a preview of the insides...
HEf6pEK.jpg


NbrDwJA.jpg


I am going to have 10-15 XLR receptacles on the bottom where I can connect temperature sensors. I am not sure if I want to have plugs on the box for each of the 8 relays, or run wires out of the box directly from the relays to the devices. I'd like to keep it clean, but the XLRs take up much of the bottom.


While I am building, the TeensyPi is down, but have also been working on being able to customize the gauges and set a "theme" from TeensyPi's web interface. Here is a live preview of the gauge settings page: http://redbenn.com/teensypi/gaugesettings.php
 
Looks great redbenn! I've been looking through the posts and I haven't seem where you describe your intended application. From my uneducated perspective it looks like you are using the relays to drive for valve solenoids for gas burners and liquid flow; outlets are driving pumps, correct? Do you have an existing setup or are you building the controller first?

I ask as I'm planning an all electric setup (electrician is coming this weekend to help me decide 120 vs 240) and I'm extremely jealous that you are able to use the relay board... I thought your box was generously sized but now that I see your layout, I think I'm way underestimating how big my enclosure will be. I'm planning to lay it out in Sketchup first but have been looking at what's available for planning/budget purposes.

I'm assuming there's no reason the teensypi and the interface you are designing (which is very cool by the way) wouldn't work in an all electric setup with 40a SSRs, contactors, etc... I'm hoping to build the panel to allow full manual as well as minimally automated operation/data logging to start which will increase the enclosure size even more.

Anyway, keep up the good work.
 
Another noobie question; Does the fact that Jim isn't planning to use the COSM capabilility mean that he will have a different user interface than Redbennss coding or are the two of you just posting your logging/reports data in different location (local vs. cloud)?
 
Looks great redbenn! I've been looking through the posts and I haven't seem where you describe your intended application.

First use will be for fermentation temp control. Going to modify a window AC unit to chill a glycol bath that will pump to 3 stainless coils in my fermentors. The TeensyPi will control the solenoids.

I previously built Kal's electric brewery which has worked out great. I actually started thinking this morning how to integrate that system with the TeensyPi, as I agree it shouldn't be too difficult to control HLT, MLT, and Boil with the TeensyPi. I want to do more testing with the PID library to see if I can get more precise/efficient control of temps.

If I had to drive larger SSRs for heating elements, I would have got a larger enclosure. I am thinking of building a separate enclosure for the brewhouse that could connect into this main box, since I would only need a few more switches and temp probes, but would like the ability to have mechanical switches as well for manual control.
 
Another noobie question; Does the fact that Jim isn't planning to use the COSM capabilility mean that he will have a different user interface than Redbennss coding or are the two of you just posting your logging/reports data in different location (local vs. cloud)?

Just different locations.
 
Jimmay, any reason you didn't go for the DS2413 switches, instead of the DS2406? Are you using the memory on the chip?

They are about half the cost.

*edit, looks like they only come in a 6-TSOC surface mount vs the TO-92 of the DS2406.
 
Jimmay, any reason you didn't go for the DS2413 switches, instead of the DS2406? Are you using the memory on the chip?

They are about half the cost.

*edit, looks like they only come in a 6-TSOC surface mount vs the TO-92 of the DS2406.

You answered your own question ;)

I'm trying to keep every thing through-hole mountable so that the average person can put it together with minimal tools and experience.

I did buy some TSOC-6 to DIP-6 adapters from epBoard.com to try them out, I just haven't gotten around to it yet. :drunk:
 
Looks great redbenn! I've been looking through the posts and I haven't seem where you describe your intended application. From my uneducated perspective it looks like you are using the relays to drive for valve solenoids for gas burners and liquid flow; outlets are driving pumps, correct? Do you have an existing setup or are you building the controller first?

I ask as I'm planning an all electric setup (electrician is coming this weekend to help me decide 120 vs 240) and I'm extremely jealous that you are able to use the relay board... I thought your box was generously sized but now that I see your layout, I think I'm way underestimating how big my enclosure will be. I'm planning to lay it out in Sketchup first but have been looking at what's available for planning/budget purposes.

I'm assuming there's no reason the teensypi and the interface you are designing (which is very cool by the way) wouldn't work in an all electric setup with 40a SSRs, contactors, etc... I'm hoping to build the panel to allow full manual as well as minimally automated operation/data logging to start which will increase the enclosure size even more.

Anyway, keep up the good work.

As a matter of fact, I've just wired up 4 25A SSRs in a 4-gang electrical box with 4 DS2406+ switches on a small PC board I made, and am getting ready to run some tests using small containers of water, and immersible heaters.

Stay tuned...
 
Another noobie question; Does the fact that Jim isn't planning to use the COSM capabilility mean that he will have a different user interface than Redbennss coding or are the two of you just posting your logging/reports data in different location (local vs. cloud)?

Correct. You could actually add both, run them side-by-side, and compare the results.

That's the great thing about open hardware/software, all of the tools are there to allow you to do whatever you are capable of doing. :mug:
 
As a matter of fact, I've just wired up 4 25A SSRs in a 4-gang electrical box with 4 DS2406+ switches on a small PC board I made, and am getting ready to run some tests using small containers of water, and immersible heaters.

Stay tuned...

Now you're talking! Pictures please.
 
First use will be for fermentation temp control. Going to modify a window AC unit to chill a glycol bath that will pump to 3 stainless coils in my fermentors. The TeensyPi will control the solenoids.

I previously built Kal's electric brewery which has worked out great. I actually started thinking this morning how to integrate that system with the TeensyPi, as I agree it shouldn't be too difficult to control HLT, MLT, and Boil with the TeensyPi. I want to do more testing with the PID library to see if I can get more precise/efficient control of temps.

If I had to drive larger SSRs for heating elements, I would have got a larger enclosure. I am thinking of building a separate enclosure for the brewhouse that could connect into this main box, since I would only need a few more switches and temp probes, but would like the ability to have mechanical switches as well for manual control.


I'm trying to start small and build a piece at a time but I'm fighting with creeping elegance and keeping enough flexibility to do stuff I may do someday (or not). Initial use will be for temp control of an eKettle and then for a recirculating eBIAB system. Next would be two vessel Brutus 20 and eventually a 3 vessel setup. That's the attraction of the TeensyPi to me is I can adapt it as I go, learn some skills and not outgrow the hardware. Problem is I'm so busy contingency planning that I'm not building anything!
 
Finally got everything wired up last night. Was able to use the relays to turn a light on and off remotely. Decided with the limited bottom panel space to run wire out to an 8 outlet junction box.

8486861381_5ed901f5cb_z.jpg


Also ordered parts to build a secondary control panel, that I am hoping to use in my Kal Clone setup, replacing the PIDs with the TeensyPi, and having the 1-wire and manual switches, with a manual override switch to control pumps manually if needed.
 
Second the kudos redbenn!

I'm working under the assumption I can substitute the Teensypi for the BCS in the attached PJ-generated wiring diagram. Any concerns/issues? I'll use a 5V power supply similar to the one Jim suggested.

Kenneth-BCS-460-wiring-2-4a.jpg
 
Second the kudos redbenn!

I'm working under the assumption I can substitute the Teensypi for the BCS in the attached PJ-generated wiring diagram. Any concerns/issues? I'll use a 5V power supply similar to the one Jim suggested.

Is there a higher resolution image available? My eyes aren't as good as they used to be.

Nevermind, I found a better image.

The control side of the two designs are opposite.

The BCS outputs source 5V at up to 20 ma. the DS2406+ sinks up to 5v at about 30 ma.

The difference is in the wiring of the SSRs and switches.

The BCS outputs are connected to the positive input of the SSR and the negative input is connected directly to ground.

The TeensyPi DS2406+ is wired with the output of the ds2406+ wired to the negative side of the SSR and the positive side wired directly to 5v.

If you wanted a manual/auto switch inserted, it would be on the ground/negative side with the TeensyPi.

A very basic diagram is here.

The AC side would be unchanged.

That is probably not the wiring diagram you want to use.
 
Bad news is I'm dumber than I thought I was; good news is that I don't have to go buy new components! I'll draw my own plan with those changes in mind and run it by you.

I have the last of the Teensypi elements ordered so I think this will click better once I have a test setup to play with. I have the Fortek SSRs to test as well so I should know in the next week if I've got the skills to do this. I got the RPi to boot and access the web so I'm on my way! Look forward to hearing the results of your water/heater tests as I'm anxious to see data on the responsiveness of the sensors and need for PID code.
 
Back
Top