Browse Source

Merge branch 'development03' into development03

pull/630/head
Rémi K 2 years ago
committed by GitHub
parent
commit
6e6ef9ff2c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/CHANGES.md
  2. 2
      src/defines.h
  3. 134
      src/publisher/pubMqtt.h
  4. 3
      src/web/RestApi.h
  5. 128
      src/wifi/ahoywifi.cpp
  6. 7
      src/wifi/ahoywifi.h

10
src/CHANGES.md

@ -2,10 +2,18 @@
(starting from release version `0.5.66`)
## 0.5.78
* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there
* fix endless loop in `zerovalues` #564
* fix auto discover again #565
* added total values to autodiscover #630
* improved zero at midnight #625
## 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
* improved Prometheus endpoint #615, thx to @fsck-block
* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611
## 0.5.76
* reduce MQTT retry interval from maximum speed to one second

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 5
#define VERSION_PATCH 77
#define VERSION_PATCH 78
//-------------------------------------
typedef struct {

134
src/publisher/pubMqtt.h

@ -133,6 +133,7 @@ class PubMqtt {
void tickerMidnight() {
Inverter<> *iv;
record_t<> *rec;
char topic[7 + MQTT_TOPIC_LEN], val[4];
// set YieldDay to zero
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
@ -142,10 +143,11 @@ class PubMqtt {
rec = iv->getRecordStruct(RealTimeRunData_Debug);
uint8_t pos = iv->getPosByChFld(CH0, FLD_YD, rec);
iv->setValue(pos, rec, 0.0f);
}
mSendList.push(RealTimeRunData_Debug);
sendIvData();
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch0/%s", iv->config->name, fields[FLD_YD]);
snprintf(val, 4, "0.0");
publish(topic, val, true);
}
}
void payloadEventListener(uint8_t cmd) {
@ -210,7 +212,11 @@ class PubMqtt {
DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig"));
char topic[64], name[32], uniq_id[32];
DynamicJsonDocument doc(512);
DynamicJsonDocument doc(256);
uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC};
const char* unitTotal[4] = {"W", "kWh", "Wh", "W"};
for (uint8_t id = 0; id < mSys->getNumInverters(); id++) {
Inverter<> *iv = mSys->getInverterByPos(id);
if (NULL == iv)
@ -218,29 +224,39 @@ class PubMqtt {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
doc.clear();
doc[F("name")] = iv->config->name;
doc[F("ids")] = String(iv->config->serial.u64, HEX);
doc[F("cu")] = F("http://") + String(WiFi.localIP().toString());
doc[F("mf")] = F("Hoymiles");
doc[F("mdl")] = iv->config->name;
JsonObject deviceObj = doc.as<JsonObject>();
for (uint8_t i = 0; i < rec->length; i++) {
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));
const char *devCls = getFieldDeviceClass(rec->assign[i].fieldId);
const char *stateCls = getFieldStateClass(rec->assign[i].fieldId);
JsonObject deviceObj = doc.as<JsonObject>(); // deviceObj is only pointer!?
for (uint8_t i = 0; i < (rec->length + 4); i++) {
const char *devCls, *stateCls;
if(i < rec->length) {
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-rec->length]]);
snprintf(topic, 64, "/%s", fields[fldTotal[i-rec->length]]);
snprintf(uniq_id, 32, "total_%s", fields[fldTotal[i-rec->length]]);
devCls = getFieldDeviceClass(fldTotal[i-rec->length]);
stateCls = getFieldStateClass(fldTotal[i-rec->length]);
}
DynamicJsonDocument doc2(512);
doc2.clear();
doc2[F("name")] = name;
doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + String(iv->config->name) + String(topic);
doc2[F("unit_of_meas")] = iv->getUnit(i, rec);
doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((i < rec->length) ? String(iv->config->name) : "total" ) + String(topic);
doc2[F("unit_of_meas")] = ((i < rec->length) ? (iv->getUnit(i,rec)) : (unitTotal[i-rec->length]));
doc2[F("uniq_id")] = String(iv->config->serial.u64, HEX) + "_" + uniq_id;
doc2[F("dev")] = deviceObj;
doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!?
@ -249,7 +265,10 @@ class PubMqtt {
if (stateCls != NULL)
doc2[F("stat_cla")] = String(stateCls);
snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec));
if(i < rec->length)
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, iv->config->name, fields[fldTotal[i-rec->length]]);
size_t size = measureJson(doc2) + 1;
char *buf = new char[size];
memset(buf, 0, size);
@ -258,72 +277,8 @@ class PubMqtt {
delete[] buf;
}
yield();
}
//Début modif
String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17);
String node_id = "AHOY_DTU_" + node_mac;
doc.clear();
doc[F("name")] = node_id;
doc[F("ids")] = node_id;
doc[F("cu")] = F("http://") + String(WiFi.localIP().toString());
doc[F("mf")] = F("Hoymiles");
doc[F("mdl")] = "AHOY_DTU";
JsonObject deviceObj = doc.as<JsonObject>();
uint8_t fieldId;
String fieldUnit;
for (uint8_t i = 0; i < 4; i++) {
switch (i) {
default:
case 0:
fieldId = FLD_PAC;
fieldUnit = "W";
break;
case 1:
fieldId = FLD_YT;
fieldUnit = "kWh";
break;
case 2:
fieldId = FLD_YD;
fieldUnit = "Wh";
break;
case 3:
fieldId = FLD_PDC;
fieldUnit = "W";
break;
}
snprintf(name, 32, "Total %s", fields[fieldId]);
snprintf(topic, 64, "/%s", fields[fieldId]);
const char *devCls = getFieldDeviceClass(fieldId);
const char *stateCls = getFieldStateClass(fieldId);
DynamicJsonDocument doc2(512);
doc2.clear();
doc2[F("name")] = String(name);
doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/total" + String(topic);
doc2[F("unit_of_meas")] = fieldUnit;
doc2[F("uniq_id")] = String(node_id) + "_" + String(fields[fieldId]);
doc2[F("dev")] = deviceObj;
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);
snprintf(topic, 64, "%s/sensor/%s/Total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fieldId]);
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();
}
}
void setPowerLimitAck(Inverter<> *iv) {
@ -452,14 +407,6 @@ class PubMqtt {
return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : stateClasses[deviceFieldAssignment[pos].stateClsId];
}
const char *getFieldUnit(uint8_t fieldId) {
uint8_t pos = 0;
for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) {
if (deviceFieldAssignment[pos].fieldId == fieldId)
break;
}
return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : deviceClasses[deviceFieldAssignment[pos].deviceClsId];
}
bool processIvStatus() {
// returns true if all inverters are available
bool allAvail = true;
@ -655,6 +602,7 @@ class PubMqtt {
case FLD_FW_BUILD_HOUR_MINUTE:
case FLD_HW_ID:
case FLD_ACT_ACTIVE_PWR_LIMIT:
fld++;
continue;
break;
}

3
src/web/RestApi.h

@ -600,9 +600,8 @@ class RestApi {
}
bool setSetup(JsonObject jsonIn, JsonObject jsonOut) {
if(F("scan_wifi") == jsonIn[F("cmd")]) {
if(F("scan_wifi") == jsonIn[F("cmd")])
mApp->scanAvailNetworks();
}
else if(F("set_time") == jsonIn[F("cmd")])
mApp->setTimestamp(jsonIn[F("val")]);
else if(F("sync_ntp") == jsonIn[F("cmd")])

128
src/wifi/ahoywifi.cpp

@ -25,6 +25,8 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) {
mStaConn = DISCONNECTED;
mCnt = 0;
mScanActive = false;
mLastApClients = 0;
mScanCnt = 0;
#if defined(ESP8266)
wifiConnectHandler = WiFi.onStationModeConnected(std::bind(&ahoywifi::onConnect, this, std::placeholders::_1));
@ -64,33 +66,79 @@ void ahoywifi::tickWifiLoop() {
#if !defined(AP_ONLY)
if(mStaConn != GOT_IP) {
if (WiFi.softAPgetStationNum() > 0) { // do not reconnect if any AP connection exists
mDns.processNextRequest();
if((WIFI_AP_STA == WiFi.getMode()) && !mScanActive) {
DBGPRINTLN(F("AP client connected"));
welcome(mApIp.toString());
WiFi.mode(WIFI_AP);
mAppWifiCb(true);
if(WIFI_AP_STA == WiFi.getMode()) {
// first time switch to AP Mode
if(mScanActive && (mLastApClients != WiFi.softAPgetStationNum()))
mScanActive = false;
// scan is finished
if(!mScanActive) {
WiFi.mode(WIFI_AP);
mDns.start(53, "*", mApIp);
}
// only once a client connects to AP
if(mLastApClients != WiFi.softAPgetStationNum()) {
mLastApClients = WiFi.softAPgetStationNum();
WiFi.scanDelete();
mAppWifiCb(false);
DBGPRINTLN(F("AP client connected"));
welcome(mApIp.toString());
}
}
mDns.processNextRequest();
return;
}
else if(WIFI_AP == WiFi.getMode()) {
mLastApClients = 0;
mCnt = 0;
DPRINTLN(DBG_INFO, "DNS stop");
mDns.stop();
WiFi.mode(WIFI_AP_STA);
}
mCnt++;
uint8_t timeout = 10; // seconds
if (mStaConn == CONNECTED) // connected but no ip
timeout = 20;
if(!mScanActive && mBSSIDList.empty() && ((mCnt % timeout) == 0)) { // start scanning APs with the given SSID
DBGPRINT(F("scanning APs with SSID "));
DBGPRINTLN(String(mConfig->sys.stationSsid));
mScanCnt = 0;
mScanActive = true;
#if defined(ESP8266)
WiFi.scanNetworks(true, false, 0U, (uint8_t *)mConfig->sys.stationSsid);
#else
WiFi.scanNetworks(true, false, false, 300U, 0U, mConfig->sys.stationSsid);
#endif
return;
}
DBGPRINT(F("reconnect in "));
DBGPRINT(String(timeout-mCnt));
DBGPRINTLN(F(" seconds"));
if(mScanActive) {
getBSSIDs();
//if(!mScanActive) // scan completed
// if ((mCnt % timeout) < 8)
// mCnt = timeout - 2;
}
if((mCnt % timeout) == 0) { // try to reconnect after x sec without connection
if(mStaConn != CONNECTED)
mStaConn = CONNECTING;
WiFi.reconnect();
if(mBSSIDList.size() > 0) { // get first BSSID in list
DBGPRINT("try to connect to AP with BSSID:");
uint8_t bssid[6];
for (int j = 0; j < 6; j++) {
bssid[j] = mBSSIDList.front();
mBSSIDList.pop_front();
DBGPRINT(" " + String(bssid[j], HEX));
}
DBGPRINTLN("");
WiFi.disconnect();
WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]);
}
mCnt = 0;
}
}
@ -135,7 +183,7 @@ void ahoywifi::setupStation(void) {
if(!WiFi.config(ip, gateway, mask, dns1, dns2))
DPRINTLN(DBG_ERROR, F("failed to set static IP!"));
}
mStaConn = (WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd) != WL_CONNECTED) ? DISCONNECTED : CONNECTED;
mBSSIDList.clear();
if(String(mConfig->sys.deviceName) != "")
WiFi.hostname(mConfig->sys.deviceName);
WiFi.mode(WIFI_AP_STA);
@ -206,6 +254,15 @@ void ahoywifi::sendNTPpacket(IPAddress& address) {
mUdp.endPacket();
}
//-----------------------------------------------------------------------------
void ahoywifi::sortRSSI(int *sort, int n) {
for (int i = 0; i < n; i++)
sort[i] = i;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i]))
std::swap(sort[i], sort[j]);
}
//-----------------------------------------------------------------------------
void ahoywifi::scanAvailNetworks(void) {
@ -217,29 +274,50 @@ void ahoywifi::scanAvailNetworks(void) {
}
}
//-----------------------------------------------------------------------------
void ahoywifi::getAvailNetworks(JsonObject obj) {
JsonArray nets = obj.createNestedArray("networks");
int n = WiFi.scanComplete();
if (n < 0)
return;
if(n > 0) {
int sort[n];
for (int i = 0; i < n; i++)
sort[i] = i;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (WiFi.RSSI(sort[j]) > WiFi.RSSI(sort[i]))
std::swap(sort[i], sort[j]);
sortRSSI(&sort[0], n);
for (int i = 0; i < n; ++i) {
nets[i]["ssid"] = WiFi.SSID(sort[i]);
nets[i]["rssi"] = WiFi.RSSI(sort[i]);
nets[i]["ssid"] = WiFi.SSID(sort[i]);
nets[i]["rssi"] = WiFi.RSSI(sort[i]);
}
mScanActive = false;
WiFi.scanDelete();
}
mScanActive = false;
WiFi.scanDelete();
}
//-----------------------------------------------------------------------------
void ahoywifi::getBSSIDs() {
int n = WiFi.scanComplete();
if (n < 0){
mScanCnt++;
if (mScanCnt < 20)
return;
}
if(n > 0) {
mBSSIDList.clear();
int sort[n];
sortRSSI(&sort[0], n);
for (int i = 0; i < n; i++) {
DBGPRINT("BSSID " + String(i) + ":");
uint8_t *bssid = WiFi.BSSID(sort[i]);
for (int j = 0; j < 6; j++){
DBGPRINT(" " + String(bssid[j], HEX));
mBSSIDList.push_back(bssid[j]);
}
DBGPRINTLN("");
}
}
mScanActive = false;
WiFi.scanDelete();
}
//-----------------------------------------------------------------------------
void ahoywifi::connectionEvent(WiFiStatus_t status) {
@ -248,15 +326,19 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) {
if(mStaConn != CONNECTED) {
mStaConn = CONNECTED;
DBGPRINTLN(F("\n[WiFi] Connected"));
WiFi.mode(WIFI_STA);
DBGPRINTLN(F("[WiFi] AP disabled"));
mDns.stop();
}
break;
case GOT_IP:
mStaConn = GOT_IP;
if (mScanActive) { // maybe another scan has started
WiFi.scanDelete();
mScanActive = false;
}
welcome(WiFi.localIP().toString() + F(" (Station)"));
mDns.stop();
WiFi.mode(WIFI_STA);
DBGPRINTLN(F("[WiFi] AP disabled"));
mAppWifiCb(true);
break;

7
src/wifi/ahoywifi.h

@ -50,7 +50,8 @@ class ahoywifi {
void onWiFiEvent(WiFiEvent_t event);
#endif
void welcome(String msg);
void sortRSSI(int *sort, int n);
void getBSSIDs(void);
settings_t *mConfig;
appWifiCb mAppWifiCb;
@ -68,9 +69,9 @@ class ahoywifi {
uint8_t mLoopCnt;
bool mScanActive;
uint8_t mLastApClients;
uint8_t mScanCnt;
void sortRSSI(int *sort, int n);
void getBSSIDs(void);
std::list<uint8_t> mBSSIDList;
};

Loading…
Cancel
Save