As you know, the IBC totes are vented at the top, which allows air to enter the tanks when liquid leaves.
You will need to maintain a Vent Path if you plan to use the 2" port in the Center of the Screw Cap for your instrumentation.
You might be able to use a PVC distributor in some way for this, IDK ?
I agree with @seulater, the industry has moved to radar for this "severe-duty" chemical application.
Radar is hard to justify for every IBC tote, so I hope you are successful with a cheaper alternative.
Rftop - I read I think that same chart. I need to check the acid concentrations and if need be change to HDPE. I found it interesting that concentration of hydrochloric was worse than the middle concentration.
Hello @Ric, I am curious about the OneShot utility you have at the top of your code. Is it something you wrote, or can you point me to a link? I have not been able to find it on this forum or the user docs.
Yes, that is something I wrote. I have a file called Extras where I put some utility methods. It has a couple of simple timers and a method to take care daylight savings time. Here’s the code for the .h file
#include "Particle.h"
void setZone();
enum Unit {
MILLIS, SECONDS, MINUTES
};
class Wait {
public:
Wait(unsigned long period, enum Unit unitOfTime);
void begin();
bool isUp(void);
void reset();
private:
unsigned long start;
unsigned long waitTime = 0;
};
class OneShot {
public:
OneShot(int hour, int minute);
bool fired(void);
void cancel();
//private:
int timeToFire;
int weekdayToFire;
};
Here is the .cpp file,
#include "Extras.h"
#include "Particle.h"
void setZone() {
int month = Time.month();
int day = Time.day();
int weekday = Time.weekday();
int previousSunday = day - weekday + 1;
if (month < 3 || month > 11) {
Time.zone(-8);
}else if (month > 3 && month < 11) {
Time.zone(-7);
}else if (month == 3) {
int offset = (previousSunday >= 8)? -7 : -8;
Time.zone(offset);
} else{
int offset = (previousSunday <= 0)? -7 : -8;
Time.zone(offset);
}
}
Wait::Wait(unsigned long period, enum Unit unitOfTime) {
unsigned long multiplier;
switch (unitOfTime) {
case MILLIS:
multiplier = 1;
break;
case SECONDS:
multiplier = 1000;
break;
case MINUTES:
multiplier = 60000;
break;
}
waitTime = period * multiplier;
}
void Wait::begin() {
start = millis();
}
bool Wait::isUp() {
if (millis() - start >= waitTime) {
start = millis();
return true;
}else{
return false;
}
}
void Wait::reset() {
start = millis();
}
OneShot::OneShot(int hour, int minute) { // timer for once a day events
setZone();
timeToFire = hour * 60 + minute;
if (timeToFire < (Time.hour() * 60 + Time.minute())) {
weekdayToFire = (Time.weekday() % 7) + 1;
}else{
weekdayToFire = Time.weekday();
}
}
bool OneShot::fired() {
int theTime = Time.hour() * 60 + Time.minute();
if (theTime >= timeToFire && weekdayToFire == Time.weekday()) {
weekdayToFire = (weekdayToFire % 7) + 1; // setup for the next day to run again
return true;
}else{
return false;
}
}
Thanks for sharing, @Ric . I am looking for a simple scheduler that works with time of day, so I don’t have to count millis or create crazy data structures.
I am going to show my lack of programming skills, so how would I modify the OneShot object without reflashing the FW? IOW: I want to change a timer from an external input (e.g., Particle.function), say from 6AM to 7AM.
Looks like I could make a new method to reach into the timer definition to change the variable timeToFire, but I don’t understand if the scope of this variable includes the main loop() function.