mirror of
https://github.com/lumapu/ahoy.git
synced 2025-08-01 23:48:24 +02:00
0.5.106
* merged MI and debug message changes #804 * fixed MQTT autodiscover #794, #632
This commit is contained in:
parent
3f2e40848e
commit
850cda3c38
4 changed files with 117 additions and 99 deletions
|
@ -2,6 +2,10 @@
|
|||
|
||||
(starting from release version `0.5.66`)
|
||||
|
||||
## 0.5.106
|
||||
* merged MI and debug message changes #804
|
||||
* fixed MQTT autodiscover #794, #632
|
||||
|
||||
## 0.5.105
|
||||
* merged MI, thx @rejoe2 #788
|
||||
* fixed reboot message #793
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 5
|
||||
#define VERSION_PATCH 105
|
||||
#define VERSION_PATCH 106
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -35,25 +35,20 @@ extra_scripts =
|
|||
|
||||
lib_deps =
|
||||
https://github.com/yubox-node-org/ESPAsyncWebServer
|
||||
nrf24/RF24
|
||||
paulstoffregen/Time
|
||||
nrf24/RF24 @ ^1.4.5
|
||||
paulstoffregen/Time @ ^1.6.1
|
||||
https://github.com/bertmelis/espMqttClient#v1.4.1
|
||||
bblanchon/ArduinoJson
|
||||
https://github.com/JChristensen/Timezone
|
||||
olikraus/U8g2
|
||||
zinggjm/GxEPD2@^1.5.0
|
||||
;esp8266/DNSServer
|
||||
;esp8266/EEPROM
|
||||
;esp8266/ESP8266WiFi
|
||||
;esp8266/SPI
|
||||
;esp8266/Ticker
|
||||
bblanchon/ArduinoJson @ ^6.21.0
|
||||
https://github.com/JChristensen/Timezone @ ^1.2.4
|
||||
olikraus/U8g2 @ ^2.34.16
|
||||
zinggjm/GxEPD2 @ ^1.5.0
|
||||
|
||||
|
||||
[env:esp8266-release]
|
||||
platform = espressif8266
|
||||
board = esp12e
|
||||
board_build.f_cpu = 80000000L
|
||||
build_flags = -D RELEASE
|
||||
build_flags = -D RELEASE -Wl,-Map,output.map
|
||||
monitor_filters =
|
||||
;default ; Remove typical terminal control codes from input
|
||||
;time ; Add timestamp with milliseconds for each new line
|
||||
|
|
|
@ -34,6 +34,12 @@ struct alarm_t {
|
|||
alarm_t(uint16_t c, uint32_t s, uint32_t e) : code(c), start(s), end(e) {}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
bool running;
|
||||
uint8_t lastIvId;
|
||||
uint8_t sub;
|
||||
} discovery_t;
|
||||
|
||||
template<class HMSYSTEM>
|
||||
class PubMqtt {
|
||||
public:
|
||||
|
@ -55,6 +61,8 @@ class PubMqtt {
|
|||
mUtcTimestamp = utcTs;
|
||||
mIntervalTimeout = 1;
|
||||
|
||||
mDiscovery.running = false;
|
||||
|
||||
snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic);
|
||||
|
||||
if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0))
|
||||
|
@ -82,6 +90,9 @@ class PubMqtt {
|
|||
mClient.loop();
|
||||
yield();
|
||||
#endif
|
||||
|
||||
if(mDiscovery.running)
|
||||
discoveryConfigLoop();
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,92 +221,9 @@ class PubMqtt {
|
|||
|
||||
void sendDiscoveryConfig(void) {
|
||||
DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig"));
|
||||
|
||||
char topic[64], name[32], uniq_id[32];
|
||||
DynamicJsonDocument doc(256);
|
||||
|
||||
uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC};
|
||||
const char* unitTotal[4] = {"W", "kWh", "Wh", "W"};
|
||||
|
||||
String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17);
|
||||
String node_id = "AHOY_DTU_" + node_mac;
|
||||
bool total = false;
|
||||
|
||||
for (uint8_t id = 0; id < mSys->getNumInverters() ; id++) {
|
||||
doc.clear();
|
||||
|
||||
if (total) // total become true at iv = NULL next cycle
|
||||
continue;
|
||||
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
if (NULL == iv)
|
||||
total = true;
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
|
||||
if (!total) {
|
||||
doc[F("name")] = iv->config->name;
|
||||
doc[F("ids")] = String(iv->config->serial.u64, HEX);
|
||||
doc[F("mdl")] = iv->config->name;
|
||||
}
|
||||
else {
|
||||
doc[F("name")] = node_id;
|
||||
doc[F("ids")] = node_id;
|
||||
doc[F("mdl")] = node_id;
|
||||
}
|
||||
|
||||
doc[F("cu")] = F("http://") + String(WiFi.localIP().toString());
|
||||
doc[F("mf")] = F("Hoymiles");
|
||||
JsonObject deviceObj = doc.as<JsonObject>(); // deviceObj is only pointer!?
|
||||
|
||||
for (uint8_t i = 0; i < ((!total) ? (rec->length) : (4) ) ; i++) {
|
||||
const char *devCls, *stateCls;
|
||||
if (!total) {
|
||||
if (rec->assign[i].ch == CH0)
|
||||
snprintf(name, 32, "%s %s", iv->config->name, iv->getFieldName(i, rec));
|
||||
else
|
||||
snprintf(name, 32, "%s CH%d %s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(topic, 64, "/ch%d/%s", rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
snprintf(uniq_id, 32, "ch%d_%s", rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
|
||||
devCls = getFieldDeviceClass(rec->assign[i].fieldId);
|
||||
stateCls = getFieldStateClass(rec->assign[i].fieldId);
|
||||
}
|
||||
|
||||
else { // total values
|
||||
snprintf(name, 32, "Total %s", fields[fldTotal[i]]);
|
||||
snprintf(topic, 64, "/%s", fields[fldTotal[i]]);
|
||||
snprintf(uniq_id, 32, "total_%s", fields[fldTotal[i]]);
|
||||
devCls = getFieldDeviceClass(fldTotal[i]);
|
||||
stateCls = getFieldStateClass(fldTotal[i]);
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc2(512);
|
||||
doc2[F("name")] = name;
|
||||
doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic);
|
||||
doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(i,rec)) : (unitTotal[i]));
|
||||
doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id;
|
||||
doc2[F("dev")] = deviceObj;
|
||||
if (!(String(stateCls) == String("total_increasing")))
|
||||
doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!?
|
||||
if (devCls != NULL)
|
||||
doc2[F("dev_cla")] = String(devCls);
|
||||
if (stateCls != NULL)
|
||||
doc2[F("stat_cla")] = String(stateCls);
|
||||
|
||||
if (!total)
|
||||
snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
|
||||
else // total values
|
||||
snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fldTotal[i]]);
|
||||
size_t size = measureJson(doc2) + 1;
|
||||
char *buf = new char[size];
|
||||
memset(buf, 0, size);
|
||||
serializeJson(doc2, buf, size);
|
||||
publish(topic, buf, true, false);
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
yield();
|
||||
}
|
||||
mDiscovery.running = true;
|
||||
mDiscovery.lastIvId = 0;
|
||||
mDiscovery.sub = 0;
|
||||
}
|
||||
|
||||
void setPowerLimitAck(Inverter<> *iv) {
|
||||
|
@ -415,6 +343,95 @@ class PubMqtt {
|
|||
mRxCnt++;
|
||||
}
|
||||
|
||||
void discoveryConfigLoop(void) {
|
||||
char topic[64], name[32], uniq_id[32], buf[350];
|
||||
DynamicJsonDocument doc(256);
|
||||
|
||||
uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC};
|
||||
const char* unitTotal[4] = {"W", "kWh", "Wh", "W"};
|
||||
|
||||
String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17);
|
||||
String node_id = "AHOY_DTU_" + node_mac;
|
||||
bool total = (mDiscovery.lastIvId == MAX_NUM_INVERTERS);
|
||||
|
||||
Inverter<> *iv = mSys->getInverterByPos(mDiscovery.lastIvId);
|
||||
record_t<> *rec;
|
||||
if (NULL != iv)
|
||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
|
||||
if ((NULL != iv) || total) {
|
||||
if (!total) {
|
||||
doc[F("name")] = iv->config->name;
|
||||
doc[F("ids")] = String(iv->config->serial.u64, HEX);
|
||||
doc[F("mdl")] = iv->config->name;
|
||||
}
|
||||
else {
|
||||
doc[F("name")] = node_id;
|
||||
doc[F("ids")] = node_id;
|
||||
doc[F("mdl")] = node_id;
|
||||
}
|
||||
|
||||
doc[F("cu")] = F("http://") + String(WiFi.localIP().toString());
|
||||
doc[F("mf")] = F("Hoymiles");
|
||||
JsonObject deviceObj = doc.as<JsonObject>(); // deviceObj is only pointer!?
|
||||
|
||||
const char *devCls, *stateCls;
|
||||
if (!total) {
|
||||
if (rec->assign[mDiscovery.sub].ch == CH0)
|
||||
snprintf(name, 32, "%s %s", iv->config->name, iv->getFieldName(mDiscovery.sub, rec));
|
||||
else
|
||||
snprintf(name, 32, "%s CH%d %s", iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec));
|
||||
snprintf(topic, 64, "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec));
|
||||
snprintf(uniq_id, 32, "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec));
|
||||
|
||||
devCls = getFieldDeviceClass(rec->assign[mDiscovery.sub].fieldId);
|
||||
stateCls = getFieldStateClass(rec->assign[mDiscovery.sub].fieldId);
|
||||
}
|
||||
|
||||
else { // total values
|
||||
snprintf(name, 32, "Total %s", fields[fldTotal[mDiscovery.sub]]);
|
||||
snprintf(topic, 64, "/%s", fields[fldTotal[mDiscovery.sub]]);
|
||||
snprintf(uniq_id, 32, "total_%s", fields[fldTotal[mDiscovery.sub]]);
|
||||
devCls = getFieldDeviceClass(fldTotal[mDiscovery.sub]);
|
||||
stateCls = getFieldStateClass(fldTotal[mDiscovery.sub]);
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc2(512);
|
||||
doc2[F("name")] = name;
|
||||
doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic);
|
||||
doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub]));
|
||||
doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id;
|
||||
doc2[F("dev")] = deviceObj;
|
||||
if (!(String(stateCls) == String("total_increasing")))
|
||||
doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!?
|
||||
if (devCls != NULL)
|
||||
doc2[F("dev_cla")] = String(devCls);
|
||||
if (stateCls != NULL)
|
||||
doc2[F("stat_cla")] = String(stateCls);
|
||||
|
||||
if (!total)
|
||||
snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec));
|
||||
else // total values
|
||||
snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fldTotal[mDiscovery.sub]]);
|
||||
size_t size = measureJson(doc2) + 1;
|
||||
memset(buf, 0, size);
|
||||
serializeJson(doc2, buf, size);
|
||||
publish(topic, buf, true, false);
|
||||
|
||||
if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) {
|
||||
mDiscovery.sub = 0;
|
||||
if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1))
|
||||
mDiscovery.running = false;
|
||||
}
|
||||
} else {
|
||||
mDiscovery.sub = 0;
|
||||
if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1))
|
||||
mDiscovery.running = false;
|
||||
}
|
||||
|
||||
yield();
|
||||
}
|
||||
|
||||
const char *getFieldDeviceClass(uint8_t fieldId) {
|
||||
uint8_t pos = 0;
|
||||
for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) {
|
||||
|
@ -643,6 +660,8 @@ class PubMqtt {
|
|||
char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT
|
||||
// global buffer for mqtt topic. Used when publishing mqtt messages.
|
||||
char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1];
|
||||
|
||||
discovery_t mDiscovery;
|
||||
};
|
||||
|
||||
#endif /*__PUB_MQTT_H__*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue