Browse Source

added hardware info

pull/1116/head
lumapu 1 year ago
parent
commit
a91885b505
  1. 1
      src/.vscode/settings.json
  2. 2
      src/defines.h
  3. 67
      src/hm/hmDefines.h
  4. 50
      src/hm/hmInverter.h
  5. 30
      src/web/RestApi.h
  6. 14
      src/web/html/style.css
  7. 43
      src/web/html/visualization.html

1
src/.vscode/settings.json

@ -84,4 +84,5 @@
},
"cmake.configureOnOpen": false,
"editor.formatOnSave": false,
"cmake.sourceDirectory": "C:/lpusch/github/ahoy/src/.pio/libdeps/esp32-wroom32-release-prometheus/Adafruit BusIO",
}

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 7
#define VERSION_PATCH 37
#define VERSION_PATCH 38
//-------------------------------------
typedef struct {

67
src/hm/hmDefines.h

@ -10,7 +10,8 @@
#include <cstdint>
// inverter generations
enum {IV_HM = 0, IV_MI, IV_HMS, IV_HMT};
enum {IV_MI = 0, IV_HM, IV_HMS, IV_HMT, IV_UNKNOWN};
const char* const generationNames[] = {"HM", "MI", "HMS", "HMT", "UNKNOWN"};
// units
enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT, UNIT_VAR, UNIT_NONE};
@ -21,20 +22,22 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
FLD_UAC, FLD_UAC_1N, FLD_UAC_2N, FLD_UAC_3N, FLD_UAC_12, FLD_UAC_23, FLD_UAC_31, FLD_IAC,
FLD_IAC_1, FLD_IAC_2, FLD_IAC_3, FLD_PAC, FLD_F, FLD_T, FLD_PF, FLD_EFF,
FLD_IRR, FLD_Q, FLD_EVT, FLD_FW_VERSION, FLD_FW_BUILD_YEAR,
FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_HW_ID,
FLD_ACT_ACTIVE_PWR_LIMIT, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP};
FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER,
FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE,
FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP};
const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
"U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC",
"IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC",
"ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","HWPartId",
"active_PowerLimit", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"};
"ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","BootloaderVersion",
"active_PowerLimit", "HWPartNumber", "HWVersion", "GridProfileCode",
"GridProfileVersion", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"};
const char* const notAvail = "n/a";
const uint8_t fieldUnits[] = {UNIT_V, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_KWH,
UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_A, UNIT_A, UNIT_A, UNIT_A,
UNIT_W, UNIT_HZ, UNIT_C, UNIT_NONE, UNIT_PCT, UNIT_PCT, UNIT_VAR,
UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_W};
UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_W};
// mqtt discovery device classes
enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP};
@ -98,11 +101,20 @@ const byteAssign_t InfoAssignment[] = {
{ FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 },
{ FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 },
{ FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 },
{ FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 }
{ FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 }
};
#define HMINFO_LIST_LEN (sizeof(InfoAssignment) / sizeof(byteAssign_t))
#define HMINFO_PAYLOAD_LEN 14
const byteAssign_t SimpleInfoAssignment[] = {
{ FLD_PART_NUM, UNIT_NONE, CH0, 2, 4, 1 },
{ FLD_HW_VERSION, UNIT_NONE, CH0, 6, 2, 1 },
{ FLD_GRID_PROFILE_CODE, UNIT_NONE, CH0, 8, 2, 1 },
{ FLD_GRID_PROFILE_VERSION, UNIT_NONE, CH0, 10, 2, 1 }
};
#define HMSIMPLE_INFO_LIST_LEN (sizeof(SimpleInfoAssignment) / sizeof(byteAssign_t))
#define HMSIMPLE_INFO_PAYLOAD_LEN 14
const byteAssign_t SystemConfigParaAssignment[] = {
{ FLD_ACT_ACTIVE_PWR_LIMIT, UNIT_PCT, CH0, 2, 2, 10 }/*,
{ FLD_ACT_REACTIVE_PWR_LIMIT, UNIT_PCT, CH0, 4, 2, 10 },
@ -242,4 +254,45 @@ const byteAssign_t hm4chAssignment[] = {
#define HM4CH_PAYLOAD_LEN 62
typedef struct {
uint32_t hwPart;
uint16_t maxPower;
} devInfo_t;
const devInfo_t devInfo[] = {
// MI 3rd gen
{ 0x100230, 1500 },
// HM
{ 0x101010, 300 },
{ 0x101020, 350 },
{ 0x101030, 400 },
{ 0x101040, 400 },
{ 0x101110, 600 },
{ 0x101120, 700 },
{ 0x101130, 800 },
{ 0x101140, 800 },
{ 0x101210, 1200 },
{ 0x101230, 1500 },
// HMS
{ 0x102021, 350 },
{ 0x102041, 400 },
{ 0x101051, 450 },
{ 0x101071, 500 },
{ 0x102111, 600 },
{ 0x102141, 800 },
{ 0x101151, 900 },
{ 0x102171, 1000 },
{ 0x102241, 1600 },
{ 0x101251, 1800 },
{ 0x102251, 1800 },
{ 0x101271, 2000 },
{ 0x102271, 2000 },
// HMT
{ 0x103311, 1800 },
{ 0x103331, 2250 }
};
#endif /*__HM_DEFINES_H__*/

50
src/hm/hmInverter.h

@ -142,6 +142,7 @@ class Inverter {
uint8_t channels; // number of PV channels (1-4)
record_t<REC_TYP> recordMeas; // structure for measured values
record_t<REC_TYP> recordInfo; // structure for info values
record_t<REC_TYP> recordHwInfo; // structure for simple (hardware) info values
record_t<REC_TYP> recordConfig; // structure for system config values
record_t<REC_TYP> recordAlarm; // structure for alarm values
//String lastAlarmMsg;
@ -189,7 +190,6 @@ class Inverter {
void setQueuedCmdFinished() {
if (!_commandQueue.empty()) {
// Will destroy CommandAbstract Class Object (?)
_commandQueue.pop();
}
}
@ -197,7 +197,6 @@ class Inverter {
void clearCmdQueue() {
DPRINTLN(DBG_INFO, F("clearCmdQueue"));
while (!_commandQueue.empty()) {
// Will destroy CommandAbstract Class Object (?)
_commandQueue.pop();
}
}
@ -207,6 +206,8 @@ class Inverter {
if (ivGen != IV_MI) {
if (getFwVersion() == 0)
enqueCommand<InfoCommand>(InverterDevInform_All); // firmware version
else if (getHwVersion() == 0)
enqueCommand<InfoCommand>(InverterDevInform_Simple); // hardware version
enqueCommand<InfoCommand>(RealTimeRunData_Debug); // live data
} else if (ivGen == IV_MI){
if (getFwVersion() == 0)
@ -229,6 +230,7 @@ class Inverter {
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:init"));
initAssignment(&recordMeas, RealTimeRunData_Debug);
initAssignment(&recordInfo, InverterDevInform_All);
initAssignment(&recordHwInfo, InverterDevInform_Simple);
initAssignment(&recordConfig, SystemConfigPara);
initAssignment(&recordAlarm, AlarmData);
toRadioId();
@ -340,6 +342,10 @@ class Inverter {
// eg. fw version ...
isConnected = true;
}
else if (rec->assign == SimpleInfoAssignment) {
DPRINTLN(DBG_DEBUG, "add simple info");
// eg. hw version ...
}
else if (rec->assign == SystemConfigParaAssignment) {
DPRINTLN(DBG_DEBUG, "add config");
if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){
@ -390,6 +396,10 @@ class Inverter {
return 0;
}
uint32_t getChannelFieldValueInt(uint8_t channel, uint8_t fieldId, record_t<> *rec) {
return (uint32_t) getChannelFieldValue(channel, fieldId, rec);
}
REC_TYP getValue(uint8_t pos, record_t<> *rec) {
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getValue"));
if(NULL == rec)
@ -452,8 +462,24 @@ class Inverter {
uint16_t getFwVersion() {
record_t<> *rec = getRecordStruct(InverterDevInform_All);
uint8_t pos = getPosByChFld(CH0, FLD_FW_VERSION, rec);
return getValue(pos, rec);
return getChannelFieldValue(CH0, FLD_FW_VERSION, rec);
}
uint16_t getHwVersion() {
record_t<> *rec = getRecordStruct(InverterDevInform_Simple);
return getChannelFieldValue(CH0, FLD_HW_VERSION, rec);
}
uint16_t getMaxPower() {
record_t<> *rec = getRecordStruct(InverterDevInform_Simple);
if(0 == getChannelFieldValue(CH0, FLD_HW_VERSION, rec))
return 0;
for(uint8_t i = 0; i < sizeof(devInfo) / sizeof(devInfo_t); i++) {
if(devInfo[i].hwPart == (getChannelFieldValueInt(CH0, FLD_PART_NUM, rec) >> 8))
return devInfo[i].maxPower;
}
return 0;
}
uint32_t getLastTs(record_t<> *rec) {
@ -463,11 +489,12 @@ class Inverter {
record_t<> *getRecordStruct(uint8_t cmd) {
switch (cmd) {
case RealTimeRunData_Debug: return &recordMeas; // 11 = 0x0b
case InverterDevInform_All: return &recordInfo; // 1 = 0x01
case SystemConfigPara: return &recordConfig; // 5 = 0x05
case AlarmData: return &recordAlarm; // 17 = 0x11
default: break;
case RealTimeRunData_Debug: return &recordMeas; // 11 = 0x0b
case InverterDevInform_Simple: return &recordHwInfo; // 0 = 0x00
case InverterDevInform_All: return &recordInfo; // 1 = 0x01
case SystemConfigPara: return &recordConfig; // 5 = 0x05
case AlarmData: return &recordAlarm; // 17 = 0x11
default: break;
}
return NULL;
}
@ -535,6 +562,11 @@ class Inverter {
rec->assign = (byteAssign_t *)InfoAssignment;
rec->pyldLen = HMINFO_PAYLOAD_LEN;
break;
case InverterDevInform_Simple:
rec->length = (uint8_t)(HMSIMPLE_INFO_LIST_LEN);
rec->assign = (byteAssign_t *)SimpleInfoAssignment;
rec->pyldLen = HMSIMPLE_INFO_PAYLOAD_LEN;
break;
case SystemConfigPara:
rec->length = (uint8_t)(HMSYSTEM_LIST_LEN);
rec->assign = (byteAssign_t *)SystemConfigParaAssignment;

30
src/web/RestApi.h

@ -107,6 +107,8 @@ class RestApi {
getInverter(root, request->url().substring(17).toInt());
else if(path.substring(0, 15) == "inverter/alarm/")
getIvAlarms(root, request->url().substring(20).toInt());
else if(path.substring(0, 15) == "inverter/version/")
getIvVersion(root, request->url().substring(20).toInt());
else
getNotFound(root, F("http://") + request->host() + F("/api/"));
}
@ -421,6 +423,34 @@ class RestApi {
}
}
void getIvVersion(JsonObject obj, uint8_t id) {
Inverter<> *iv = mSys->getInverterByPos(id);
if(NULL == iv) {
obj[F("error")] = F("inverter not found!");
return;
}
record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple);
obj[F("name")] = String(iv->config->name);
obj[F("generation")] = iv->ivGen;
obj[F("max_pwr")] = iv->getMaxPower();
obj[F("part_num")] = iv->getChannelFieldValueInt(CH0, FLD_PART_NUM, rec);
obj[F("hw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_HW_VERSION, rec);
obj[F("prod_cw")] = ((iv->radioId.b[3] & 0x0f) * 10 + ((iv->radioId.b[4] & 0x0f)));
obj[F("prod_year")] = ((iv->radioId.b[3] >> 4) & 0x0f) + 2014;
rec = iv->getRecordStruct(InverterDevInform_All);
obj[F("fw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_FW_VERSION, rec);
obj[F("fw_date")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_YEAR, rec))
+ "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) / 100)
+ "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) % 100);
obj[F("fw_time")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) / 100)
+ ":" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) % 100);
obj[F("boot_ver")] = iv->getChannelFieldValueInt(CH0, FLD_BOOTLOADER_VER, rec);
}
void getMqtt(JsonObject obj) {
obj[F("broker")] = String(mConfig->mqtt.broker);
obj[F("clientId")] = String(mConfig->mqtt.clientId);

14
src/web/html/style.css

@ -318,6 +318,20 @@ p {
.col-md-12 { width: 100%; }
}
table {
border-collapse: collapse;
width: 100%;
}
th {
text-align: inherit;
}
.table td, .table th {
padding: .75rem;
border-bottom: 1px solid var(--nav-bg);
}
#wrapper {
min-height: 100%;
}

43
src/web/html/visualization.html

@ -102,7 +102,9 @@
ml("div", {class: "col"}, [
ml("div", {class: "p-2 " + clh},
ml("div", {class: "row"}, [
ml("div", {class: "col mx-2 mx-md-1"}, obj.name),
ml("div", {class: "col mx-2 mx-md-1"}, ml("span", { class: "pointer", onclick: function() {
getAjax("/api/inverter/version/" + obj.id, parseIvVersion);
}}, obj.name)),
ml("div", {class: "col a-c"}, "Power limit " + ((obj.power_limit_read == 65535) ? "n/a" : (obj.power_limit_read + "&nbsp;%"))),
ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() {
getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm);
@ -250,6 +252,45 @@
modal("Alarms of inverter #" + obj.iv_id, ml("div", {}, html));
}
function parseIvVersion(obj) {
var model;
switch(obj.generation) {
case 0: model = "MI-"; break;
case 1: model = "HM-"; break;
case 2: model = "HMS-"; break;
case 3: model = "HMT-"; break;
default: model = "???-"; break;
}
model += String(obj.max_pwr);
var html = ml("table", {class: "table"}, [
ml("tbody", {}, [
ml("tr", {}, [
ml("th", {}, "Model"),
ml("td", {}, model)
]),
ml("tr", {}, [
ml("th", {}, "Firmware Version / Build"),
ml("td", {}, String(obj.fw_ver) + " (build: " + String(obj.fw_date) + " " + String(obj.fw_time) + ")")
]),
ml("tr", {}, [
ml("th", {}, "Hardware Version / Build"),
ml("td", {}, String(obj.hw_ver) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")")
]),
ml("tr", {}, [
ml("th", {}, "Hardware Number"),
ml("td", {}, String(obj.part_num))
]),
ml("tr", {}, [
ml("th", {}, "Bootloader Version"),
ml("td", {}, String(obj.boot_ver))
])
])
]);
modal("Info for inverter " + obj.name, ml("div", {}, html));
}
function parse(obj) {
if(null != obj) {
parseGeneric(obj["generic"]);

Loading…
Cancel
Save