Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerLimit Regelung via MQTT mit separatem ESP #618

Merged
merged 280 commits into from
Mar 27, 2023
Merged

PowerLimit Regelung via MQTT mit separatem ESP #618

merged 280 commits into from
Mar 27, 2023

Conversation

SeibeGitHub
Copy link

HoymilesPowerlimit.zip

Anbei ein kleines Projekt, wo ein HM1500 Automatisch auf einen gewünschten Einspeisewert via MQTT limitiert, es
wird hierzu ein separater ESP benötigt und die Daten (Wunsch Limit, Aktueller Gesamtbezug Netz, Aktuelle Inverter AC Leistung) müssen via MQTT bereitgestellt werden. Das Programm läuft für sich auf einem ESP. Es entspricht sicher nicht eurem Programmierstil :-)

included alarm ID parse to serial console (in development)
improved `isAvailable`, checkes all record structs, inverter becomes available more early because version is check first
fix tickers were not set if NTP is not available
disabled annoying `FlashStringHelper` it gives randomly Expeptions during development, feels more stable since then
moved erase button to the bottom in settings, not nice but more functional
split `tx_count` to `tx_cnt` and `retransmits` in `system.html`
fix mqtt retransmit IP address #602
added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console)
…idn't start in the morning

reenabled FlashStringHelper because of lacking RAM
complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup
…er) #620

added rotate display feature #619
improved Prometheus endpoint #615, thx to fsck-block
@stefan123t
Copy link
Collaborator

stefan123t commented Jan 25, 2023

@SeibeGitHub jetzt habe ich es kapiert:
Du hast einfach das Zip mit Deinem Arduino Code HoymilesPowerLimit.ino an Deinen Kommentar angehängt und das alles in einem Pull Request.
Das ist ein bißchen unorthodox, so muss man den Code erstmal runterladen und auspacken um ihn anzusehen ... 😉

@lumapu können wir mit dem Code in HoymilesPowerLimit.ino (siehe unter Details) und FB_GleitenderMittelwertFilter.cpp/.h etwas anfangen ?

**HoymilesPowerLimit.ino**

// In Zeile 11 Eintrag des Inverters und in Zeile 14-16 WIFI & MQTT Eintragen


#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include "FB_GleitenderMittelwertFilter.h"

#define LED LED_BUILTIN //D4 GPIO 2
#define MAXInverterPower 1500.0f  // Hoymiles HM-1500 
 
// wlan param FritzBox
const char* ssid = "Router"; // Hier eure wifi ssid
const char* password = "WIFIPasswort"; // Hier euer wifi passwort
const char* MQQTBroker = "192.168.2.122"; // Hier euer MQTT Broker Port 8123 ist fest weiter uunen eingestellt

WiFiClient wlanclient;
PubSubClient mqttClient(wlanclient);

// ------------------------
// ###### Global Var ######
// ------------------------

int WifiFault;
bool WifiNewConnected;
int WifiReconnect=0;

static bool StartupDone;
static bool MqttReconnect;
static bool MqttSendReconnect;
static unsigned long T_MqttReconnected;
static float PowerLimt;   // Soll Einspeise Limit, ein Wert von +100 begrenzt auf 100Watt Netzeinspeisung (-100W Gesamtbezug) ein Wert von -100 begrenzt auf einen Bezug von 100W (Gesamtbezug +100W)  
static float AktGesamtbezug; // Aktueller Bezug aus dem Netz aller 3 Phasen wird alle 20Sekunden via MQTT bereitgestellt
static bool bNewGesamtbezug; // Neuer Wert vorhanden
static float AktPVLeistung; // Aktuelle erzeugte PV Leistung wird alle 15 Sekunden von AHOY via MQTT bereitgestellt
static bool bNewPVLeistung; // Neuer Wert vorhanden

static float fPowerLimitProz; // Prozentuales Powerlimit des Inverters
static float fPowerLimitProzOld;
FB_GleitenderMittelwertFilter GleitenderMittelwertBezug; // Mittelwert des Gesamtbezugs
FB_GleitenderMittelwertFilter GleitenderMittelwertPV; // Mittelwert des Gesamtbezugs

// ------------------------
// ###### Setup ######
// ------------------------

void setup() {
  Serial.begin (115200);
  Serial.println("\r\n");

  uint32_t realSize = ESP.getFlashChipRealSize();
  Serial.printf("Reale Flash groesse : %u", realSize);
  Serial.println(" Byte");
  uint32_t ideSize = ESP.getFlashChipSize();
  Serial.printf("IDE Flash groesse   : %u", ideSize);
  Serial.println(" Byte");
  
  //ESP.wdtDisable();//SW Watchdog abschalten, dieser wird bei jedem Loop neustart und delay neu gestartet somit kann auch delay(0) beutzt werden

  String newHostname = "AhoyLimiter";
  WiFi.hostname(newHostname.c_str());
  WiFi.begin(ssid, password);
  WiFi.setAutoReconnect(true); // ist default eh schon auf true
  WiFiConnect();
  ArduinoOTA.setHostname("OTA_AhoyLimiter");
  //  ArduinoOTA.setPassword("OTA_AhoyLimiter"); // Wenn zum download ein Passwort abgefragt werden soll
  ArduinoOTA.begin();


  mqttClient.setServer (MQQTBroker,1883);// Hier euer MQTT Broker
  mqttClient.setCallback(mqttCallback);

  if(mqttClient.connect ("AhoyLimiter-Client",NULL,NULL)) {

    Serial.println ("Connected to MQTT Broker");
    mqttClient.publish("AhoyLimiter-Client","Connected");
  } else {
    Serial.print("MQTT Broker connection failed");
    Serial.print (mqttClient.state());
    delay(200);
  }

// auf diese Topics wird gehört
  mqttClient.subscribe("HomeAssistant/Solar/Limit");  // Eingabe des Max Einspeiselimits 
  mqttClient.subscribe("HomeAssistant/Shelly3EM/Gesamtbezug");// Aktueller Gesamtbezug aller 3 Phasen des Hauses
  mqttClient.subscribe("inverter/Markise/ch0/P_AC");// Aktuelle PV Leistung

}

// ------------------------
// ###### Loop ######
// ------------------------

void loop() {
  ArduinoOTA.handle();
  delay(0);//Resetet den WD Timer
  WiFiConnect();
  if (!mqttClient.connected()) {
    mqttClient.setCallback(mqttCallback);
    Serial.println("Try Mqtt Connection");
    MqttReconnect=true;
    mqttClient.connect ("AhoyLimiter-Client",NULL,NULL);
  }
  else
  {
    mqttClient.loop();
    if (MqttReconnect){
      MqttReconnect=false;
      T_MqttReconnected=millis();
      MqttSendReconnect=true;
    }
  }

  if ((millis()-T_MqttReconnected)>3000 && MqttSendReconnect){
      MqttSendReconnect=false;
      mqttClient.publish("AhoyLimiter-Client","Connected");
  }

  
  GleitenderMittelwertBezug.Code(bNewGesamtbezug, AktGesamtbezug, 5);// Enable erst wenn Abschaltpunkt gefordert
  GleitenderMittelwertPV.Code(bNewPVLeistung, AktPVLeistung, 3);// Enable erst wenn Abschaltpunkt gefordert

  if (bNewGesamtbezug && GleitenderMittelwertPV.OMittelwert>0){
    Serial.print("Mittelwert Gesamtbezug: ");
    Serial.println(GleitenderMittelwertBezug.OMittelwert,2);
    fPowerLimitProz=min(100.0,(100.0/MAXInverterPower)*(GleitenderMittelwertPV.OMittelwert+(GleitenderMittelwertBezug.OMittelwert+PowerLimt)));// auf 100% begrenzen
    fPowerLimitProz=max(fPowerLimitProz,100.0f/MAXInverterPower*50.0f); // Nicht weniger als 50 W zulassen
    Serial.print("PowerLimit %: ");
    Serial.println(fPowerLimitProz);
    bNewGesamtbezug=false;
  }
  if (bNewPVLeistung){
    Serial.print("Mittelwert PV Leistung: ");
    Serial.println(GleitenderMittelwertPV.OMittelwert,2);
    bNewPVLeistung=false;
  }

  if (abs(fPowerLimitProz-fPowerLimitProzOld)>2){
    char abc[12];
    snprintf (abc,11, "%.2f",fPowerLimitProz); //Zahl in Char Array um zu senden
    mqttClient.publish("inverter/ctrl/limit_nonpersistent_relative/0",abc);
    fPowerLimitProzOld=fPowerLimitProz;
    Serial.print("Sende Limit an Inverter: ");
    Serial.println(fPowerLimitProz,2);
  }

  
  StartupDone=true;
 }


// ------------------------
// ###### Mqtt Read ######
// ------------------------

void mqttCallback(char *topic, byte *payload, unsigned int length) {
  String str_topic = String(topic);//Char to String
  if (length>19)
  {
    Serial.println ("Message to long !!!!");
    length=19;
  }

  Serial.println ("Message arrived on Topic:");
  Serial.print (topic);
  Serial.print (" ");

  char message[20]={0x00};
    
  for(int i=0;i<length;i++)
  message[i]=(char)payload[i];

  message[length]=0x00;//NUL Terminierung
  //Serial.println (message);

// Payload in Zahl wandeln
  float Value;
  Value=atof(message);
  Serial.println (Value,2);
  

// Werte Zuordnen  
 if(str_topic.equals ("HomeAssistant/Solar/Limit")) {
    PowerLimt=Value;
    Serial.print("Powerlimit Soll: ");
    Serial.println(PowerLimt,2);
 }
 if(str_topic.equals ("HomeAssistant/Shelly3EM/Gesamtbezug")) {
    AktGesamtbezug=Value;
    bNewGesamtbezug=true;
    Serial.print("Akt. Gesamtbezug: ");
    Serial.println(AktGesamtbezug,2);
 }
 if(str_topic.equals ("inverter/Markise/ch0/P_AC")) {
    AktPVLeistung=Value;
    bNewPVLeistung=true;
    Serial.print("Akt. PV Leistung: ");
    Serial.println(AktPVLeistung,2);
 }

}




void WiFiConnect()
{
  while (WiFi.status() != WL_CONNECTED) { // so lange hier verweilen bis neu verbunden
    WifiNewConnected=true;
    delay(250);
    Serial.print(".");
    WifiFault++;
    if (WifiFault > 30)
    {
      WifiReconnect++;
      if (WifiReconnect>=20){
        ESP.restart(); 
      }
      WifiFault = 0;
      Serial.println("\r\nStartWifiAgain");
      //WiFi.setAutoReconnect(true); // ist default eh schon auf true
      //Serial.println(WiFi.getAutoReconnect());
      WiFi.disconnect();
      delay(500);
      WiFi.begin(ssid, password);
    }
    delay(250);
  }
  if (WifiNewConnected){
    WifiNewConnected=false;
    Serial.println("\r\nOnline");
    Serial.println("\nVerbunden mit: " + WiFi.SSID());
    Serial.println("Esp8266 IP: " + WiFi.localIP().toString());
    Serial.println("Esp8266 GW: " + WiFi.gatewayIP().toString());
    WiFi.persistent(true);
   }
}

@Adminius
Copy link

ich will jetzt keinen Spaßverderber sein... https://github.com/berni2288/OpenDTU_PowerLimiter
Da funktioniert es schon erstaunlich gut.
Wenn mir noch jemand erklärt was der Unterschied zwischen Ahoy und OpenDTU ist und warum man 2 getrennte Wege geht, wäre ich echt dankbar.

markusdd and others added 29 commits March 26, 2023 14:39
* merge: PR SPI pins configureable (ESP32) #807
* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805
* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805
(@knickohr|s erster codebeitrag, er ist stolz wie bolle)
* reduced heap fragmentation by optimizing MqTT #768
* reduced heap fragmentation by optimizing MqTT #768
* ePaper: centered text thx @knickohr
something missing?
+ add better readable table.
- remove discord topic, double effort here... in the main site already there
Not tested yet, but compiled on 0.5.107.

So no urgent check in is required, but most likely this will perform more consistent than the previous version.
* MQTT fix reconnection by new lib version #780
* display 'failed' if no Update was selected #813
* MQTT fix reconnection by new lib version #780
* add `about` page
* MQTT fix reconnection by new lib version #780
* add `about` page
* improved documentation regarding SPI pins #814
* improved documentation (getting started) #815 #816
* improved MI 4-ch inverter #820
@lumapu lumapu merged commit 9c7d7a0 into main Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet