Skip to content

Commit

Permalink
🐞 Optimizations, bug fixes, json output, progress %
Browse files Browse the repository at this point in the history
- No longer listens to mqtt pref values, use the ‘cmd’ topic
 * fixes issue of endless loop of self-get-set
- OTA upload update percentage reporting
- better update rate for DPS supplies
- new ‘Pub::jsonValue()’ method, Publishable class
   now will quote strings correctly
- Publishable class will now publish preference actions
- try/catch around Modbus actions
  • Loading branch information
t413 committed Jul 6, 2020
1 parent fd3b72d commit 767c222
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 46 deletions.
46 changes: 30 additions & 16 deletions lib/MPPTLib/powerSupplies.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "powerSupplies.h"
#include <Arduino.h>
#include <stdexcept>
#include <ModbusMaster.h> // ModbusMaster
#include "utils.h"

Expand Down Expand Up @@ -143,22 +143,29 @@ String DPS::getType() const { return "DPS"; }

bool DPS::begin() {
bus_->begin(1, *port_);
return doUpdate();
}

bool DPS::doUpdate() {
//read a range of 16-bit registers starting at register 0 to 10
if (bus_->readHoldingRegisters(0, 10) == bus_->ku8MBSuccess) {
outVolt_ = ((float)bus_->getResponseBuffer(2) / 100 );
outCurr_ = ((float)bus_->getResponseBuffer(3) / 1000 );
inputVolts_ = ((float)bus_->getResponseBuffer(5) / 100 );
// float power = ((float)bus_->getResponseBuffer(4) / 100 );
limitVolt_ = ((float)bus_->getResponseBuffer(0) / 100 );
limitCurr_ = ((float)bus_->getResponseBuffer(1) / 1000 );
outEn_ = ((bool)bus_->getResponseBuffer(9) );
cc_ = ((bool)bus_->getResponseBuffer(8) );
doTotals();
lastSuccess_ = millis();
return true;
try {
if (bus_->readHoldingRegisters(0, 10) == bus_->ku8MBSuccess) {
outVolt_ = ((float)bus_->getResponseBuffer(2) / 100 );
outCurr_ = ((float)bus_->getResponseBuffer(3) / 1000 );
inputVolts_ = ((float)bus_->getResponseBuffer(5) / 100 );
// float power = ((float)bus_->getResponseBuffer(4) / 100 );
limitVolt_ = ((float)bus_->getResponseBuffer(0) / 100 );
limitCurr_ = ((float)bus_->getResponseBuffer(1) / 1000 );
outEn_ = ((bool)bus_->getResponseBuffer(9) );
cc_ = ((bool)bus_->getResponseBuffer(8) );
doTotals();
lastSuccess_ = millis();
return true;
}
} catch (std::runtime_error e) {
log("caught exception in DPS::update " + String(e.what()));
} catch (...) {
log("caught unknown exception in DPS::update");
}
return false;
}
Expand All @@ -175,7 +182,14 @@ bool DPS::setCurrent(float c) {

bool DPS::isCC() const { return cc_; }

bool DPS::getInputVolt(float* v) const {
if (v) *v = inputVolts_;
return true;
bool DPS::getInputVolt(float* v) {
try {
if (bus_->readHoldingRegisters(5, 1) == bus_->ku8MBSuccess) {
inputVolts_ = ((float)bus_->getResponseBuffer(5) / 100 );
lastSuccess_ = millis();
if (v) *v = inputVolts_;
return true;
}
} catch (...) { log("caught unknown exception in DPS::update"); }
return true; //still return true because we _can_ read input voltage
}
4 changes: 2 additions & 2 deletions lib/MPPTLib/powerSupplies.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class PowerSupply {
virtual bool isCV() const;
virtual bool isCC() const;
virtual bool isCollapsed() const;
virtual bool getInputVolt(float* v) const { return false; }
virtual bool getInputVolt(float* v) { return false; }
virtual String toString() const;
virtual String getType() const = 0;
protected:
Expand Down Expand Up @@ -78,5 +78,5 @@ class DPS : public PowerSupply {
bool doUpdate() override; //runs these next three:

bool isCC() const override;
bool getInputVolt(float* v) const override;
bool getInputVolt(float* v) override;
};
16 changes: 11 additions & 5 deletions lib/MPPTLib/publishable.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "publishable.h"
#include "utils.h"
#include <WiFi.h>
#include <Arduino.h>
#include <Preferences.h>

template<typename T>
Expand All @@ -10,6 +9,7 @@ struct Pub : PubItem {
Pub(String k, T v, int p) : PubItem(k,p), value(v) { }
~Pub() { }
String toString() const override { return String(*value); }
String jsonValue() const override { return toString(); }
String set(String v) override { *value = v.toFloat(); return toString(); }
void const* val() const override { return value; }
void save(Preferences&p) override { p.putBytes(key.c_str(), value, sizeof(*value)); }
Expand All @@ -28,6 +28,7 @@ String prefGetString(Preferences&p, String key) {
template<> String Pub<double*>::toString() const { return String(*value, 3); }
template<> String Pub<bool* >::toString() const { return (*value)? "true":"false"; }
template<> String Pub<Action>::toString() const { return (value)(""); }
template<> String Pub<Action>::jsonValue() const { return "\"" + toString() + "\""; }
template<> String Pub<bool* >::set(String v) { (*value) = v=="on" || v=="true" || v=="1"; return toString(); }
template<> String Pub<Action>::set(String v) { return (value)(v); }
template<> void const* Pub<Action>::val() const { return &value; }
Expand All @@ -37,6 +38,7 @@ template<> void Pub<Action>::save(Preferences&p) { String v = (value)(""); p.put
template<> void Pub<Action>::load(Preferences&p) { String v = prefGetString(p, key); if (v.length()) try { (value)(v); } catch(...) { } }
template<> String Pub<String*>::set(String v) { return (*value) = v; }
template<> String Pub<String*>::toString() const { return (*value); }
template<> String Pub<String*>::jsonValue() const { return "\"" + toString() + "\""; }
template<> void Pub<String*>::save(Preferences&p) { p.putBytes(key.c_str(), value->c_str(), value->length()); }
template<> void Pub<String*>::load(Preferences&p) {
(*value) = prefGetString(p, key);
Expand Down Expand Up @@ -197,9 +199,13 @@ void Publishable::printHelp() const {
String Publishable::toJson() const {
String ret = "{\n";
for (const auto & i : items_)
if (!i.second->hidden_)
ret += " \"" + i.first + "\":" + i.second->toString() + ",\n";
if (items_.size())
ret.remove(ret.length() - 2, 2); //remove trailing comma + LF
if (!i.second->hidden_ && !i.second->pref_)
ret += " \"" + i.first + "\":" + i.second->jsonValue() + ",\n";
ret += "\"prefs\":{\n";
for (const auto & i : items_)
if (!i.second->hidden_ && i.second->pref_)
ret += " \"" + i.first + "\":" + i.second->jsonValue() + ",\n";
ret.remove(ret.length() - 2, 2); //remove trailing comma + LF
ret += " }\n";
return ret + "\n}\n";
}
5 changes: 4 additions & 1 deletion lib/MPPTLib/publishable.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#pragma once
#include <Arduino.h>
#include <WString.h>
#include <FreeRTOS.h>
#include <functional>
#include <map>
#include <list>
#include "utils.h"

class Stream;
class PubSubClient;
class WebServer;
class Preferences;
Expand All @@ -21,6 +23,7 @@ struct PubItem {
PubItem(String k, int p) : key(k), period(p), pref_(false), hidden_(false), dirty_(false) { }
virtual ~PubItem() { }
virtual String toString() const = 0;
virtual String jsonValue() const = 0;
virtual String set(String v) = 0;
virtual void const* val() const = 0;
virtual void save(Preferences&) = 0;
Expand Down
39 changes: 19 additions & 20 deletions lib/MPPTLib/solar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ uint32_t nextAutoSweep_ = 0, lastAutoSweep_ = 0;
double newDesiredCurr_ = 0;
extern const String updateIndex;
String doOTAUpdate_ = "";
uint32_t espSketchSize_ = 0;

class Backoff : public std::runtime_error { public:
Backoff(String s) : std::runtime_error(s.c_str()) { }
Expand All @@ -41,6 +42,7 @@ void Solar::setup() {
Serial.begin(115200);
Serial.setTimeout(10); //very fast, need to keep the ctrl loop running
addLogger(&pub_); //sets global context
espSketchSize_ = ESP.getSketchSize();
delay(100);
log(getResetReasons());
uint64_t chipid = ESP.getEfuseMac();
Expand Down Expand Up @@ -116,7 +118,7 @@ void Solar::setup() {
if (!Update.begin(UPDATE_SIZE_UNKNOWN))//start with max available size
Update.printError(Serial);
} else if (upload.status == UPLOAD_FILE_WRITE){
log(str("got write(size %d) at %d", upload.currentSize, Update.progress()));
log(str("OTA upload at %dKB ~%0.1%%%", Update.progress() / 1000, Update.progress() * 100 / espSketchSize_));
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize)
Update.printError(Serial);
} else if(upload.status == UPLOAD_FILE_END){
Expand Down Expand Up @@ -162,6 +164,8 @@ String Solar::setPSU(String s) {
if (s.startsWith("DP")) {
psu_.reset(new DPS(&Serial2));
Serial2.begin(9600, SERIAL_8N1, -1, -1, false, 1000);
if (measperiod_ == 200) //default
measperiod_ = 500;
} else { //default
psu_.reset(new Drok(&Serial2));
Serial2.begin(4800, SERIAL_8N1, -1, -1, false, 1000);
Expand All @@ -185,6 +189,7 @@ void Solar::doConnect() {
MDNS.begin("mppt");
MDNS.addService("http", "tcp", 80);
server_.begin();
lastConnected_ = millis();
}
} else log("no wifiap or wifipass set!");
}
Expand All @@ -194,13 +199,10 @@ void Solar::doConnect() {
db_.client.setServer(db_.getEndpoint().c_str(), db_.getPort());
if (db_.client.connect("MPPT", db_.user.c_str(), db_.pass.c_str())) {
log("PubSub connect success! " + db_.client.state());
auto pubs = pub_.items(true);
for (auto i : pubs)
if (i->pref_)
db_.client.subscribe((db_.feed + "/prefs/" + i->key).c_str()); //subscribe to preference changes
db_.client.subscribe((db_.feed + "/cmd").c_str()); //subscribe to cmd topic for any actions
lastConnected_ = millis();
} else pub_.logNote("[PubSub connect ERROR]" + db_.client.state());
} else pub_.logNote("[no MQTT user / pass / server / feed set up]");
} else pub_.logNote("[no MQTT user/pass/serv/feed set up]");
} else pub_.logNote(str("[can't pub connect, wifi %d pub %d]", WiFi.isConnected(), db_.client.connected()));
}

Expand Down Expand Up @@ -317,7 +319,10 @@ void Solar::loop() {
return delay(100);

if (now > nextVmeas_) {
if (!psu_->getInputVolt(&inVolt_)) {
if (psu_->getInputVolt(&inVolt_)) {
psu_->doUpdate();
psu_->getInputVolt(&inVolt_);
} else {
int analogval = analogRead(pinInvolt_);
inVolt_ = analogval * 3.3 * (vadjust_ / 3.3) / 4096.0;
}
Expand Down Expand Up @@ -412,7 +417,7 @@ void Solar::loop() {
bool res = psu_->doUpdate();
if (res) {
pub_.setDirty({"outvolt", "outcurr", "outputEN", "outpower", "currFilt"});
if (millis() > ignoreSubsUntil_) pub_.setDirty("wh"); //don't publish at first
if (psu_->wh_ > 2.0 || (millis() - lastConnected_) > 60000) pub_.setDirty("wh"); //don't publish at first
} else {
log("psu update fail" + String(psu_->debug_? " serial debug output enabled" : ""));
psu_->begin(); //try and reconnect
Expand Down Expand Up @@ -459,21 +464,17 @@ void Solar::sendOutgoingLogs() {
void Solar::publishTask() {
doConnect();
db_.client.loop();
ignoreSubsUntil_ = millis() + 10000;
db_.client.setCallback([=](char*topicbuf, uint8_t*buf, unsigned int len){
String topic(topicbuf), val = str(std::string((char*)buf, len));
log("got sub value " + topic + " -> " + val);
if (topic == (db_.feed + "/wh")) {
psu_->wh_ = (millis() > ignoreSubsUntil_)? val.toFloat() : psu_->wh_ + val.toFloat();
psu_->wh_ = (psu_->wh_ > 2.0)? val.toFloat() : psu_->wh_ + val.toFloat();
log("restored wh value to " + val);
db_.client.unsubscribe((db_.feed + "/wh").c_str());
} else if (millis() > ignoreSubsUntil_) { //don't load old values
if (topic == db_.feed + "/cmd") {
log("MQTT cmd " + topic + ":" + val + " -> " + pub_.handleCmd(val));
} else {
topic.replace(db_.feed + "/prefs/", ""); //replaces in-place, sadly
log("MQTT cmd " + topic + ":" + val + " -> " + pub_.handleSet(topic, val));
}
} else if (topic == db_.feed + "/cmd") {
log("MQTT cmd " + topic + ":" + val + " -> " + pub_.handleCmd(val));
} else {
log("MQTT unknown message " + topic + ":" + val);
}
});
db_.client.subscribe((db_.feed + "/wh").c_str());
Expand All @@ -490,10 +491,8 @@ void Solar::publishTask() {
if (db_.client.connected()) {
int wins = 0;
auto pubs = pub_.items(true);
for (auto i : pubs) {
for (auto i : pubs)
wins += db_.client.publish((db_.feed + "/" + (i->pref_? "prefs/":"") + i->key).c_str(), i->toString().c_str(), true)? 1 : 0;
if (i->pref_) ignoreSubsUntil_ = now + 3000;
}
pub_.logNote(str("[pub-%d]", wins));
pub_.clearDirty();
} else {
Expand Down
4 changes: 2 additions & 2 deletions lib/MPPTLib/solar.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include <Arduino.h>
#include "publishable.h"
#include <WString.h>
#include <PubSubClient.h>
#include <WebServer.h>

Expand Down Expand Up @@ -56,7 +56,7 @@ class Solar {
float vadjust_ = 116.50;
CircularArray<SPoint, 10> sweepPoints_; //size here is important, larger == more stable setpoint
String wifiap, wifipass;
uint32_t ignoreSubsUntil_ = 0;
uint32_t lastConnected_ = 0;
int8_t backoffLevel_ = 0;
std::unique_ptr<LowVoltageProtect> lvProtect_;

Expand Down

0 comments on commit 767c222

Please sign in to comment.