// Include the libraries:
#include <Arduino.h>
#include "EPCS_relay.h"
#include "EPCS_dht22.h"
#include "EPCS_comms.h"
#include "Config.h"
#include "EPCS.h"
#include <avr/wdt.h>
//These are the project veriables
#define VERSION "0.r2.1"
//Create the global pointers and other global veriables
myAllRelays* RList = NULL;
mySensorType SList[MAX_SENSORS];
int inputChannels[MAX_SENSORS] = { INPUT_CHANNELS };
char inputTypes[MAX_SENSORS] = { INPUT_TYPES };
myOutputs* myInterface = NULL;
DhtLib* dht[3];
unsigned long runNow; //The next time to get the average temperature will be processed etc and generate output
unsigned long sampleNow; //The next time to get DHT sensor values
float useTemp = errT; //The current temperature to control the relays
bool Flash = false; //LED to indicate board is alive
unsigned long FlashNow; //The next time to flash
bool CommsOK; //Flag to track the status of the comms links
bool Verbose = VERBOSE; //Set the lots of output flag
/************************ Code ****************************/
//Configure the Relays as defined in Config.h
void initR() {
RList = new myAllRelays(N_RELAYS);
if (RList->Info.inuse > MAX_RELAYS) RList->Info.inuse = MAX_RELAYS;
if (N_RELAYS > 0) RList->Relay(0)->Set(RELAY_1);
if (N_RELAYS > 1) RList->Relay(1)->Set(RELAY_2);
if (N_RELAYS > 2) RList->Relay(2)->Set(RELAY_3);
if (N_RELAYS > 3) RList->Relay(3)->Set(RELAY_4);
if (N_RELAYS > 4) RList->Relay(4)->Set(RELAY_5);
if (N_RELAYS > 5) RList->Relay(5)->Set(RELAY_6);
if (N_RELAYS > 6) RList->Relay(6)->Set(RELAY_7);
if (N_RELAYS > 7) RList->Relay(7)->Set(RELAY_8);
}
//Configure the inputs as defined in Config.h
void initS() {
int j = 0;
for (int i = 0; i < NUMBER_INPUTS; i++) {
SList[i].channel = inputChannels[i];
SList[i].type = inputTypes[i];
SList[i].state = false;
SList[i].failed = false;
if (SList[i].type == 'S') {
SList[i].dhtNum = j;
//dht[j] = new DhtLib(SList[i].channel);
//dht[j]->begin();
j = j + 1;
if (j == 3) j = 0; //Stop the array from going out of bounds
}
if (SList[i].type == 'D') {
pinMode(SList[i].channel, INPUT);
}
}
}
void setup() {
unsigned long delayT = millis();
//Set the indicator LED
if (LED_FLASH > 0) {
pinMode(LED_FLASH, OUTPUT);
FlashNow = millis();
}
while ((millis() - delayT) < StartDelay) {} //Do Nothing
runNow = millis(); //Sets the starting cycle time in ms
//Create the output class but does not initilise any of the streams. Arduino hangs if the recevers are not ready!
//myInterface = new myOutputs(OUTPUT_SERIAL, OUTPUT_TCP, OUTPUT_UDP);
//Setup the I/O ports, configure the veriables etc.
initR();
initS();
//Make the sensor storage
Serial.begin(9600);
for (int i = 0; i < 3; i++) dht[i] = new DhtLib(i + 6);
for (int i = 0; i < 3; i++) dht[i]->begin();
}
//Find the current average for all of the temperature values
float AverageOfAverages() {
float av = 0.0;
float count = 0;
for (int i = 0; i < NUMBER_INPUTS; i++) {
if (SList[i].Temperature.mean != errT) {
count++;
av += SList[i].Temperature.mean;
}
}
if (count > 0) av = av / count;
else av = errT;
return av;
}
//Find the rolling average for the sensor values
void Average(myResultType* info) {
if (info->value > errT) {
info->count++;
info->total += info->value;
//If we have enough samples find the average. Average start as errT and then be the last valid reading
if (info->count == SAMPLES_TO_AVERAGE) {
info->mean = info->total / info->count;
info->count = 0;
info->total = 0.0;
}
}
}
void GetReadings() {
//Sample the seneors and find the folling average for each sensor
for (int i = 0; i < NUMBER_INPUTS; i++) {
if (SList[i].type == 'S') {
SList[i].Temperature.value = dht[SList[i].dhtNum]->getTemperature();
if (SList[i].Temperature.value == errT) SList[i].failed = true;
else {
Average(&SList[i].Temperature);
SList[i].Humidity.value = dht[SList[i].dhtNum]->getHumidity();
;
Average(&SList[i].Humidity);
}
}
if (SList[i].type == 'D') {
SList[i].state = digitalRead(SList[i].channel);
}
}
}
void SetReading(int Sensor, float Reading) {
//Sets the reading for a virtual sensor
if (Sensor > 0 && Sensor < NUMBER_INPUTS + 1) {
if (SList[Sensor].type == 'V') {
SList[Sensor].Temperature.mean = Reading;
}
}
}
void AddNumber(float num, char* units, char* txt) {
char numTxt[8];
strcat(txt, ",");
dtostrf(num, 2, 1, numTxt);
strcat(txt, numTxt);
if (Verbose) strcat(txt, units);
}
void ShowReadings(float temperature) {
char msgTxt[200] = { '\0' };
char subTxt[100] = { '\0' };
strcat(msgTxt, NAME);
AddNumber(temperature, "C", msgTxt);
for (int i = 0; i < NUMBER_INPUTS; i++) {
if (Verbose) {
sprintf(subTxt, ",%d%c", i + 1, SList[i].type);
strcat(msgTxt, subTxt);
}
if (SList[i].failed) strcat(msgTxt, ",FAIL");
else {
if (SList[i].type == 'S') {
if (Verbose) AddNumber(SList[i].Temperature.value, "C", msgTxt);
AddNumber(SList[i].Temperature.mean, "aC", msgTxt);
if (Verbose) AddNumber(SList[i].Humidity.value, "%", msgTxt);
AddNumber(SList[i].Humidity.mean, "a%", msgTxt);
}
if (SList[i].type == 'D') {
sprintf(subTxt, ",%d", SList[i].state);
strcat(msgTxt, subTxt);
}
if (SList[i].type == 'V') {
AddNumber(SList[i].Temperature.mean, "aC", msgTxt);
}
}
}
subTxt[0] = '\0';
RList->Print(Verbose, subTxt);
strcat(msgTxt, subTxt);
myInterface->Snd(msgTxt);
}
//Causes an LED on the board to flash every second.
void FlashLED(unsigned long myNow) {
if (LED_FLASH > 0) {
if (myNow >= FlashNow) {
FlashNow += 500;
if (Flash) {
digitalWrite(LED_FLASH, LOW);
Flash = false;
} else {
digitalWrite(LED_FLASH, HIGH);
Flash = true;
}
}
}
}
//Carry out the commends
void DoCommand(myCommandType* Command) {
switch (Command->number) {
case 1: //Long message command
Verbose = true;
break;
case 2: //Short message command
Verbose = false;
break;
case 3: //Reboot command
wdt_enable(WDTO_15MS); //Turn on the WatchDog and don't stroke it.
for (;;) {} //do nothing and wait for the eventual...
break;
case 4: //Serial message command
myInterface->Reset(1, Command->param1);
break;
case 5: //TCP message command
myInterface->Reset(2, Command->param1);
break;
case 6: //UDP message command
myInterface->Reset(3, Command->param1);
break;
case 7: //All relays message command
if (Command->param1 > -1 && Command->param1 < 4) RList->ManualLock = Command->param1;
break;
case 8: //Single Relay message command
RList->LockRelay(Command->param1, Command->param2);
break;
case 9: //Sets the virtual sensor reading
SetReading(Command->param1, Command->param2);
break;
}
}
void loop() {
unsigned long myNow = millis();
char myTxt[80];
myCommandType ThisCommand;
//Flashes the indicator to show we are running
FlashLED(myNow);
//This gets sensor readings at the rate speicified. It can be faster or slower (more likely) than the relay update reat
if (myNow >= sampleNow) {
sampleNow += SensorDelay;
//If the comms are not running try and start them
//if (!CommsOK) CommsOK = myInterface->StartComms(NAME, VERSION);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
GetReadings();
useTemp = AverageOfAverages();
}
//Controls the relays etc.
if (myNow >= runNow) {
runNow += CycleDelay;
//Operate the relays. If there is a valid temperature reading
if (useTemp != errT) {
RList->SetRelays(myNow); //See which relays need to change in this time step, and change them
RList->FindState(useTemp); //Find the state a relay should be in according to the current temperature
RList->FindTime(myNow); //If the relay is in a diffent state to the one it should be in, set a time for it to change
}
ShowReadings(useTemp); //Provides output
myInterface->Command(&ThisCommand);
if (ThisCommand.number > 0) DoCommand(&ThisCommand);
}
}