mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-03 20:25:54 +02:00
fix wrong filename for automatically created manifest (online installer) #620
added rotate display feature #619 improved Prometheus endpoint #615, thx to fsck-block
This commit is contained in:
parent
2610f1adfb
commit
22ae6d2e22
8 changed files with 78 additions and 21 deletions
|
@ -36,13 +36,13 @@ def buildManifest(path, infile, outfile):
|
||||||
esp32["parts"].append({"path": "bootloader.bin", "offset": 4096})
|
esp32["parts"].append({"path": "bootloader.bin", "offset": 4096})
|
||||||
esp32["parts"].append({"path": "partitions.bin", "offset": 32768})
|
esp32["parts"].append({"path": "partitions.bin", "offset": 32768})
|
||||||
esp32["parts"].append({"path": "ota.bin", "offset": 57344})
|
esp32["parts"].append({"path": "ota.bin", "offset": 57344})
|
||||||
esp32["parts"].append({"path": version[1] + "_esp32_" + sha + ".bin", "offset": 65536})
|
esp32["parts"].append({"path": version[1] + "_" + sha + "_esp32.bin", "offset": 65536})
|
||||||
data["builds"].append(esp32)
|
data["builds"].append(esp32)
|
||||||
|
|
||||||
esp8266 = {}
|
esp8266 = {}
|
||||||
esp8266["chipFamily"] = "ESP8266"
|
esp8266["chipFamily"] = "ESP8266"
|
||||||
esp8266["parts"] = []
|
esp8266["parts"] = []
|
||||||
esp8266["parts"].append({"path": version[1] + "_esp8266_" + sha + ".bin", "offset": 0})
|
esp8266["parts"].append({"path": version[1] + "_" + sha + "_esp8266.bin", "offset": 0})
|
||||||
data["builds"].append(esp8266)
|
data["builds"].append(esp8266)
|
||||||
|
|
||||||
jsonString = json.dumps(data, indent=2)
|
jsonString = json.dumps(data, indent=2)
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
(starting from release version `0.5.66`)
|
(starting from release version `0.5.66`)
|
||||||
|
|
||||||
|
## 0.5.77
|
||||||
|
* fix wrong filename for automatically created manifest (online installer) #620
|
||||||
|
* added rotate display feature #619
|
||||||
|
* improved Prometheus endpoint #615, thx to fsck-block
|
||||||
|
|
||||||
## 0.5.76
|
## 0.5.76
|
||||||
* reduce MQTT retry interval from maximum speed to one second
|
* reduce MQTT retry interval from maximum speed to one second
|
||||||
* fixed homeassistant autodiscovery #565
|
* fixed homeassistant autodiscovery #565
|
||||||
|
|
|
@ -122,6 +122,7 @@ typedef struct {
|
||||||
bool pwrSaveAtIvOffline;
|
bool pwrSaveAtIvOffline;
|
||||||
bool logoEn;
|
bool logoEn;
|
||||||
bool pxShift;
|
bool pxShift;
|
||||||
|
bool rot180;
|
||||||
uint16_t wakeUp;
|
uint16_t wakeUp;
|
||||||
uint16_t sleepAt;
|
uint16_t sleepAt;
|
||||||
uint8_t contrast;
|
uint8_t contrast;
|
||||||
|
@ -340,6 +341,7 @@ class settings {
|
||||||
mCfg.plugin.display.contrast = 60;
|
mCfg.plugin.display.contrast = 60;
|
||||||
mCfg.plugin.display.logoEn = true;
|
mCfg.plugin.display.logoEn = true;
|
||||||
mCfg.plugin.display.pxShift = true;
|
mCfg.plugin.display.pxShift = true;
|
||||||
|
mCfg.plugin.display.rot180 = false;
|
||||||
mCfg.plugin.display.pin0 = DEF_PIN_OFF; // SCL
|
mCfg.plugin.display.pin0 = DEF_PIN_OFF; // SCL
|
||||||
mCfg.plugin.display.pin1 = DEF_PIN_OFF; // SDA
|
mCfg.plugin.display.pin1 = DEF_PIN_OFF; // SDA
|
||||||
}
|
}
|
||||||
|
@ -471,6 +473,7 @@ class settings {
|
||||||
disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline;
|
disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline;
|
||||||
disp[F("logo")] = (bool)mCfg.plugin.display.logoEn;
|
disp[F("logo")] = (bool)mCfg.plugin.display.logoEn;
|
||||||
disp[F("pxShift")] = (bool)mCfg.plugin.display.pxShift;
|
disp[F("pxShift")] = (bool)mCfg.plugin.display.pxShift;
|
||||||
|
disp[F("rot180")] = (bool)mCfg.plugin.display.rot180;
|
||||||
disp[F("wake")] = mCfg.plugin.display.wakeUp;
|
disp[F("wake")] = mCfg.plugin.display.wakeUp;
|
||||||
disp[F("sleep")] = mCfg.plugin.display.sleepAt;
|
disp[F("sleep")] = mCfg.plugin.display.sleepAt;
|
||||||
disp[F("contrast")] = mCfg.plugin.display.contrast;
|
disp[F("contrast")] = mCfg.plugin.display.contrast;
|
||||||
|
@ -482,6 +485,7 @@ class settings {
|
||||||
mCfg.plugin.display.pwrSaveAtIvOffline = (bool) disp[F("pwrSafe")];
|
mCfg.plugin.display.pwrSaveAtIvOffline = (bool) disp[F("pwrSafe")];
|
||||||
mCfg.plugin.display.logoEn = (bool) disp[F("logo")];
|
mCfg.plugin.display.logoEn = (bool) disp[F("logo")];
|
||||||
mCfg.plugin.display.pxShift = (bool) disp[F("pxShift")];
|
mCfg.plugin.display.pxShift = (bool) disp[F("pxShift")];
|
||||||
|
mCfg.plugin.display.rot180 = (bool) disp[F("rot180")];
|
||||||
mCfg.plugin.display.wakeUp = disp[F("wake")];
|
mCfg.plugin.display.wakeUp = disp[F("wake")];
|
||||||
mCfg.plugin.display.sleepAt = disp[F("sleep")];
|
mCfg.plugin.display.sleepAt = disp[F("sleep")];
|
||||||
mCfg.plugin.display.contrast = disp[F("contrast")];
|
mCfg.plugin.display.contrast = disp[F("contrast")];
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 5
|
#define VERSION_MINOR 5
|
||||||
#define VERSION_PATCH 76
|
#define VERSION_PATCH 77
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -51,18 +51,20 @@ class MonochromeDisplay {
|
||||||
mUtcTs = utcTs;
|
mUtcTs = utcTs;
|
||||||
mNewPayload = false;
|
mNewPayload = false;
|
||||||
mLoopCnt = 0;
|
mLoopCnt = 0;
|
||||||
|
|
||||||
mTimeout = DISP_DEFAULT_TIMEOUT; // power off timeout (after inverters go offline)
|
mTimeout = DISP_DEFAULT_TIMEOUT; // power off timeout (after inverters go offline)
|
||||||
|
|
||||||
|
u8g2_cb_t *rot = (u8g2_cb_t *)((mCfg->rot180) ? U8G2_R2 : U8G2_R0);
|
||||||
|
|
||||||
if(mCfg->type) {
|
if(mCfg->type) {
|
||||||
switch(mCfg->type) {
|
switch(mCfg->type) {
|
||||||
case 1:
|
case 1:
|
||||||
mDisplay = new U8G2_PCD8544_84X48_F_4W_HW_SPI(U8G2_R0, mCfg->pin0, mCfg->pin1, disp_reset);
|
mDisplay = new U8G2_PCD8544_84X48_F_4W_HW_SPI(rot, mCfg->pin0, mCfg->pin1, disp_reset);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, disp_reset, mCfg->pin0, mCfg->pin1);
|
mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, disp_reset, mCfg->pin0, mCfg->pin1);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(U8G2_R0, disp_reset, mCfg->pin0, mCfg->pin1);
|
mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, disp_reset, mCfg->pin0, mCfg->pin1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mDisplay->begin();
|
mDisplay->begin();
|
||||||
|
|
|
@ -359,6 +359,7 @@ class RestApi {
|
||||||
obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline;
|
obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline;
|
||||||
obj[F("logo_en")] = (bool)mConfig->plugin.display.logoEn;
|
obj[F("logo_en")] = (bool)mConfig->plugin.display.logoEn;
|
||||||
obj[F("px_shift")] = (bool)mConfig->plugin.display.pxShift;
|
obj[F("px_shift")] = (bool)mConfig->plugin.display.pxShift;
|
||||||
|
obj[F("rot180")] = (bool)mConfig->plugin.display.rot180;
|
||||||
obj[F("contrast")] = (uint8_t)mConfig->plugin.display.contrast;
|
obj[F("contrast")] = (uint8_t)mConfig->plugin.display.contrast;
|
||||||
obj[F("pinDisp0")] = mConfig->plugin.display.pin0;
|
obj[F("pinDisp0")] = mConfig->plugin.display.pin0;
|
||||||
obj[F("pinDisp1")] = mConfig->plugin.display.pin1;
|
obj[F("pinDisp1")] = mConfig->plugin.display.pin1;
|
||||||
|
|
|
@ -192,6 +192,8 @@
|
||||||
<input type="checkbox" class="cb" name="dispPwr"/><br/>
|
<input type="checkbox" class="cb" name="dispPwr"/><br/>
|
||||||
<label for="dispPxSh">Enable pixel shifting</label>
|
<label for="dispPxSh">Enable pixel shifting</label>
|
||||||
<input type="checkbox" class="cb" name="dispPxSh"/><br/>
|
<input type="checkbox" class="cb" name="dispPxSh"/><br/>
|
||||||
|
<label for="disp180">Rotate 180 degree</label>
|
||||||
|
<input type="checkbox" class="cb" name="disp180"/><br/>
|
||||||
|
|
||||||
<label for="dispCont">Contrast</label>
|
<label for="dispCont">Contrast</label>
|
||||||
<select name="dispCont" id="contrast"></select>
|
<select name="dispCont" id="contrast"></select>
|
||||||
|
@ -534,7 +536,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDisplay(obj, type) {
|
function parseDisplay(obj, type) {
|
||||||
for(var i of [["logoEn", "logo_en"], ["dispPwr", "disp_pwr"], ["dispPxSh", "px_shift"]])
|
for(var i of [["logoEn", "logo_en"], ["dispPwr", "disp_pwr"], ["dispPxSh", "px_shift"], ["disp180", "rot180"]])
|
||||||
document.getElementsByName(i[0])[0].checked = obj[i[1]];
|
document.getElementsByName(i[0])[0].checked = obj[i[1]];
|
||||||
|
|
||||||
var e = document.getElementById("dispPins");
|
var e = document.getElementById("dispPins");
|
||||||
|
|
|
@ -567,6 +567,7 @@ class Web {
|
||||||
mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("dispPwr") == "on");
|
mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("dispPwr") == "on");
|
||||||
mConfig->plugin.display.logoEn = (request->arg("logoEn") == "on");
|
mConfig->plugin.display.logoEn = (request->arg("logoEn") == "on");
|
||||||
mConfig->plugin.display.pxShift = (request->arg("dispPxSh") == "on");
|
mConfig->plugin.display.pxShift = (request->arg("dispPxSh") == "on");
|
||||||
|
mConfig->plugin.display.rot180 = (request->arg("disp180") == "on");
|
||||||
mConfig->plugin.display.type = request->arg("dispType").toInt();
|
mConfig->plugin.display.type = request->arg("dispType").toInt();
|
||||||
mConfig->plugin.display.contrast = request->arg("dispCont").toInt();
|
mConfig->plugin.display.contrast = request->arg("dispCont").toInt();
|
||||||
mConfig->plugin.display.pin0 = request->arg("pinDisp0").toInt();
|
mConfig->plugin.display.pin0 = request->arg("pinDisp0").toInt();
|
||||||
|
@ -735,36 +736,78 @@ class Web {
|
||||||
void showMetrics(AsyncWebServerRequest *request) {
|
void showMetrics(AsyncWebServerRequest *request) {
|
||||||
DPRINTLN(DBG_VERBOSE, F("web::showMetrics"));
|
DPRINTLN(DBG_VERBOSE, F("web::showMetrics"));
|
||||||
String metrics;
|
String metrics;
|
||||||
char headline[80];
|
char infoline[90];
|
||||||
|
|
||||||
snprintf(headline, 80, "ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1", mApp->getVersion(), mConfig->sys.deviceName);
|
// System info
|
||||||
metrics += "# TYPE ahoy_solar_info gauge\n" + String(headline) + "\n";
|
snprintf(infoline, sizeof(infoline), "ahoy_solar_info{version=\"%s\",image=\"\",devicename=\"%s\"} 1", mApp->getVersion(), mConfig->sys.deviceName);
|
||||||
|
metrics += "# TYPE ahoy_solar_info gauge\n" + String(infoline) + "\n";
|
||||||
Inverter<> *iv;
|
Inverter<> *iv;
|
||||||
record_t<> *rec;
|
record_t<> *rec;
|
||||||
char type[60], topic[60], val[25];
|
char type[60], topic[80], val[25];
|
||||||
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||||
iv = mSys->getInverterByPos(id);
|
iv = mSys->getInverterByPos(id);
|
||||||
if(NULL == iv)
|
if(NULL == iv)
|
||||||
continue;
|
continue;
|
||||||
|
// Inverter info
|
||||||
|
snprintf(infoline, sizeof(infoline), "ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\",enabled=\"%d\"} 1",
|
||||||
|
iv->config->name, iv->config->serial.u64,iv->config->enabled);
|
||||||
|
metrics += "# TYPE ahoy_solar_inverter_info gauge\n" + String(infoline) + "\n";
|
||||||
|
|
||||||
|
// AC
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
for(uint8_t i = 0; i < rec->length; i++) {
|
for(uint8_t i = 0; i < rec->length; i++) {
|
||||||
uint8_t channel = rec->assign[i].ch;
|
uint8_t channel = rec->assign[i].ch;
|
||||||
if(channel == 0) {
|
if(channel == 0) {
|
||||||
String promUnit, promType;
|
String promUnit, promType;
|
||||||
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(i, rec));
|
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(i, rec));
|
||||||
snprintf(type, 60, "# TYPE ahoy_solar_%s_%s %s", iv->getFieldName(i, rec), promUnit.c_str(), promType.c_str());
|
snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s_%s %s", iv->getFieldName(i, rec), promUnit.c_str(), promType.c_str());
|
||||||
snprintf(topic, 60, "ahoy_solar_%s_%s{inverter=\"%s\"}", iv->getFieldName(i, rec), promUnit.c_str(), iv->config->name);
|
snprintf(topic, sizeof(topic), "ahoy_solar_%s_%s{inverter=\"%s\"}", iv->getFieldName(i, rec), promUnit.c_str(), iv->config->name);
|
||||||
snprintf(val, 25, "%.3f", iv->getValue(i, rec));
|
snprintf(val, sizeof(val), "%.3f", iv->getValue(i, rec));
|
||||||
|
metrics += String(type) + "\n" + String(topic) + " " + String(val) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// channels DC
|
||||||
|
for(uint8_t j = 1; j <= iv->channels; j ++) {
|
||||||
|
uint8_t pos;
|
||||||
|
for (uint8_t k = 0; k < 6; k++) {
|
||||||
|
switch(k) {
|
||||||
|
default: pos = (iv->getPosByChFld(j, FLD_UDC, rec)); break;
|
||||||
|
case 1: pos = (iv->getPosByChFld(j, FLD_IDC, rec)); break;
|
||||||
|
case 2: pos = (iv->getPosByChFld(j, FLD_PDC, rec)); break;
|
||||||
|
case 3: pos = (iv->getPosByChFld(j, FLD_YD, rec)); break;
|
||||||
|
case 4: pos = (iv->getPosByChFld(j, FLD_YT, rec)); break;
|
||||||
|
case 5: pos = (iv->getPosByChFld(j, FLD_IRR, rec)); break;
|
||||||
|
}
|
||||||
|
String promUnit, promType;
|
||||||
|
std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(pos, rec));
|
||||||
|
snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s_%s %s", iv->getFieldName(pos, rec), promUnit.c_str(), promType.c_str());
|
||||||
|
snprintf(topic, sizeof(topic), "ahoy_solar_%s_%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(pos, rec), promUnit.c_str(), iv->config->name, iv->config->chName[j-1]);
|
||||||
|
snprintf(val, sizeof(val), "%.3f", iv->getValue(pos, rec));
|
||||||
metrics += String(type) + "\n" + String(topic) + " " + String(val) + "\n";
|
metrics += String(type) + "\n" + String(topic) + " " + String(val) + "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse(200, F("text/html"), metrics);
|
// NRF Statistics
|
||||||
|
statistics_t *stat = mApp->getStatistics();
|
||||||
|
metrics += radioStatistic(F("rx_success"), stat->rxSuccess);
|
||||||
|
metrics += radioStatistic(F("rx_fail"), stat->rxFail);
|
||||||
|
metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser);
|
||||||
|
metrics += radioStatistic(F("frame_cnt"), stat->frmCnt);
|
||||||
|
metrics += radioStatistic(F("tx_cnt"), mSys->Radio.mSendCnt);
|
||||||
|
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, F("text/plain"), metrics);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String radioStatistic(String statistic, uint32_t value) {
|
||||||
|
char type[60], topic[80], val[25];
|
||||||
|
snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s gauge",statistic.c_str());
|
||||||
|
snprintf(topic, sizeof(topic), "ahoy_solar_radio_%s",statistic.c_str());
|
||||||
|
snprintf(val, sizeof(val), "%d", value);
|
||||||
|
return ( String(type) + "\n" + String(topic) + " " + String(val) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<String, String> convertToPromUnits(String shortUnit) {
|
std::pair<String, String> convertToPromUnits(String shortUnit) {
|
||||||
if(shortUnit == "A") return {"ampere", "gauge"};
|
if(shortUnit == "A") return {"ampere", "gauge"};
|
||||||
if(shortUnit == "V") return {"volt", "gauge"};
|
if(shortUnit == "V") return {"volt", "gauge"};
|
||||||
|
|
Loading…
Add table
Reference in a new issue