IO Expansion methods
Posted: Sat Jan 07, 2017 5:34 pm
I just got my Water Level and IO Expansion and Expansion hub yesterday. Got the WL all calibrated and it is working GREAT! Should have done this long ago. I do daily water changes and by using the high and low ATO memvars I can dial in EXACTLY how much water to drain before turning the ATO back on. Also, I noticed it had come on alot over night and realized that i had the upper limit set above may overflow drain and so the RO was running ever 30-45 min. i was able to keep dialing it down while i was out to running errands this morning until I got it below the overflow mark. This was all done on my phone!!!! Its freakin cool!!!!
This evening I have turned my attention to start using the IO and have run into a bit of a snafu.....
I have scoured the forum, the code (even stepping through every instance of "IO" in ReefAngle.ccp) and google for info on how to use the IO Expansion. The only thing i have found is this rather old reference which appears to be from when it was in its infancy.
http://forum.reefangel.com/viewtopic.ph ... 7&start=10
The IO class itself only has one method - GetChannel which appears to only do a read. That would be the "Output" part of IO, but how do you write to it? Also, how do you address each individual pin on the device?
A couple of code snippets should be able to get me on my way.
Thanks!
This evening I have turned my attention to start using the IO and have run into a bit of a snafu.....
I have scoured the forum, the code (even stepping through every instance of "IO" in ReefAngle.ccp) and google for info on how to use the IO Expansion. The only thing i have found is this rather old reference which appears to be from when it was in its infancy.
http://forum.reefangel.com/viewtopic.ph ... 7&start=10
The IO class itself only has one method - GetChannel which appears to only do a read. That would be the "Output" part of IO, but how do you write to it? Also, how do you address each individual pin on the device?
A couple of code snippets should be able to get me on my way.
Thanks!
Code: Select all
#include <ReefAngel_Features.h>
#include <Globals.h>
#include <RA_Wifi.h>
#include <Wire.h>
#include <OneWire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <InternalEEPROM.h>
#include <RA_NokiaLCD.h>
#include <RA_ATO.h>
#include <RA_Joystick.h>
#include <LED.h>
#include <RA_TempSensor.h>
#include <Relay.h>
#include <RA_PWM.h>
#include <Timer.h>
#include <Memory.h>
#include <InternalEEPROM.h>
#include <RA_Colors.h>
#include <RA_CustomColors.h>
#include <Salinity.h>
#include <RF.h>
#include <IO.h>
#include <ORP.h>
#include <AI.h>
#include <PH.h>
#include <WaterLevel.h>
#include <Humidity.h>
#include <DCPump.h>
#include <PAR.h>
#include <ReefAngel.h>
////// Place global variable code below here
// Define Custom Memory Locations
#define Mem_B_MoonOffset 100
#define Mem_B_Vacation 101
#define Mem_B_AutoFeed 102
#define Mem_B_AutoFeedPress 103
#define Mem_B_AutoFeedRepeat 104
#define Mem_B_AutoFeedOffset 105
#define Mem_I_WCFillTime 106
byte wc_status = 0;
time_t ato_endfill;
byte ato_topping = 0;
void init_memory() {
// Initialize Custom Memory Locations
InternalMemory.write(Mem_B_Vacation,false);
InternalMemory.write(Mem_B_AutoFeed,true);
InternalMemory.write(Mem_B_AutoFeedPress,2);
InternalMemory.write(Mem_B_AutoFeedRepeat,4);
InternalMemory.write(Mem_B_AutoFeedOffset,3);
InternalMemory.write_int(Mem_I_WCFillTime,1200 ); //How long topoff is allowed to run
}
// Define Relay Ports by Name
#define T5Light 1
#define LEDLights 2
#define ATODrain 3
#define Feeder 4
#define Mixer 5
#define Topoff 6
#define Ferts 7
#define Filter 8
////// Place global variable code above here
void setup()
{
// This must be the first line
ReefAngel.Init(); //Initialize controller
ReefAngel.Use2014Screen(); // Let's use 2014 Screen
ReefAngel.AddWaterLevelExpansion(); // Water Level Expansion Module
// Ports toggled in Feeding Mode
ReefAngel.FeedingModePorts = 0;
// Ports toggled in Water Change Mode
ReefAngel.WaterChangePorts = 0;
// Ports toggled when Lights On / Off menu entry selected
ReefAngel.LightsOnPorts = 0;
// Ports turned off when Overheat temperature exceeded
ReefAngel.OverheatShutoffPorts = 0;
// Use T1 probe as temperature and overheat functions
ReefAngel.TempProbe = T1_PROBE;
// Ports that are always on
ReefAngel.Relay.Auto(Filter);
////// Place additional initialization code below here
init_memory();
// Ports that default off
ReefAngel.Relay.Off(ATODrain);
ReefAngel.Relay.Off(Feeder);
ReefAngel.Relay.Off(Mixer);
ReefAngel.Relay.Off(Ferts);
ReefAngel.CustomLabels[0]="T5 Light";
ReefAngel.CustomLabels[1]="LED";
ReefAngel.CustomLabels[2]="Drain";
ReefAngel.CustomLabels[3]="Feeder";
ReefAngel.CustomLabels[4]="Mixer";
ReefAngel.CustomLabels[5]="Topoff";
ReefAngel.CustomLabels[6]="Ferts";
ReefAngel.CustomLabels[7]="Filter";
ReefAngel.Relay.On(Filter);
////// Place additional initialization code above here
}
void loop()
{
ReefAngel.StandardLights( LEDLights);
ReefAngel.StandardLights( T5Light);
ReefAngel.PWM.SetActinic( PWMSlope(9,0,20,0,15,100,60,15) );
////// Place your custom code below here
//Automation
//RunFeeder();
//Water Change
if (hour() == InternalMemory.DP1Timer_read() && minute() == InternalMemory.DP1RepeatInterval_read()) {
wc_status = 1;
}
if (wc_status > 0 ) {
AutoWaterChange();
}
//Keep Water topped off
AutoTopOff();
////// Place your custom code above here
// This should always be the last line
ReefAngel.Portal( "diverjoe" );
ReefAngel.DDNS("75");
ReefAngel.ShowInterface();
}
void AutoTopOff() {
//run for 30 sec any time float valve is turned on and WC drain is not active
if (ato_endfill > now() && wc_status != 1 && ato_topping) {
ReefAngel.Relay.On(Topoff);
}
else {
ReefAngel.Relay.Off(Topoff);
ato_topping = 0;
if ( ReefAngel.WaterLevel.GetLevel() < InternalMemory.WaterLevelLow_read () && !ato_topping) {
ato_endfill = now() + InternalMemory.ATOExtendedTimeout_read();
ato_topping = 1;
}
}
}f
void RunFeeder() {
boolean autoFeed;
static time_t t;
int press, repeat, offset;
autoFeed=InternalMemory.read(Mem_B_AutoFeed);
press=InternalMemory.read(Mem_B_AutoFeedPress);
repeat=InternalMemory.read(Mem_B_AutoFeedRepeat)*SECS_PER_HOUR;
offset=InternalMemory.read(Mem_B_AutoFeedOffset)*SECS_PER_HOUR;
ReefAngel.Relay.Set(Feeder, autoFeed);
if (ReefAngel.Relay.Status(Feeder)!=autoFeed) {
autoFeed=ReefAngel.Relay.Status(Feeder);
InternalMemory.write(Mem_B_AutoFeed, autoFeed);
ReefAngel.Relay.Auto(Feeder);
}
if (autoFeed) {
if (((hour() > 9 && hour() < 20)) && (now()+offset)%repeat==0) {
t=now();
}
}
if (ReefAngel.Relay.isMaskOn(Feeder)) {
ReefAngel.Relay.Auto(Feeder);
t=now()-now()%20; // One feeding has already happened.
}
// Press the button once every 20 seconds
if (now()-t < press*20) {
ReefAngel.Relay.Set(Feeder,now()%20==0);
} else {
ReefAngel.Relay.Off(Feeder);
}
}
void AutoWaterChange() {
int NowMins;
static time_t t;
if (wc_status == 1) {
ReefAngel.Relay.Override(Topoff,0);
ReefAngel.Relay.Off(Topoff);
ReefAngel.Relay.Off(Filter);
ReefAngel.Relay.Auto(ATODrain);
ReefAngel.Relay.On(ATODrain);
}
if(ReefAngel.WaterLevel.GetLevel() < InternalMemory.WaterLevelHigh_read() && wc_status == 1)
{
wc_status = 2; //Enter Mix mode
ReefAngel.Relay.Auto(ATODrain);
ReefAngel.Relay.Off(ATODrain);
ReefAngel.Relay.On(Mixer);
ReefAngel.Relay.Auto(Topoff);
ReefAngel.Relay.On(Topoff);
ReefAngel.Relay.Auto(Filter);
ReefAngel.Relay.On(Filter);
t = now();
}
//Ferts Mode
if ( wc_status == 2) {
if (now() - t > SECS_PER_MIN * InternalMemory.DP2Timer_read()) {
wc_status = 3; //enter Ferts mode
ReefAngel.Relay.Off(Mixer);
ReefAngel.Relay.On(Ferts);
t = now();
}
}
//ferts Mode
if ( wc_status == 3) {
if (now() - t > InternalMemory.DP2RepeatInterval_read()) {
ReefAngel.Relay.Off(Ferts);
wc_status = 0;
}
}
}
// Disable masks for things that should not be turned on by mistake
void LockPorts() {
ReefAngel.AddPortOverrides();
}