Peristaltic Doser - Doser set amount over 24hr period

I figured this out..basically any time, less than or equal to now, will immediately fire the relay. Is that correct?

With regards to the retained variables, I'm not sure what changed. It worked at one point, and now it suddenly isn't working at all. I double checked that the photon is still receiving the 3.2v, which it is. It used to work perfectly, now its not working at all. Here is the code.

typedef struct {
    int onTime;
    int offTime;
    float totalDose;
    float doseRate; // mL/min
    int connectedPin;
    int calibrationEnd = 90000; // a vaule greater than "now" can ever be
    int numberOfDoses; //number of doses in 24hr period
} Channel;
 
 STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));
 
 void updateChannel(Channel c);
 float now;
 
     char getRelay1[75];
     char getRelay2[75];
     char getRelay3[75];
     char getRelay4[75];
    
retained Channel channels[4];


void setup() {
    channels[1].connectedPin = D3;
    channels[2].connectedPin = D4;
    channels[3].connectedPin = D5;
    channels[4].connectedPin = D6;
    pinMode(D3,OUTPUT);
    pinMode(D4,OUTPUT);
    pinMode(D5,OUTPUT);
    pinMode(D6,OUTPUT);
    Serial.begin(9600);
    Time.zone(-4);
    delay(3000);
    Particle.function("setupChannel", setupChannel);
    Particle.function("calibrate",calibrate);
    Particle.function("manual",manual);
    Particle.variable("getRelay1", getRelay1);
    Particle.variable("getRelay2", getRelay2);
    Particle.variable("getRelay3", getRelay3);
    Particle.variable("getRelay4", getRelay4);
   }


void loop() {
    now = Time.hour() * 3600 + Time.minute() * 60 + Time.second();
    Serial.println(now);
    for (int i=0;i<4;i++) {
        updateChannel(i);
    }
    
    
    delay(5000);
}



void updateChannel(int index) {
    Channel *c = &channels[index];
    if (c->onTime <= now && c->totalDose > 0) { 
        digitalWrite(c->connectedPin, HIGH);
        Serial.printlnf("Fired Relay %d", index);
        c->onTime += 7200;
    }

    if (c->offTime <= now && c->totalDose > 0) {
        digitalWrite(c->connectedPin, LOW);
        Serial.printlnf("Turned off Relay %d", index);
        c->offTime += 7200;
    }
    
        if (c->calibrationEnd <= now) {
        digitalWrite(c->connectedPin, LOW);
        c->calibrationEnd = 90000;
    }
}


int setupChannel(String cmd) { // cmd syntax: "channel#,startTime,doseRate, numberOfDoses, totalDose" (startTime is sent as hour*3600 + minute*60 + second)
    Serial.println(cmd);
    char *rmdr;
    char *stringArgs = (char*)cmd.c_str();
    int index = atoi(strtok_r(stringArgs, ",", &rmdr));
    Channel* c = &channels[index];
    c->onTime = atof(strtok_r(NULL, "," ,&rmdr));
    c->doseRate = atof(strtok_r(NULL, "," , &rmdr));
    c->numberOfDoses = atoi(strtok_r(NULL, ",", &rmdr));
    c->totalDose = atof(rmdr);
    float dosePerActuation = c->totalDose/c->numberOfDoses;
    float durationPerActuation = (dosePerActuation/c->doseRate) * 60; // assuming doseRate is in volume/minute
    c->offTime = c->onTime + durationPerActuation;
  
    Serial.printlnf("channel#: %d, onTime: %d, doseRate: %f, totalDose: %f, numberOfDoses: %d", index, c->onTime, c->doseRate, c->totalDose, c->numberOfDoses);
char *str;
    switch (index) {
        case 1:
            str = getRelay1;
            break;
        case 2:
            str = getRelay2;
            break;
        case 3:
            str = getRelay3;
            break;
        case 4:
            str = getRelay4;
            break;
    }
    sprintf(str, "onTime: %d, totalDose: %.1f, numberOfDoses: %.1d", c->onTime, c->totalDose, c->numberOfDoses);
    return 1;
}

float doseRate(String cmd) {
    char *rmdr;
    char *stringArgs = (char*)cmd.c_str();
    int index = atoi(strtok_r(stringArgs, ",", &rmdr));
    Channel* c = &channels[index];
    return 1;
    
}
    int calibrate(String cmd) {
    char *rmdr;
    char *stringArgs = (char*)cmd.c_str();
    int index = atoi(strtok_r(stringArgs, ",", &rmdr));
    Channel* c = &channels[index];
    
    if (strcmp(rmdr, "on") == 0) {
        digitalWrite(c->connectedPin,HIGH);
        c->calibrationEnd =  Time.hour() * 3600 + Time.minute() * 60 + Time.second() + 60;
        return 1;
    }
    else if (strcmp(rmdr, "off") == 0) {
        digitalWrite(c->connectedPin,LOW);
        return 0;
    }
    else {
        return -1;
    }
}
    int manual(String cmd) {
    char *rmdr;
    char *stringArgs = (char*)cmd.c_str();
    int index = atoi(strtok_r(stringArgs, ",", &rmdr));
    Channel* c = &channels[index];
    
    if (strcmp(rmdr, "on") == 0) {
        digitalWrite(c->connectedPin,HIGH);
        return 1;
    }
    else if (strcmp(rmdr, "off") == 0) {
        digitalWrite(c->connectedPin,LOW);
        return 0;
    }
    else {
        return -1;
    }
}

Any thoughts on why the retained variables may have worked before, and now it doesn’t
How would I troubleshoot this?

If you’re testing by checking your Particle variables, they need to be retained too. In the code you posted that was a screen image of your phone, you did have those marked as retained. In this latest code, they are not.

There is a bit of misunderstanding then, I thought you said I only needed it on the channels. Either way, I put it back in to play on the getRelay variables:

     retained char getRelay1[75];
     retained char getRelay2[75];
     retained char getRelay3[75];
     retained char getRelay4[75];

     retained Channel channels[4];

I then tested by inputting variables for channel 1, removed the USB plug, let it sit for about a minute, then plugged it back in, and you can see the results on the last line.

DUSTINs-MBP-2:~ dustinbetterly$ particle call doser-4 setDoseRate 1,50
1
DUSTINs-MBP-2:~ dustinbetterly$ particle call doser-4 setupChannel 1,10000,10,1000
1
DUSTINs-MBP-2:~ dustinbetterly$ particle get doser-4 getRelay1
onTime: 10000, t

So the issue only seems to reside with the first channel. Would this have anything to do with me changing the relay numbers from 0,1,2,3 to 1,2,3,4?

Probably, but it’s hard to know without seeing your whole code. However, and this is a big however; it shouldn’t be our job to troubleshoot your code. You need to do that, and you need to have the knowledge base in C and in Particle devices to do that for yourself. The way you’re pursing this project is extremely inefficient; we’re up to 206 posts on this thread, and you asked initially about this project (or a related one) back in May of 2014. It’s clear from the questions that you’re asking, and your coding attempts, that you don’t have the necessary background in C to pull this project off. Getting us to write the program through numerous questions, suggestions, hints, etc. is not going to go well; none of us knows exactly what you want, and none of us sees the whole project, so you’re likely to end up wth a mish-mash that won’t work properly. You really should step back from this project, and take whatever time it takes to learn C, and the unique characteristics of the Particle devices. I think you will find it much more rewarding, and much less frustrating to complete the project, if you learn the basics first.

3 Likes

My apologies to all. I sincerely had no intentions of taking advantage of people, but had intentions of learning. I’m not a person who learns by reading, but by doing, hence me coming here. I guess I’ll have to try and find some video tutorials as I’ve never been good at learning from books. Its become clear to me through some of the hasty responses that I’ve become a burden, which was not my intention.

It seems I’ve resolved most of my issues, the project isn’t quite where I wanted it, but I’ll work it out over time.

The better way to learn is not always by making something barely work but by understanding why it doesn’t and using that knowledge to build upon.

And in order to do that you need to take smaller bites and chew them till you can really swallow them.

We got the impression you try to swallow them whole and then feel the pain of being unable to digest it.

Learning and understanding should enable you to put the well understood building blocks together into something new.
Just rebuilding what someone else has done or shown in a video does not really teach you a lot.

Let me ask a very stupid question, since I’m on a roll here, I know C coding is used in my project, but what is the name of the basic type of coding used with the Particle devices? If I wanted to look into videos/tutorials, etc…where does one begin?

I’m confused by this question :confused:

You ā€œknowā€ you’ve used C (it’s a programming language not a coding style) on a Particle device but yet you ask what is used on Particles?

It is basically C (or C++) but with some framework (Wiring - also basis for Arduino code) in place that hides some of the otherwise required stuff from you and gives you standard functions to start from (setup() and loop()).

But it seems your problem is not (yet) the language but rather the basic building blocks for any programming language like variable types, functions, parameters.
And for getting these I usually recommend the very fundamental videos of Harward Open University CS50
https://www.youtube.com/watch?v=zFenJJtAEzE&list=PLhQjrBD2T383Xfn0zECHrOTpfOSlptPAB

There are hours to watch, but once you are through them you should have a more stable basis for tackling C

Thank you @ScruffR, you answered my question perfectly!

I’m sure you guys are excited to see me back. I haven’t changed anything in my code since my last post and I’m trying to resolve some issues on my own here.

I’m retaining the variables in my code with a thumb cell, if I remove that thumb cell so it doesn’t retain those variables, does that create a risk for fragmentation with the memory?

@james211, removing the cell will simply cause the reset of the variables in retained RAM. Think of it as starting with a new ā€œcleanā€ Photon. Fragmentation only occurs when you have dynamic RAM allocation (eg. using Strings a lot). For your retained variables, this is not the case.

1 Like

Thank you, that’s the answer I was hoping for.

1 Like

Is there a way to clear the variables, the same as removing the battery, without removing the battery?

Just set them to 0?

1 Like

I thought about that, wasn’t sure if that was the best option. Thank you.

@james211, you can use or extend an existing Particle.function() to have a ā€œresetā€ command for your retained variables to a set of default values.

Got it! I’ll consider that, but I’m not sure its completely necessary, it was just a question.

I had a thought after reading a horror story recently about dosers, and I’m not even sure how this would work generally speaking. So I’m curious about feedback. Basically there was a story of a guy who had a doser, like what I’m building, from a Chinese company that accidentally dumped an entire container of alkaline supplement into his aquarium and killed all of his coral. With that in mind, does anyone have any ideas on any type of safety that could be implemented to prevent that?

@james211, how are your pumps controlled?