Skip to content

Commit

Permalink
🗂 refactor & cleanup of loop() tasks, psu logging
Browse files Browse the repository at this point in the history
- measure/update-state/adjust are all moved to functions
- PSU gets better log calls
- updatePSU function gets time profiling when in debug
  • Loading branch information
t413 committed Jul 23, 2020
1 parent dcf43c0 commit ee17d87
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 92 deletions.
23 changes: 12 additions & 11 deletions lib/MPPTLib/powerSupplies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ bool Drok::doUpdate() {
if (res && !limitVolt_) {
handleReply(cmdReply("arc")); //read current limit
handleReply(cmdReply("arv")); //read voltage limit
log(str("finished PSU begin, got %0.3fV %0.3fA limits\n", limitVolt_, limitCurr_));
log(getType() + str(" finished begin, got %0.3fV %0.3fA limits\n", limitVolt_, limitCurr_));
}
return res;
}
Expand All @@ -86,7 +86,7 @@ bool Drok::handleReply(const String &msg) {
setCheck(outCurr_, body.toFloat() / 100.0, 15);
doTotals();
} else {
log("PSU got unknown msg > '" + hdr + "' / '" + body + "'");
log(getType() + " got unknown msg > '" + hdr + "' / '" + body + "'");
return false;
}
lastSuccess_ = millis();
Expand All @@ -99,21 +99,22 @@ void Drok::flush() {

String Drok::cmdReply(const String &cmd) {
port_->print(cmd + "\r\n");
if (debug_) log("PSU > " + cmd + "CRLF");
String tolog;
if (debug_) tolog += " > '" + cmd + "CRLF'";
String reply;
uint32_t start = millis();
char c;
while ((millis() - start) < 1000 && !reply.endsWith("\n"))
if (port_->readBytes(&c, 1))
reply.concat(c);
if (debug_ && reply.length()) {
String debug = reply;
debug.replace("\r", "CR");
debug.replace("\n", "NL");
log("PSU < " + debug);
tolog += " < '" + reply + "'";
tolog.replace("\r", "CR");
tolog.replace("\n", "NL");
log(getType() + tolog);
}
if (!reply.length() && debug_ && port_->available())
log("PSU nothing read.. stuff available!? " + String(port_->available()));
log(getType() + " nothing read.. stuff available!? " + String(port_->available()));
reply.trim();
return reply;
}
Expand Down Expand Up @@ -174,11 +175,11 @@ bool DPS::doUpdate() {
doTotals();
lastSuccess_ = millis();
return true;
}
} else log(getType() + " error fetching registers");
} catch (std::runtime_error e) {
log("caught exception in DPS::update " + String(e.what()));
log(getType() + " caught exception in DPS::update " + String(e.what()));
} catch (...) {
log("caught unknown exception in DPS::update");
log(getType() + " caught unknown exception in DPS::update");
}
return false;
}
Expand Down
172 changes: 92 additions & 80 deletions lib/MPPTLib/solar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,12 @@ bool Solar::hasCollapsed() const {
int Solar::getCollapses() const { return collapses_.size(); }

bool Solar::updatePSU() {
uint32_t start = millis();
if (psu_ && psu_->doUpdate()) {
pub_.setDirty({"outvolt", "outcurr", "outputEN", "outpower", "currFilt"});
if (psu_->wh_ > 2.0 || (millis() - lastConnected_) > 60000)
pub_.setDirty("wh"); //don't publish for a while after reboot
if (psu_->debug_) log(psu_->getType() + str(" updated in %d ms: ", millis() - start) + psu_->toString());
return true;
}
return false;
Expand Down Expand Up @@ -359,93 +361,97 @@ void Solar::restoreFromCollapse(float restoreCurrent) {
psu_->enableOutput(true);
}

void Solar::loop() {
uint32_t now = millis();
float newDesiredCurr = psu_->limitCurr_;
if (doOTAUpdate_.length())
return delay(100);

if (now > nextVmeas_ || now > nextSolarAdjust_) {
measureInvolt();

if (state_ == States::sweeping) {
doSweepStep();
} else if (setpoint_ > 0 && psu_ && psu_->outEn_) { //corrections enabled
double error = inVolt_ - setpoint_;
double dcurr = constrain(error * pgain_, -ramplimit_ * 2, ramplimit_); //limit ramping speed
if (error > 0.3 || (-error > 0.2)) { //adjustment deadband, more sensitive when needing to ramp down
newDesiredCurr = min(psu_->limitCurr_ + dcurr, currentCap_);
if ((error < 0.6) && (state_ == States::mppt)) { //ramp down, quick!
pub_.logNote("[QUICK]");
nextSolarAdjust_ = now;
}
float Solar::doMeasure() {
measureInvolt();
if (state_ == States::sweeping) {
doSweepStep();
} else if (setpoint_ > 0 && psu_ && psu_->outEn_) { //corrections enabled
double error = inVolt_ - setpoint_;
double dcurr = constrain(error * pgain_, -ramplimit_ * 2, ramplimit_); //limit ramping speed
if (error > 0.3 || (-error > 0.2)) { //adjustment deadband, more sensitive when needing to ramp down
if ((error < 0.6) && (state_ == States::mppt)) { //ramp down, quick!
pub_.logNote("[QUICK]");
nextSolarAdjust_ = millis();
}
return min(psu_->limitCurr_ + dcurr, currentCap_);
}
}
return psu_? psu_->limitCurr_ : 0;
}

//update system states:
if (!psu_) {
setState(States::error);
} else if (state_ != States::sweeping && state_ != States::collapsemode) {
int lastPSUsecs = (millis() - psu_->lastSuccess_) / 1000;
if (psu_->outEn_) {
if (lastPSUsecs > 11) setState(States::error, "enabled but no PSU comms");
else if (psu_->outCurr_ > (currentCap_ * 0.95 )) setState(States::capped);
else if (psu_->isCV()) setState(States::full_cv);
else setState(States::mppt);
} else { //disabled
if ((inVolt_ > 1) && lastPSUsecs > 120) //psu active at least every 2m when shut down
setState(States::error, "inactive PSU");
else setState(States::off);
}
if ((inVolt_ > 1) && (lastPSUsecs > 5 * 60)) {
log("VERY UNRESPONSIVE PSU, RESTARTING");
nextPub_ = now;
delay(1000);
ESP.restart();
}
void Solar::doUpdateState() {
if (!psu_) {
setState(States::error);
} else if (state_ != States::sweeping && state_ != States::collapsemode) {
int lastPSUsecs = (millis() - psu_->lastSuccess_) / 1000;
if (psu_->outEn_) {
if (lastPSUsecs > 11) setState(States::error, "enabled but no PSU comms");
else if (psu_->outCurr_ > (currentCap_ * 0.95 )) setState(States::capped);
else if (psu_->isCV()) setState(States::full_cv);
else setState(States::mppt);
} else { //disabled
if ((inVolt_ > 1) && lastPSUsecs > 120) //psu active at least every 2m when shut down
setState(States::error, "inactive PSU");
else setState(States::off);
}
nextVmeas_ = now + ((state_ == States::sweeping)? measperiod_ * 4 : measperiod_);
}
}

if (now > nextSolarAdjust_) {
try {
if (state_ == States::error) {
if (psu_ && (now - psu_->lastSuccess_) < 30000) { //for 30s after failure try and shut it down
psu_->enableOutput(false);
psu_->setCurrent(0);
throw Backoff("PSU failure, disabling");
}
} else if (setpoint_ > 0 && (state_ != States::sweeping)) {
if (hasCollapsed() && state_ != States::collapsemode) {
collapses_.push_back(now);
pub_.setDirty("collapses");
log(str("collapsed! %0.2fV ", inVolt_) + psu_->toString());
restoreFromCollapse(psu_->currFilt_ * 0.95); //restore at 90% of previous point
} else if (psu_ && !psu_->outEn_) { //power supply is off. let's check about turning it on
if (inVolt_ < psu_->outVolt_ || psu_->outVolt_ < 0.1) {
throw Backoff("not starting up, input voltage too low (is it dark?)");
} else if ((psu_->outVolt_ > psu_->limitVolt_) || (psu_->outVolt_ < (psu_->limitVolt_ * 0.60) && psu_->outVolt_ > 1)) {
//li-ion 4.1-2.5 is 60% of range. the last && condition allows system to work with battery drain diode in place
throw Backoff(str("not starting up, battery %0.1fV too far from Supply limit %0.1fV. ", psu_->outVolt_, psu_->limitVolt_) +
"Use outvolt command (or PSU buttons) to set your appropiate battery voltage and restart");
} else {
log("restoring from collapse");
psu_->enableOutput(true);
}
}
if (psu_ && psu_->outEn_ && state_ != States::collapsemode) {
applyAdjustment(newDesiredCurr);
void Solar::doAdjust(float desired) {
uint32_t now = millis();
try {
if (state_ == States::error) {
if (psu_ && (now - psu_->lastSuccess_) < 30000) { //for 30s after failure try and shut it down
psu_->enableOutput(false);
psu_->setCurrent(0);
throw Backoff("PSU failure, disabling");
}
} else if (setpoint_ > 0 && (state_ != States::sweeping)) {
if (hasCollapsed() && state_ != States::collapsemode) {
collapses_.push_back(now);
pub_.setDirty("collapses");
log(str("collapsed! %0.2fV ", inVolt_) + psu_->toString());
restoreFromCollapse(psu_->currFilt_ * 0.95); //restore at 90% of previous point
} else if (psu_ && !psu_->outEn_) { //power supply is off. let's check about turning it on
if (inVolt_ < psu_->outVolt_ || psu_->outVolt_ < 0.1) {
throw Backoff("not starting up, input voltage too low (is it dark?)");
} else if ((psu_->outVolt_ > psu_->limitVolt_) || (psu_->outVolt_ < (psu_->limitVolt_ * 0.60) && psu_->outVolt_ > 1)) {
//li-ion 4.1-2.5 is 60% of range. the last && condition allows system to work with battery drain diode in place
throw Backoff(str("not starting up, battery %0.1fV too far from Supply limit %0.1fV. ", psu_->outVolt_, psu_->limitVolt_) +
"Use outvolt command (or PSU buttons) to set your appropiate battery voltage and restart");
} else {
log("restoring from collapse");
psu_->enableOutput(true);
}
}
backoffLevel_ = max(backoffLevel_ - 1, 0); //successes means less backoff
} catch (const Backoff &b) {
backoffLevel_ = min(backoffLevel_ + 1, 8);
log(str("backoff now at %ds: ", getBackoff(adjustPeriod_) / 1000) + String(b.what()));
}
if (collapses_.size() && (millis() - collapses_.front()) > (5 * 60000)) { //5m age
pub_.logNote(str("[clear collapse (%ds ago)]", (now - collapses_.pop_front())/1000));
pub_.setDirty("collapses");
if (psu_ && psu_->outEn_ && state_ != States::collapsemode) {
applyAdjustment(desired);
}
}
backoffLevel_ = max(backoffLevel_ - 1, 0); //successes means less backoff
} catch (const Backoff &b) {
backoffLevel_ = min(backoffLevel_ + 1, 8);
log(str("backoff now at %ds: ", getBackoff(adjustPeriod_) / 1000) + String(b.what()));
}
if (collapses_.size() && (millis() - collapses_.front()) > (5 * 60000)) { //5m age
pub_.logNote(str("[clear collapse (%ds ago)]", (now - collapses_.pop_front())/1000));
pub_.setDirty("collapses");
}
}

void Solar::loop() {
uint32_t now = millis();
if (doOTAUpdate_.length())
return delay(100);

if (now > nextVmeas_) {
doMeasure(); //may set nextSolarAdjust sooner
doUpdateState();
nextVmeas_ = now + ((state_ == States::sweeping)? measperiod_ * 2 : measperiod_);
}

if (now > nextSolarAdjust_) {
doAdjust(doMeasure());
heap_caps_check_integrity_all(true);
nextSolarAdjust_ = now + getBackoff(adjustPeriod_);
}
Expand All @@ -460,6 +466,12 @@ void Solar::loop() {
log("psu update fail" + String(psu_->debug_? " serial debug output enabled" : ""));
psu_->begin(); //try and reconnect
}
if ((inVolt_ > 1) && ((millis() - psu_->lastSuccess_) > 5 * 60 * 1000)) { //5m
log("VERY UNRESPONSIVE PSU, RESTARTING");
nextPub_ = now;
delay(1000);
ESP.restart();
}
nextPSUpdate_ = now + min(getBackoff(5000), 100000); //100s
}

Expand Down Expand Up @@ -524,7 +536,7 @@ void Solar::publishTask() {
while (doOTAUpdate_ == " ") //stops this task while an upload-OTA is running
delay(1000);
if (doOTAUpdate_.length()) {
doUpdate(doOTAUpdate_);
doOTA(doOTAUpdate_);
doOTAUpdate_ = "";
}
if (db_.client.connected()) {
Expand Down Expand Up @@ -581,7 +593,7 @@ String DBConnection::getEndpoint() const {
return (sep >= 0)? serv.substring(0, sep) : serv;
}

void Solar::doUpdate(String url) {
void Solar::doOTA(String url) {
log("[OTA] running from " + url);
sendOutgoingLogs(); //send any outstanding log() messages
db_.client.disconnect(); //helps to disconnect everything
Expand Down
6 changes: 5 additions & 1 deletion lib/MPPTLib/solar.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class Solar {
String setPSU(String);

void loop();
float doMeasure();
void doUpdateState();
void doAdjust(float desired);

bool updatePSU();
float measureInvolt();
void sendOutgoingLogs();
Expand All @@ -42,7 +46,7 @@ class Solar {
bool hasCollapsed() const;
int getCollapses() const;
void restoreFromCollapse(float restoreCurrent);
void doUpdate(String url);
void doOTA(String url);

int getBackoff(int period) const;
void setState(const String state, String reason="");
Expand Down

0 comments on commit ee17d87

Please sign in to comment.