IO Expansion methods

Do you have a question on how to do something.
Ask in here.

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: 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.

viewtopic.php?f=9&t=4567&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();


}

Posts: 12327
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sat Jan 07, 2017 7:24 pm
Are you trying to use it as output or input?
Roberto.

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: Sat Jan 07, 2017 7:39 pm
I will use some as input only and some as outputs

Posts: 12327
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sat Jan 07, 2017 10:57 pm
As input, it is easy.
Code: Select all
if (ReefAngel.IO.GetChannel(0))
{
}

As output, we don't have a library for it.
The reason is that it is not recommended unless you really know what you doing and understand a little of electronics.
Each channel is only capable of driving 25mA. So, you can't really drive anything more than a small LED.
So, you are better off using one of the relays for output rather than the I/O.
Roberto.

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: Sun Jan 08, 2017 8:41 am
i am not an expert, but i do know the basics about electronics. I will mostly be driving a relay for my 5v/12v stuff.

Posts: 12327
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sun Jan 08, 2017 10:38 am
Ok. good.
So, just make sure you do not drive the relay directly from the pin of the I/O module.
You need a relay driver with a feedback diode.
Something like this:
http://www.learningaboutelectronics.com ... ircuit.php
Roberto.

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: Sun Jan 08, 2017 12:16 pm
yea, i have an opto isolated relay like the sainsmart i had from a netduino project.

Posts: 12327
Joined: Fri Mar 18, 2011 6:47 pm
PostPosted: Sun Jan 08, 2017 2:08 pm
Ok, so you are good.
You can update the I/O module just like the relay box, except you change the address to the I/O expansion module.
It uses the same chipset PCF8574.
Code: Select all
    Wire.beginTransmission(I2CIO_PCF8574);
    Wire.write(data);
    Wire.endTransmission();

Where data is what you want to output.
Roberto.

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: Sun Jan 08, 2017 2:40 pm
Wow that is plenty easy enough. But one question. Which of the 6 will that data be sent to?

Thanks!

Posts: 33
Joined: Thu Nov 24, 2016 7:19 am
PostPosted: Sun Jan 08, 2017 8:45 pm
[quote="rimai"]As input, it is easy.
Code: Select all
if (ReefAngel.IO.GetChannel(0))
{
}


After learning how I2C works and seeing how it is
used then reviewing the schematic I have come to
Understand that the is a I2C slave based off the 328p.
With that in mind I looked back at all the code libraries
Especially the expansion libraries. I am not seeing how
I can get more that a bit from the IO expansion. Will it
Return more than 1 byte as in the io library? I can only
assume that there is some code running on the 328p that
"Packages" the data from the 6 pins into 1 byte.

Please help me understand how to talk to this thing.
Next

Return to How do I code ...

Who is online

Users browsing this forum: No registered users and 2 guests

cron