ESPHome + micro Onduleur SG300W

Bonjour a tous,

J’ai un panneau solaire avec un micro-onduleur SG300W dont les statistiques de production sont disponibles par un lien UART à 2.4GHz.
Une librairie arduino existe : https://github.com/atc1441/NETSGPClient/
J’avais fait un sketch arduino mais je voulais publier les infos dans HA.
Au niveau materiel, on utilise un module LC12S
Par exemple : https://www.satistronics.com/shop/product/180300-lc12s-uart-wireless-serial-transparent-transmition-128-channel-module-9312

Je partage le code que j’ai écris pour une cible WemosD1 mini + OLED 64x48 et qui est certainement perfectible :slight_smile:

rx-sg300w.yaml

esphome:
  name: rx-sg300w
  includes:
    - SG300W.h

  libraries:
    - NETSGPClient
    - EspSoftwareSerial


esp8266:
  board: d1_mini

# Enable logging
logger:
  level: DEBUG 
  baud_rate: 115200

# Enable Home Assistant API
api:

ota:
  password: "xxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: x.x.x.x
    gateway: x.x.x.x
    subnet: x.x.x.x
  output_power: 10dB
  fast_connect: true
  power_save_mode: HIGH

web_server:
  port: 80

captive_portal:

font:
  - file: "fonts/FreeSans.ttf"
    id: Free_font
    size: 10
  - file: "fonts/LiberationSans.ttf"
    id: Lib_font
    size: 10

i2c:
  sda: D2
  scl: D1

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    reset_pin: D0
    address: 0x3C
    id: my_display
    pages:
    - id: page1
      lambda: |-
          it.printf(0, 0, id(Free_font), "Production PV");
          it.printf(0, 11, id(Lib_font), "Vdc = %.1f V", id(pv_vdc).state);
          it.printf(0, 22, id(Lib_font), "Adc = %.1f A", id(pv_adc).state);
          it.printf(0, 33, id(Lib_font), "Wdc = %.1f W", id(pv_wdc).state);
    - id: page2
      lambda: |-
          it.printf(0, 0, id(Free_font), "Production AC");
          it.printf(0, 11, id(Lib_font), "Vac = %.1f V", id(pv_vac).state);
          it.printf(0, 22, id(Lib_font), "Aac = %.1f A", id(pv_aac).state);
          it.printf(0, 33, id(Lib_font), "Wac = %.1f W", id(pv_wac).state);
    - id: page3
      lambda: |-
          it.printf(0, 0, id(Free_font), "Rendement");
          it.printf(0, 22, id(Lib_font), "R = %.1f%%", id(pv_rend).state);
    - id: page4
      lambda: |-
          it.print(0, 0, id(Free_font), "Prod. Totale");
          it.printf(0, 22, id(Lib_font), "Wac = %.1f kW", id(pv_totalkW).state);
    - id: page5
      lambda: |-
          it.print(0, 0, id(Free_font), "Temp");
          it.printf(30, 22, id(Lib_font), "%d °C", id(pv_temp).state);

interval:
  - interval: 3s
    then:
      - display.page.show_next: my_display
      - component.update: my_display

sensor:
- platform: custom
  lambda: |-
    auto my_custom = new customUartSg300w();
    App.register_component(my_custom);
    return {my_custom->Vdc_sensor, my_custom->Adc_sensor, my_custom->Wdc_sensor, my_custom->Vac_sensor, my_custom->Aac_sensor, my_custom->Wac_sensor,  my_custom->Wtot_sensor,  my_custom->Temp_sensor,  my_custom->Rend_sensor};
  sensors:
  - name: "Vdc"
    unit_of_measurement: V
    accuracy_decimals: 1
    id: pv_vdc
    
  - name: "Adc"
    unit_of_measurement: A
    accuracy_decimals: 2
    id: pv_adc
    
  - name: "Wdc"
    unit_of_measurement: W
    accuracy_decimals: 1
    id: pv_wdc
    
  - name: "Vac"
    unit_of_measurement: V
    accuracy_decimals: 1
    id: pv_vac
    
  - name: "Aac"
    unit_of_measurement: A
    accuracy_decimals: 1
    id: pv_aac
    
  - name: "Wac"
    unit_of_measurement: V
    accuracy_decimals: 1
    id: pv_wac
    
  - name: "Total_kW"
    unit_of_measurement: kW
    accuracy_decimals: 1
    id: pv_totalkW
    
  - name: "Temp"
    unit_of_measurement: "°C"
    id: pv_temp
    
  - name: "Rendement"
    unit_of_measurement: "%"
    accuracy_decimals: 1
    id: pv_rend

SG300W.h

#include "esphome.h"
#include "NETSGPClient.h"
#include <SoftwareSerial.h>

#define NETSGP_BUFFER_LENGTH 32
#define LC12S_PROG_PIN 13
#define LC12S_RX_PIN 14
#define LC12S_TX_PIN 12
#define LC12S_BAUDS 9600
#define inverterID xxxx 

#define INTERVAL 10

class customUartSg300w : public Component, public Sensor {

 public:
    Sensor *Vdc_sensor = new Sensor();
    Sensor *Adc_sensor = new Sensor();
    Sensor *Wdc_sensor = new Sensor();
    Sensor *Vac_sensor = new Sensor();
    Sensor *Aac_sensor = new Sensor();
    Sensor *Wac_sensor = new Sensor();
    Sensor *Wtot_sensor = new Sensor();
    Sensor *Temp_sensor = new Sensor();
    Sensor *Rend_sensor = new Sensor();

//----------------------------------------------------------------------------
    customUartSg300w() {
    ESP_LOGD("customUartSg300w", "*******************");
    ESP_LOGD("customUartSg300w", " Constructor");
    Ser2 = new SoftwareSerial;
    Ser2->begin(LC12S_BAUDS, SWSERIAL_8N1, LC12S_RX_PIN, LC12S_TX_PIN, false);
    clientNETSGP = new NETSGPClient(*Ser2, LC12S_PROG_PIN);
    ESP_LOGD("customUartSg300w", "*******************");
}
  
//----------------------------------------------------------------------------
  void setup() override {
    ESP_LOGD("customUartSg300w", "*******************");
    ESP_LOGD("customUartSg300w", " Setup");
    currentMillis = millis();
    lastSendMillis = millis();
    delay(1000);
    if (!clientNETSGP->setDefaultRFSettings()) {
        ESP_LOGD("customUartSg300w", "*** Could not set RF module to default settings ***");
    } else {
        ESP_LOGD("customUartSg300w", "Connection to RF Module LC12S: OK");
    }
    this->getSettings();
    ESP_LOGD("customUartSg300w", "*******************");
  }

  //----------------------------------------------------------------------------
  void loop() override {
      currentMillis = millis();
      if (currentMillis - lastSendMillis > INTERVAL * 1000) // interrogation INTERVAL sec
      {
        lastSendMillis = currentMillis;
        this->getStatus();
        this->publishSensors();
      }
    }
    
  //----------------------------------------------------------------------------
    void getSettings() {
        LC12S_settings  = clientNETSGP->readRFModuleSettings();
        ESP_LOGD("customUartSg300w", "\n Module LC12S Settings:  ");
        ESP_LOGD("customUartSg300w", "moduleID:  %X ", LC12S_settings.moduleID);
        ESP_LOGD("customUartSg300w", "networkID: %d ", LC12S_settings.networkID);
        ESP_LOGD("customUartSg300w", "rfChannel: %d ", LC12S_settings.rfChannel);
        ESP_LOGD("customUartSg300w", "valid:     %d ", LC12S_settings.valid);
        ESP_LOGD("customUartSg300w", "rfPower:   %d ", LC12S_settings.rfPower);
        ESP_LOGD("customUartSg300w", "baudrate:  %d ", LC12S_settings.baudrate);
    }
    
  //----------------------------------------------------------------------------
    void getStatus() {
        status = clientNETSGP->getStatus(inverterID);
        if (status.valid) {
            ESP_LOGD("customUartSg300w", "-------------------------------------");
            ESP_LOGD("customUartSg300w", "Status Valid");
            ESP_LOGD("customUartSg300w", "State: %d", status.state);
            ESP_LOGD("customUartSg300w", "Vdc = %.1fV",status.dcVoltage);
            ESP_LOGD("customUartSg300w", "Adc = %.1fA",status.dcCurrent);
            ESP_LOGD("customUartSg300w", "Wdc = %.1fW",status.dcPower);
            ESP_LOGD("customUartSg300w", "Vac = %.1fV",status.acVoltage);
            ESP_LOGD("customUartSg300w", "Aac = %.1fA",status.acCurrent);
            ESP_LOGD("customUartSg300w", "Wac = %.1fw",status.acPower);
            ESP_LOGD("customUartSg300w", "TotW= %.1fW",status.totalGeneratedPower);
            ESP_LOGD("customUartSg300w", "Temp= %d°C",status.temperature);
        } else {
            ESP_LOGD("customUartSg300w", "Status Non Valid");
        }
    }
  
  //----------------------------------------------------------------------------
    void publishSensors() {
            Vdc_sensor->publish_state(status.dcVoltage);
            Adc_sensor->publish_state(status.dcCurrent);
            Wdc_sensor->publish_state(status.dcPower);
            Vac_sensor->publish_state(status.acVoltage);
            Aac_sensor->publish_state(status.acCurrent);
            Wac_sensor->publish_state(status.acPower);
            Wtot_sensor->publish_state(status.totalGeneratedPower);
            Temp_sensor->publish_state((uint8_t)status.temperature);
            if (status.dcPower > 0) { 
                Rend_sensor->publish_state(100*(status.dcPower - status.acPower)/status.dcPower);
            } else {
                Rend_sensor->publish_state(0);
            }
    }

//----------------------------------------------------------------------------
  private:
    char buffer[NETSGP_BUFFER_LENGTH];
    SoftwareSerial * Ser2;
    NETSGPClient * clientNETSGP;
    NETSGPClient::InverterStatus status;
    LC12S::Settings LC12S_settings;
    uint32_t lastSendMillis;
    uint32_t currentMillis;
};