Reef-pi doser stuck on... Bad Day

Ranjib

7500 Club Member
View Badges
Joined
Apr 16, 2016
Messages
9,843
Reaction score
17,056
Location
Pleasant Hill, Concord
Rating - 0%
0   0   0
Rebooting PI fixed the multiple dose triggers. Very odd how that happened. I was experimenting with some POST commands to modify the dose duration based on PH (new feature suggest?) so this is the only cause I can think of.
If the duration is longer than the ph check interval then that can cause multiple triggers to be in flight, as the previous might not finish before the next one triggers
 

ReeferLou

Active Member
View Badges
Joined
Dec 24, 2020
Messages
193
Reaction score
151
Location
Michigan-Oakland County
Rating - 0%
0   0   0
If the duration is longer than the ph check interval then that can cause multiple triggers to be in flight, as the previous might not finish before the next one triggers
I was using the API GET command for the PH check and only checking every 30 min with a CRON python script and limiting the update to 1 per 20hrs. I think I may have written some bad DOSER entires as I was debugging how to modify - But without a way to see the CRON-GO table I was not sure since they did not show in the UI.
 

trustychords

New Member
View Badges
Joined
Aug 17, 2019
Messages
23
Reaction score
28
Location
Virginia, USA
Rating - 0%
0   0   0
This is a known issue with Reef-Pi. Using the "Doser" tab is risky because, seemingly randomly, it won't shut off (at least with pca9685, which many people use for dosing pumps). See another instance of this here: https://www.reef2reef.com/threads/r...-on-raspberry-pi.289256/page-883#post-9584971

The work around is to use the dosing pump on a timer rather than through the doser tab. I do wish that Reef-Pi would either get rid of the doser tab (or at least put a "caution" statement when using pca9685) since it is unreliable or fix this known issue.
 

Uncle99

7500 Club Member
View Badges
Joined
Jul 22, 2018
Messages
8,959
Reaction score
13,168
Location
Province of Ontario
Rating - 0%
0   0   0
Dumped about 3/4 gallon of bicarb in my 13.5 gallon reef. First issue I have had with equipment failure so not sure how to approach this. Finally got alkalinity down to around 20 but I am thinking about when I eventually turn the system back online what should I do to prevent this happening again? I ran a calibration and the doser seemed to turn off just fine so not sure what happened...
I don’t keep any more than 7 days dose in the jars.
Fill once a week.
May mitigate a failure.
 

robsworld78

Well-Known Member
View Badges
Joined
Feb 14, 2020
Messages
952
Reaction score
1,281
Location
Edmonton, Canada
Rating - 0%
0   0   0
Recently I came up with a solution for this on another project, soon I was going to PM Ranjib but maybe someone else can make the update as it's not very difficult if you know GO. Unfortunately I'm unable to as I barely get by on c++ but I've updated the functions below to give the idea. To be honest I2C is the only thing that keeps me up at night, it just can't be trusted in most cases. Once I got this working a major load was lifted knowing it can be done as my controller uses pca9685 on DC ports and PWM ports. So yeah if someone can migrate this to reef-pi that would be amazing.

The idea is simple, it requires a basic function to get the PWM value and the global function to set the PCA9685 is modified. Like this all systems are covered. Any time a new value is sent to the PCA9685 it immediately reads back that pin to get the value. Then it compares the value sent to the value returned, if they match it was updated, if not the loop will continue to try up to 50 times which is overkill. This is so there's no infinite loop. If it ever did error out then there's serious issues.

The changes need to be made in the pca9685.go file in the drivers section, this is the file I'm referring to.


Here's the function that needs to be added, I called it GetPwmLevel. The channel number being adjusted is sent to it. The first half is my poor attempt to convert to GO, the 2nd half after the dash lines is c++ as the example.

Code:
func (p *PCA9685) GetPwmLevel(channel int) error {  // Get PWM value for select pin from PCA9685
    // need to write only the first line when you set PWM value, then read 4 bytes
    timeReg := byte(pwm0OnLowReg + (4 * channel))  // you can see below my line is slightly different but I think this will work.

    if err := p.bus.WriteToReg(p.addr, timeReg); err != nil {  // this needs fixed I'm sure
        return err
    }
    read(pca9685I2Cfile[driverLoc], inData, 4);  // need to read 4 bytes, 2nd byte holds the PWM value, need to update for GO.

    return inData[1];  // return PWM level

    // ----------------------------------------------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------------------------------------------
    // C++ working example - Above needs to do this
    char buffer[1];
    buffer[0] = pwm0OnLowReg + (channel << 2);  // send channel number request - updated variable names to match reef-pi
    write(pca9685I2Cfile[driverLoc], buffer, 1);  // write
  
    uint16_t inData[4];  // store incoming data
    int length = 4;  // number of bytes to read
    if (read(pca9685I2Cfile[driverLoc], inData, 4) != length) {  // must read 4 bytes
        std::cout << "Failed to read from the i2c bus - getPWM." << std::endl;
        return -1;
    }

    return inData[1];  // return PWM level
}

Below is the function that already exists, SetPwm, this needs to be modified.

The first half of the function is the original and stays as is except for the last return line as we don't want to exit the function yet. A return will be needed at the end so reef-pi gets what it wants.

The 2nd half of the function under the dash lines is the addition, it's just a while loop that compares value sent to returned value when it runs the GetPwmLevel function. If it matches it moves on otherwise it repeats. I marked lines with NEED TO UPDATE that need converting to GO.

Code:
func (p *PCA9685) SetPwm(channel int, onTime, offTime uint16) error {
    log.Println("onTime ", onTime, " offTime ", offTime)
    // Split the ints into 4 bytes
    timeReg := byte(pwm0OnLowReg + (4 * channel))
    onTimeLow := byte(onTime & 0xFF)
    onTimeHigh := byte(onTime >> 8)
    offTimeLow := byte(offTime & 0xFF)
    offTimeHigh := byte(offTime >> 8)

    //log.Println("onLow ", onTimeLow, " onHigh ", onTimeHigh, " offLow ", offTimeLow, " offHigh ", offTimeHigh)
    if err := p.bus.WriteToReg(p.addr, timeReg, []byte{onTimeLow}); err != nil {
        return err
    }
    if err := p.bus.WriteToReg(p.addr, timeReg+1, []byte{onTimeHigh}); err != nil {
        return err
    }
    if err := p.bus.WriteToReg(p.addr, timeReg+2, []byte{offTimeLow}); err != nil {
        return err
    }
    return p.bus.WriteToReg(p.addr, timeReg+3, []byte{offTimeHigh})  // NEED TO REMOVE RETURN at beginning and add something similar to end of function as we don't want to exit yet.


    // ----------------------------------------------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------------------------------------------
    // MOD TO CHECK PWM VALUE AFTER SENDING
    bool f = 0;  // flag to exit while loop  -- UPDATE FOR GO
    short r = 0;  // track how many times we retry updating pin, if over 50 consecutive fails we stop trying (this should never happen, just a method to exit so we don't have an infinite loop)
    while (f == 0)  // check if pca9685 received the signal until we get a match -- UPDATE FOR GO
    {
        if (GetPwmLevel(channel) == pwmValue) {f = 1;}  // check if PWM value just sent to PCA9685 matches what we just read  -- UPDATE FOR GO
        else {  // PWM values didn't match so we try again
            // std::cout << "TRY AGAIN                 - " << std::endl;
            log.Println("PCA9685 Didn't Update ", channel)  // log if you see fit
            f = 0;  // NEED TO UPDATE FOR GO
            r++;  // NEED TO UPDATE FOR GO
            timeReg := byte(pwm0OnLowReg + (4 * channel))
            onTimeLow := byte(onTime & 0xFF)
            onTimeHigh := byte(onTime >> 8)
            offTimeLow := byte(offTime & 0xFF)
            offTimeHigh := byte(offTime >> 8)
      
            //log.Println("onLow ", onTimeLow, " onHigh ", onTimeHigh, " offLow ", offTimeLow, " offHigh ", offTimeHigh)
            if err := p.bus.WriteToReg(p.addr, timeReg, []byte{onTimeLow}); err != nil {
                return err
            }
            if err := p.bus.WriteToReg(p.addr, timeReg+1, []byte{onTimeHigh}); err != nil {
                return err
            }
            if err := p.bus.WriteToReg(p.addr, timeReg+2, []byte{offTimeLow}); err != nil {
                return err
            }
            return p.bus.WriteToReg(p.addr, timeReg+3, []byte{offTimeHigh})

            delay(50)  // 50 millisecond delay -- UPDATE FOR GO
        }
        if (r > 48) break  // exit loop after 50 tries if it can't update - could add an alert here or logging -- UPDATE FOR GO
    }

    return what_reef-pi_requires
}

So yeah it's quite simple and I think a good solution. If more info is needed or you have a better idea let me know.
 
Last edited:

WhoIsCandice

Community Member
View Badges
Joined
Jul 11, 2021
Messages
36
Reaction score
16
Location
Concord, CA
Rating - 0%
0   0   0
This is somewhat of a hack but I was having a similar issue with a Raspberrry Pi 4 that would stop responding every other 3 days that was acting as a TorrentBox but over a VPN that way I wouldn't have to be always VPNd on my local machine.

Essentially what would happen was there was a bug with a raspberry-pi image where a memory-leak in a system daemon or some low-level service would cause the raspberry to stop responding after 3 days. I had to reflash a nonbuggy image in order to resolve this.

A hack that I ended up doing that *worked* before my ex-gf spilled water on that pi was to have a cron job just restart once a day.

That's my 2 cents right there IMO.
 

Being sticky and staying connected: Have you used any reef-safe glue?

  • I have used reef safe glue.

    Votes: 99 87.6%
  • I haven’t used reef safe glue, but plan to in the future.

    Votes: 6 5.3%
  • I have no interest in using reef safe glue.

    Votes: 5 4.4%
  • Other.

    Votes: 3 2.7%
Back
Top