mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-04 12:45:54 +02:00
Merge pull request #85 from KG3RK3N/mqtt_discovery
MQTT Auto Discovery Unterstützung (ESP8266)
This commit is contained in:
commit
b7cfe3e6ca
6 changed files with 123 additions and 11 deletions
|
@ -16,6 +16,7 @@ This code can be compiled using Arduino. The settings were:
|
|||
- Time Arduino Time library (TimeLib.h)
|
||||
- RF24 Optimized high speed nRF24L01+ driver class documentation
|
||||
- PubSubClient A client library for MQTT messaging. By Nick O'Leary
|
||||
- ArduinoJson Arduino Json library
|
||||
|
||||
### Optional Configuration before compilation
|
||||
|
||||
|
@ -65,3 +66,4 @@ For now the following inverters should work out of the box:
|
|||
- `Time` 1.6.1
|
||||
- `RF24` 1.4.2
|
||||
- `PubSubClient` 2.8
|
||||
- `ArduinoJson` 6.19.4
|
|
@ -284,6 +284,7 @@ void app::loop(void) {
|
|||
}
|
||||
}
|
||||
snprintf(val, 10, "%d", millis()/1000);
|
||||
sendMqttDiscoveryConfig();
|
||||
mMqtt.sendMsg("uptime", val);
|
||||
}
|
||||
|
||||
|
@ -904,3 +905,74 @@ void app::updateCrc(void) {
|
|||
DPRINTLN(DBG_DEBUG, F("new CRC: ") + String(crc, HEX));
|
||||
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];
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <RF24.h>
|
||||
#include <RF24_config.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "main.h"
|
||||
|
@ -73,6 +74,9 @@ class app : public Main {
|
|||
|
||||
void saveValues(bool webSend);
|
||||
void updateCrc(void);
|
||||
void sendMqttDiscoveryConfig(void);
|
||||
const char* getFieldDeviceClass(uint8_t fieldId);
|
||||
const char* getFieldStateClass(uint8_t fieldId);
|
||||
|
||||
uint64_t Serial2u64(const char *val) {
|
||||
char tmp[3] = {0};
|
||||
|
@ -116,6 +120,7 @@ class app : public Main {
|
|||
uint16_t mMqttTicker;
|
||||
uint16_t mMqttInterval;
|
||||
bool mMqttActive;
|
||||
bool mMqttConfigSendState[MAX_NUM_INVERTERS];
|
||||
|
||||
// serial
|
||||
uint16_t mSerialTicker;
|
||||
|
|
|
@ -50,12 +50,14 @@ typedef struct {
|
|||
|
||||
#define RF24_AMP_PWR_LEN 1
|
||||
|
||||
#define MQTT_ADDR_LEN 4 // IP
|
||||
#define MQTT_USER_LEN 16
|
||||
#define MQTT_PWD_LEN 32
|
||||
#define MQTT_TOPIC_LEN 32
|
||||
#define MQTT_INTERVAL_LEN 2 // uint16_t
|
||||
#define MQTT_PORT_LEN 2 // uint16_t
|
||||
#define MQTT_ADDR_LEN 4 // IP
|
||||
#define MQTT_USER_LEN 16
|
||||
#define MQTT_PWD_LEN 32
|
||||
#define MQTT_TOPIC_LEN 32
|
||||
#define MQTT_INTERVAL_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_DEBUG_LEN 1 // uint8_t
|
||||
|
|
|
@ -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,
|
||||
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",
|
||||
"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
|
||||
enum {CALC_YT_CH0 = 0, CALC_YD_CH0, CALC_UDC_CH, CALC_PDC_CH0, CALC_EFF_CH0, CALC_IRR_CH};
|
||||
|
|
|
@ -29,6 +29,7 @@ class mqtt {
|
|||
DPRINTLN(DBG_VERBOSE, F("mqtt.h:setup"));
|
||||
mAddressSet = true;
|
||||
mClient->setServer(broker, port);
|
||||
mClient->setBufferSize(MQTT_MAX_PACKET_SIZE);
|
||||
|
||||
mPort = port;
|
||||
snprintf(mUser, MQTT_USER_LEN, "%s", user);
|
||||
|
@ -38,14 +39,17 @@ class mqtt {
|
|||
|
||||
void sendMsg(const char *topic, const char *msg) {
|
||||
//DPRINTLN(DBG_VERBOSE, F("mqtt.h:sendMsg"));
|
||||
if(mAddressSet) {
|
||||
char top[64];
|
||||
snprintf(top, 64, "%s/%s", mTopic, topic);
|
||||
char top[64];
|
||||
snprintf(top, 64, "%s/%s", mTopic, topic);
|
||||
sendMsg2(top, msg);
|
||||
}
|
||||
|
||||
void sendMsg2(const char *topic, const char *msg) {
|
||||
if(mAddressSet) {
|
||||
if(!mClient->connected())
|
||||
reconnect();
|
||||
if(mClient->connected())
|
||||
mClient->publish(top, msg);
|
||||
mClient->publish(topic, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue