diff --git a/tools/esp8266/README.md b/tools/esp8266/README.md
index 57066fc0..4d02eec1 100644
--- a/tools/esp8266/README.md
+++ b/tools/esp8266/README.md
@@ -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
\ No newline at end of file
diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp
index d45baa62..428f3dd2 100644
--- a/tools/esp8266/app.cpp
+++ b/tools/esp8266/app.cpp
@@ -154,7 +154,7 @@ void app::setup(uint32_t timeout) {
 
         mMqtt.setup(addr, mqttTopic, mqttUser, mqttPwd, mqttPort);
         mMqttTicker = 0;
-
+        
         mSerialTicker = 0;
 
         if(mqttAddr[0] > 0) {
@@ -284,6 +284,7 @@ void app::loop(void) {
                 }
             }
             snprintf(val, 10, "%d", millis()/1000);
+            sendMqttDiscoveryConfig();
             mMqtt.sendMsg("uptime", val);
         }
 
@@ -904,3 +905,61 @@ 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);
+
+                    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;
+                    if (devCls != NULL) {
+                        doc["dev_cla"] = devCls;
+                    }
+
+                    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];
+}
diff --git a/tools/esp8266/app.h b/tools/esp8266/app.h
index 1970ed7d..ef14b9b2 100644
--- a/tools/esp8266/app.h
+++ b/tools/esp8266/app.h
@@ -8,6 +8,7 @@
 
 #include <RF24.h>
 #include <RF24_config.h>
+#include <ArduinoJson.h>
 
 #include "defines.h"
 #include "main.h"
@@ -73,6 +74,8 @@ class app : public Main {
 
         void saveValues(bool webSend);
         void updateCrc(void);
+        void sendMqttDiscoveryConfig(void);
+        const char* getFieldDeviceClass(uint8_t fieldId);
 
         uint64_t Serial2u64(const char *val) {
             char tmp[3] = {0};
@@ -116,6 +119,7 @@ class app : public Main {
         uint16_t mMqttTicker;
         uint16_t mMqttInterval;
         bool mMqttActive;
+        bool mMqttConfigSendState[MAX_NUM_INVERTERS];
 
         // serial
         uint16_t mSerialTicker;
diff --git a/tools/esp8266/defines.h b/tools/esp8266/defines.h
index 8861bab9..b5471678 100644
--- a/tools/esp8266/defines.h
+++ b/tools/esp8266/defines.h
@@ -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
diff --git a/tools/esp8266/hmDefines.h b/tools/esp8266/hmDefines.h
index 38a2fc4e..3594c2f7 100644
--- a/tools/esp8266/hmDefines.h
+++ b/tools/esp8266/hmDefines.h
@@ -27,6 +27,29 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
 const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
         "U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Effiency", "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"};
+typedef struct {
+    uint8_t    fieldId; // field id
+    uint8_t    deviceClsId;  // device class
+} byteAssign_fieldDeviceClass;
+const byteAssign_fieldDeviceClass deviceFieldAssignment[] = {
+    {FLD_UDC, DEVICE_CLS_VOLTAGE},
+    {FLD_IDC, DEVICE_CLS_CURRENT},
+    {FLD_PDC, DEVICE_CLS_PWR},
+    {FLD_YD, DEVICE_CLS_ENERGY},
+    {FLD_YW, DEVICE_CLS_ENERGY},
+    {FLD_YT, DEVICE_CLS_ENERGY},
+    {FLD_UAC, DEVICE_CLS_VOLTAGE},
+    {FLD_IAC, DEVICE_CLS_CURRENT},
+    {FLD_PAC, DEVICE_CLS_PWR},
+    {FLD_F, DEVICE_CLS_FREQ},
+    {FLD_T, DEVICE_CLS_TEMP},
+    {FLD_EFF, DEVICE_CLS_NONE},
+    {FLD_IRR, DEVICE_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};
diff --git a/tools/esp8266/mqtt.h b/tools/esp8266/mqtt.h
index 79dbecc5..9b2eff49 100644
--- a/tools/esp8266/mqtt.h
+++ b/tools/esp8266/mqtt.h
@@ -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);
             }
         }