Browse Source

Merge pull request #85 from KG3RK3N/mqtt_discovery

MQTT Auto Discovery Unterstützung (ESP8266)
pull/97/head
lumapu 2 years ago
committed by GitHub
parent
commit
b7cfe3e6ca
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      tools/esp8266/README.md
  2. 72
      tools/esp8266/app.cpp
  3. 5
      tools/esp8266/app.h
  4. 14
      tools/esp8266/defines.h
  5. 29
      tools/esp8266/hmDefines.h
  6. 12
      tools/esp8266/mqtt.h

2
tools/esp8266/README.md

@ -16,6 +16,7 @@ This code can be compiled using Arduino. The settings were:
- Time Arduino Time library (TimeLib.h) - Time Arduino Time library (TimeLib.h)
- RF24 Optimized high speed nRF24L01+ driver class documentation - RF24 Optimized high speed nRF24L01+ driver class documentation
- PubSubClient A client library for MQTT messaging. By Nick O'Leary - PubSubClient A client library for MQTT messaging. By Nick O'Leary
- ArduinoJson Arduino Json library
### Optional Configuration before compilation ### Optional Configuration before compilation
@ -65,3 +66,4 @@ For now the following inverters should work out of the box:
- `Time` 1.6.1 - `Time` 1.6.1
- `RF24` 1.4.2 - `RF24` 1.4.2
- `PubSubClient` 2.8 - `PubSubClient` 2.8
- `ArduinoJson` 6.19.4

72
tools/esp8266/app.cpp

@ -284,6 +284,7 @@ void app::loop(void) {
} }
} }
snprintf(val, 10, "%d", millis()/1000); snprintf(val, 10, "%d", millis()/1000);
sendMqttDiscoveryConfig();
mMqtt.sendMsg("uptime", val); mMqtt.sendMsg("uptime", val);
} }
@ -904,3 +905,74 @@ void app::updateCrc(void) {
DPRINTLN(DBG_DEBUG, F("new CRC: ") + String(crc, HEX)); DPRINTLN(DBG_DEBUG, F("new CRC: ") + String(crc, HEX));
mEep->write(ADDR_SETTINGS_CRC, crc); mEep->write(ADDR_SETTINGS_CRC, crc);
} }
void app::sendMqttDiscoveryConfig(void) {
DPRINTLN(DBG_VERBOSE, F("app::sendMqttDiscoveryConfig"));
char stateTopic[64], discoveryTopic[64], buffer[512], name[32], uniq_id[32];
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
Inverter<> *iv = mSys->getInverterByPos(id);
if(NULL != iv) {
if(iv->isAvailable(mTimestamp) && mMqttConfigSendState[id] != true) {
DynamicJsonDocument deviceDoc(128);
deviceDoc["name"] = iv->name;
deviceDoc["ids"] = String(iv->serial.u64, HEX);
deviceDoc["cu"] = F("http://") + String(WiFi.localIP().toString());
JsonObject deviceObj = deviceDoc.as<JsonObject>();
DynamicJsonDocument doc(384);
for(uint8_t i = 0; i < iv->listLen; i++) {
if (iv->assign[i].ch == CH0) {
snprintf(name, 32, "%s %s", iv->name, iv->getFieldName(i));
} else {
snprintf(name, 32, "%s CH%d %s", iv->name, iv->assign[i].ch, iv->getFieldName(i));
}
snprintf(stateTopic, 64, "%s/%s/ch%d/%s", mMqtt.getTopic(), iv->name, iv->assign[i].ch, iv->getFieldName(i));
snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->name, iv->assign[i].ch, iv->getFieldName(i));
snprintf(uniq_id, 32, "ch%d_%s", iv->assign[i].ch, iv->getFieldName(i));
const char* devCls = getFieldDeviceClass(iv->assign[i].fieldId);
const char* stateCls = getFieldStateClass(iv->assign[i].fieldId);
doc["name"] = name;
doc["stat_t"] = stateTopic;
doc["unit_of_meas"] = iv->getUnit(i);
doc["uniq_id"] = String(iv->serial.u64, HEX) + "_" + uniq_id;
doc["dev"] = deviceObj;
doc["exp_aft"] = mMqttInterval + 5; // add 5 sec if connection is bad or ESP too slow
if (devCls != NULL) {
doc["dev_cla"] = devCls;
}
if (stateCls != NULL) {
doc["stat_cla"] = stateCls;
}
serializeJson(doc, buffer);
mMqtt.sendMsg2(discoveryTopic, buffer);
doc.clear();
yield();
}
mMqttConfigSendState[id] = true;
}
}
}
}
const char* app::getFieldDeviceClass(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];
}
const char* app::getFieldStateClass(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 : stateClasses[deviceFieldAssignment[pos].stateClsId];
}

5
tools/esp8266/app.h

@ -8,6 +8,7 @@
#include <RF24.h> #include <RF24.h>
#include <RF24_config.h> #include <RF24_config.h>
#include <ArduinoJson.h>
#include "defines.h" #include "defines.h"
#include "main.h" #include "main.h"
@ -73,6 +74,9 @@ class app : public Main {
void saveValues(bool webSend); void saveValues(bool webSend);
void updateCrc(void); void updateCrc(void);
void sendMqttDiscoveryConfig(void);
const char* getFieldDeviceClass(uint8_t fieldId);
const char* getFieldStateClass(uint8_t fieldId);
uint64_t Serial2u64(const char *val) { uint64_t Serial2u64(const char *val) {
char tmp[3] = {0}; char tmp[3] = {0};
@ -116,6 +120,7 @@ class app : public Main {
uint16_t mMqttTicker; uint16_t mMqttTicker;
uint16_t mMqttInterval; uint16_t mMqttInterval;
bool mMqttActive; bool mMqttActive;
bool mMqttConfigSendState[MAX_NUM_INVERTERS];
// serial // serial
uint16_t mSerialTicker; uint16_t mSerialTicker;

14
tools/esp8266/defines.h

@ -50,12 +50,14 @@ typedef struct {
#define RF24_AMP_PWR_LEN 1 #define RF24_AMP_PWR_LEN 1
#define MQTT_ADDR_LEN 4 // IP #define MQTT_ADDR_LEN 4 // IP
#define MQTT_USER_LEN 16 #define MQTT_USER_LEN 16
#define MQTT_PWD_LEN 32 #define MQTT_PWD_LEN 32
#define MQTT_TOPIC_LEN 32 #define MQTT_TOPIC_LEN 32
#define MQTT_INTERVAL_LEN 2 // uint16_t #define MQTT_INTERVAL_LEN 2 // uint16_t
#define MQTT_PORT_LEN 2 // uint16_t #define MQTT_PORT_LEN 2 // uint16_t
#define MQTT_DISCOVERY_PREFIX "homeassistant"
#define MQTT_MAX_PACKET_SIZE 384
#define SER_ENABLE_LEN 1 // uint8_t #define SER_ENABLE_LEN 1 // uint8_t
#define SER_DEBUG_LEN 1 // uint8_t #define SER_DEBUG_LEN 1 // uint8_t

29
tools/esp8266/hmDefines.h

@ -25,8 +25,35 @@ const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%"};
enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF, FLD_IRR}; FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF, FLD_IRR};
const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
"U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Effiency", "Irradiation"}; "U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Efficiency", "Irradiation"};
// 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};
const char* const deviceClasses[] = {0, "current", "energy", "power", "voltage", "frequency", "temperature"};
enum {STATE_CLS_NONE = 0, STATE_CLS_MEASUREMENT, STATE_CLS_TOTAL_INCREASING};
const char* const stateClasses[] = {0, "measurement", "total_increasing"};
typedef struct {
uint8_t fieldId; // field id
uint8_t deviceClsId; // device class
uint8_t stateClsId; // state class
} byteAssign_fieldDeviceClass;
const byteAssign_fieldDeviceClass deviceFieldAssignment[] = {
{FLD_UDC, DEVICE_CLS_VOLTAGE, STATE_CLS_MEASUREMENT},
{FLD_IDC, DEVICE_CLS_CURRENT, STATE_CLS_MEASUREMENT},
{FLD_PDC, DEVICE_CLS_PWR, STATE_CLS_MEASUREMENT},
{FLD_YD, DEVICE_CLS_ENERGY, STATE_CLS_TOTAL_INCREASING},
{FLD_YW, DEVICE_CLS_ENERGY, STATE_CLS_TOTAL_INCREASING},
{FLD_YT, DEVICE_CLS_ENERGY, STATE_CLS_TOTAL_INCREASING},
{FLD_UAC, DEVICE_CLS_VOLTAGE, STATE_CLS_MEASUREMENT},
{FLD_IAC, DEVICE_CLS_CURRENT, STATE_CLS_MEASUREMENT},
{FLD_PAC, DEVICE_CLS_PWR, STATE_CLS_MEASUREMENT},
{FLD_F, DEVICE_CLS_FREQ, STATE_CLS_NONE},
{FLD_T, DEVICE_CLS_TEMP, STATE_CLS_MEASUREMENT},
{FLD_PCT, DEVICE_CLS_NONE, STATE_CLS_NONE},
{FLD_EFF, DEVICE_CLS_NONE, STATE_CLS_NONE},
{FLD_IRR, DEVICE_CLS_NONE, STATE_CLS_NONE}
};
#define DEVICE_CLS_ASSIGN_LIST_LEN (sizeof(deviceFieldAssignment) / sizeof(byteAssign_fieldDeviceClass))
// indices to calculation functions, defined in hmInverter.h // indices to calculation functions, defined in hmInverter.h
enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH}; enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH};

12
tools/esp8266/mqtt.h

@ -29,6 +29,7 @@ class mqtt {
DPRINTLN(DBG_VERBOSE, F("mqtt.h:setup")); DPRINTLN(DBG_VERBOSE, F("mqtt.h:setup"));
mAddressSet = true; mAddressSet = true;
mClient->setServer(broker, port); mClient->setServer(broker, port);
mClient->setBufferSize(MQTT_MAX_PACKET_SIZE);
mPort = port; mPort = port;
snprintf(mUser, MQTT_USER_LEN, "%s", user); snprintf(mUser, MQTT_USER_LEN, "%s", user);
@ -38,14 +39,17 @@ class mqtt {
void sendMsg(const char *topic, const char *msg) { void sendMsg(const char *topic, const char *msg) {
//DPRINTLN(DBG_VERBOSE, F("mqtt.h:sendMsg")); //DPRINTLN(DBG_VERBOSE, F("mqtt.h:sendMsg"));
if(mAddressSet) { char top[64];
char top[64]; snprintf(top, 64, "%s/%s", mTopic, topic);
snprintf(top, 64, "%s/%s", mTopic, topic); sendMsg2(top, msg);
}
void sendMsg2(const char *topic, const char *msg) {
if(mAddressSet) {
if(!mClient->connected()) if(!mClient->connected())
reconnect(); reconnect();
if(mClient->connected()) if(mClient->connected())
mClient->publish(top, msg); mClient->publish(topic, msg);
} }
} }

Loading…
Cancel
Save