danjulio / MPPT-Solar-Charger

Supporting documentation and software for the MPPT Solar Charger
144 stars 33 forks source link

Strange behaviour when charging; shutting down output #2

Closed gon0 closed 4 years ago

gon0 commented 4 years ago

Dear danjulio, ich have 2 makerPowerSolar units. Here I a going to focus on the configuration which causes bigger problems. I read out the actual values via I2C and send them to my Grafana server via an ESP32. Here are the data for the solar panel (left side) and the battery (right side): grafik

Here is the complete data from today: grafik You can see that the makerPowerSolar shuts down power for the microcontroller sometimes (empty intervals). Also the sensor readings are spiking sometimes, showing impossible values. FLOAT = red IDLE = pink BULK = green SCAN = yellow I2C FAIL = orange

Before the night, I disconnected the solar panel, disconnected the battery. Then I connected the battery and connected the solar panel. The ESP32 was powered by the makerPowerSolar throughout the night: grafik

After the night, the charger goes from IDLE to SCAN to BULK. In BULK, the voltage and charge power rises. Then the power to the microcontroller is shut down (I do not read out the state of the ALARM-output yet) for no obvious reasons: grafik

Here is an excerpt from an interval during the cloudy day: grafik It can be seen that some of the spiking values are followed by I2C FAILs (orange bars), some are not.

I cannot really explain this behaviour. I did not change the configuration of the charger. You have any ideas on what I could investigate?

danjulio commented 4 years ago

Hello :

Sorry you are having troubles.

It is always very difficult to remotely diagnose problems because there are so many things to consider. So I can try to give you ideas to help debug. Thank you for including so much information.

  1. Battery + Solar panel look good!

  2. I did not test with ESP32 (only ESP8266 which uses software I2C). Can ESP32 I2C handle clock stretching by I2C slave. The charger does stretch the clock slightly during reads as it executes code to get the data for the I2C peripheral. I have seen some devices like the Raspberry Pi have trouble with this. Usually the clock stretch is very short but there are rare occasions where it might be a little longer. One thing to do might be to either attempt to qualify the values and re-read if they seam bad or always read twice and compare (maybe some values like voltage would have to be compared within a range since they might change reading to reading).

  3. It does not look like the charger should be shutting down its 5V output given the battery voltages in your charts. Is it possible to actually verify this physically using a DMM when it occurs? What is the values of the status register, the battery voltage register and the power-off voltage register? The status register will tell you if the charger thinks it has disabled the power output and it shouldn’t disable it unless the battery voltage falls below the power-off threshold (default 11.5 volts - but can be changed by code). If you are seeing I2C failures, is it possible the power-off threshold is being changed unexpectedly?

  4. Have you tried the second charger? Perhaps there is a hardware fault with the first board. For example a bad solder joint that opens when the board hits certain temperatures, etc.

I am sorry I cannot provide more detailed information but I am happy to try to answer further questions to help you debug this.

Regards, Dan

On Aug 27, 2020, at 1:15 PM, gon0 notifications@github.com wrote:

Dear danjulio, ich have 2 makerPowerSolar units. Here I a going to focus on the configuration which causes bigger problems. I read out the actual values via I2C and send them to my Grafana server via an ESP32. Here are the data for the solar panel (left side) and the battery (right side): https://user-images.githubusercontent.com/33236024/91483285-c4f82280-e8a7-11ea-8a52-3ad22bd20080.png Here is the complete data from today: https://user-images.githubusercontent.com/33236024/91483629-48b20f00-e8a8-11ea-8602-e92cad8050e1.png You can see that the makerPowerSolar shuts down power for the microcontroller sometimes (empty intervals). Also the sensor readings are spiking sometimes, showing impossible values. FLOAT = red IDLE = pink BULK = green SCAN = yellow I2C FAIL = orange

Before the night, I disconnected the solar panel, disconnected the battery. Then I connected the battery and connected the solar panel. The ESP32 was powered by the makerPowerSolar throughout the night: https://user-images.githubusercontent.com/33236024/91485040-7304cc00-e8aa-11ea-92ab-225ad7c76dfd.png After the night, the charger goes from IDLE to SCAN to BULK. In BULK, the voltage and charge power rises. Then the power to the microcontroller is shut down (I do not read out the state of the ALARM-output yet) for no obvious reasons: https://user-images.githubusercontent.com/33236024/91483938-ba8a5880-e8a8-11ea-9766-d9e823c1d5a5.png Here is an excerpt from an interval during the cloudy day: https://user-images.githubusercontent.com/33236024/91484332-55833280-e8a9-11ea-8707-458f12a17606.png It can be seen that some of the spiking values are followed by I2C FAILs (orange bars), some are not.

I cannot really explain this behaviour. I did not change the configuration of the charger. You have any ideas on what I could investigate?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/danjulio/MPPT-Solar-Charger/issues/2, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOB66SIG5EX2RO77GKMKGDSC2WG5ANCNFSM4QNKOGEQ.

gon0 commented 4 years ago

Dear Dan, thank you for your quick investigation.

  1. great!
  2. ok, I'll work on the code to read the vales und omit values which are not in a plausible range. Maybe I can get around investing too much time to do low-levelclock signal-debugging with an oscilloscope.
  3. I have measured the battery quite some times, but not exactly when the output was turned off. When I measured the battery voltage, the value was identical to the value from the makerPowerSolar. My idea was to read the state of the ALARM output, so I can get an indication from the charger. Do you think this might help? How do I read the status register, the battery voltage register and the power-off voltage register via arduino? How do I perform a firmware-upgrade if necessary?
  4. The second charger is connected to a second solar panel of the same type, but to a 7Ah battery. Here, it does never charge more than 1 W and shuts down the output on dawn. I think we should have a look at the first board since I tend to buy a second 17 Ah battery if the setup runs reliable.

Have a good day

danjulio commented 4 years ago

On Aug 28, 2020, at 10:37 AM, gon0 notifications@github.com wrote:

I have measured the battery quite some times, but not exactly when the output was turned off. When I measured the battery voltage, the value was identical to the value from the makerPowerSolar. My idea was to read the state of the ALARM output, so I can get an indication from the charger. Do you think this might help? How do I read the status register, the battery voltage register and the power-off voltage register via arduino? How do I perform a firmware-upgrade if necessary? If you haven’t already please read the user manual for a description of all the registers and their addresses. You can read the status register using the same I2C interface as the battery voltage. In my github there is a library for Arduino to simplify this.

The ALARM output will be asserted 60 seconds before the board removes power. It will be de-asserted when the board restores power.

There is no new firmware for the board but you would need a Silicon Labs C2 programmer contacting 4 test points on the underside of the board. You can see the programming interface in the schematic and the firmware itself is in the github repository. I used v4 of Simplicity Studio to compile it.

gon0 commented 4 years ago

Hi, thank you for your reply. I will have a look at reading the registers next weekend maybe.

Ok, since I don't have the programmer, the firmware update is out of scope for me.

At least I got stabe readings now. Maybe I have bombarded the makerPowerSolar with I2C requests, since the routine reading for new values ran directly in "loop". Now the ESP32 reads new values each 500 ms and puts the value in a running median array. This is how today with a sunny day looked like: grafik

It is strange that it was never charging more than 2 W although it was a clear sky and sunny. After 7 pm the ESP32 was cut from power again, although the battery voltage was 12.99 V. Maybe I'll find out more after reading the registers.

Cheers!

gon0 commented 4 years ago

Dear Dan, I now had the time to read out all the register values from the makerPowerSolar under direct sunlight:

Published status FLOAT
Published power = 0.75
Published vb = 14.08
Published ib = 20
Published temp = 21.10
register values SYS_ID:4114 SYS_BUCK:21058  VAL_IC:18   VAL_V_TH:14077  VAL_V_MPPT:20377    CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000    CFG_PWR_OFF_TH:13000    CFG_PWR_ON_TH:13000 isAlert:0   isNight:0   getWatchdogTimeout:255  getWatchdogPoweroff:65535   getWatchdogEnable:0

For me these values look quite ok.

These are the values from today with sunny sky: grafik

You can see that the output is switched on when enough sun intensity was available and switched off when the sun does not shine onto the solar panel. In the last 7 days it looked like this: grafik

EDIT:

I should have been taking more time on thinking. I makes sense to me now why the output was switched off, because the factory-set thresholds were quite high (PWR_OFF was at 13 V, I have set it to 11,5 V).

I have written an init-function to set lower thresholds:

void makerPowerSolar_init(){
  reg_CFG_PWR_OFF_TH = 11500;
  reg_CFG_PWR_ON_TH = 12500;
  (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH);
  (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);
}

This results in these values read out from the registers:

    Published status FLOAT  Published power = 0.63  Published vb = 14.08    Published ib = 20   Published temp = 20.60register values SYS_ID:4114   SYS_BUCK:17666  VAL_IC:12   VAL_V_TH:14087  VAL_V_MPPT:20838    CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000    CFG_PWR_OFF_TH:11500    CFG_PWR_ON_TH:12500 isAlert:0   isNight:0   getWatchdogTimeout:255  getWatchdogPoweroff:65535   getWatchdogEnable:0
register values SYS_ID:4114 SYS_BUCK:17666  VAL_IC:11   VAL_V_TH:14087  VAL_V_MPPT:20838    CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000    CFG_PWR_OFF_TH:11500    CFG_PWR_ON_TH:12500 isAlert:0   isNight:0   getWatchdogTimeout:255  getWatchdogPoweroff:65535   getWatchdogEnable:0

So, I am going to let it run for some days. With these changes I expect the makerPowerSolar to work as expected.

I am still wondering, why the charging power is not very high, but maybe the cause is a full battery.

Thank you for your support. I'll give a feedback after some testing.

gon0 commented 4 years ago

All of the posts above are regarding to my first makerPowerSolar, being used with a 17 Ah battery.

I have an additional question regarding my second makerPowerSolar:

I am using a Panasonic LC-R127R2PG1 12 V 7.2 AH Lead-Acid battery with the second makerPowerSolar. After using the same code and reading the register values, i noticed, that some values differ.

1st makerPower Solar, used with the above mentioned 17 Ah battery:
register values SYS_ID:4114 SYS_BUCK:17666  VAL_IC:11   VAL_V_TH:14087  VAL_V_MPPT:20838    CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000    CFG_PWR_OFF_TH:11500    CFG_PWR_ON_TH:12500 isAlert:0   isNight:0   getWatchdogTimeout:255  getWatchdogPoweroff:65535   getWatchdogEnable:0

2nd makerPower Solar, used with the mentioned 7 Ah battery in this post:
register values SYS_ID:4114 SYS_BUCK:6402   VAL_IC:-1   VAL_V_TH:13585  VAL_V_MPPT:20326    CFG_BUCK_V_TH:14700 CFG_FLOAT_V_TH:13650    CFG_PWR_OFF_TH:11500    CFG_PWR_ON_TH:12500 isAlert:0   isNight:0   getWatchdogTimeout:0    getWatchdogPoweroff:10  getWatchdogEnable:0

It can be seen, that both makerPowerSolars have different values for CFG_BUCK_V_TH and CFG_FLOAT_V_TH. What values would you recommend for each battery?

danjulio commented 4 years ago

A couple of things stand out.

In the previous email you showed: CFG_PWR_OFF_TH:13000 CFG_PWR_ON_TH:13000 This means the system will shut down at 13 Volts!

In this email, as you mention, the CFG_BUCK_V_TH and CFG_FLOAT_V_TH values are different. The values CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000 seem too high.

Are you intentionally writing to these registers? If not then perhaps there is a bug in your code. I think the default values should be good for both batteries

CFG_BUCK_V_TH:14700 CFG_FLOAT_V_TH:13650 CFG_PWR_OFF_TH:11500 CFG_PWR_ON_TH:12500 Also you might want to measure the VS & IS parameters to compute the number of watts you are getting from the panel. This value will be lower when the charger is in FLOAT and only maintaining the charge level and providing power for your load. However it is a good measure of how much sun you are getting when the charger is in BULK state.

Regards, Dan

On Sep 13, 2020, at 7:33 AM, gon0 notifications@github.com wrote:

All of the posts above are regarding to my first makerPowerSolar, being used with a 17 Ah battery.

I have an additional question regarding my second makerPowerSolar:

I am using a Panasonic LC-R127R2PG1 12 V 7.2 AH Lead-Acid battery with the second makerPowerSolar. After using the same code and reading the register values, i noticed, that some values differ.

1st makerPower Solar, used with the above mentioned 17 Ah battery: register values SYS_ID:4114 SYS_BUCK:17666 VAL_IC:11 VAL_V_TH:14087 VAL_V_MPPT:20838 CFG_BUCK_V_TH:15000 CFG_FLOAT_V_TH:14000 CFG_PWR_OFF_TH:11500 CFG_PWR_ON_TH:12500 isAlert:0 isNight:0 getWatchdogTimeout:255 getWatchdogPoweroff:65535 getWatchdogEnable:0

2nd makerPower Solar, used with the mentioned 7 Ah battery in this post: register values SYS_ID:4114 SYS_BUCK:6402 VAL_IC:-1 VAL_V_TH:13585 VAL_V_MPPT:20326 CFG_BUCK_V_TH:14700 CFG_FLOAT_V_TH:13650 CFG_PWR_OFF_TH:11500 CFG_PWR_ON_TH:12500 isAlert:0 isNight:0 getWatchdogTimeout:0 getWatchdogPoweroff:10 getWatchdogEnable:0

It can be seen, that both makerPowerSolars have different values for CFG_BUCK_V_TH and CFG_FLOAT_V_TH. What values would you recommend for each battery?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/danjulio/MPPT-Solar-Charger/issues/2#issuecomment-691672051, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOB66REI2CTAIOQ6YBOPN3SFTCZ7ANCNFSM4QNKOGEQ.

gon0 commented 4 years ago

Dear Dan, thank you for your help again!

Before you mentioned the registers, I have never changed register values, because I did not use any of your functions in my code to get or set the values. I assume these values were either default values or they were set while by mistake while the ESP32 did the "I2C bombarding" mentioned above.

However, I now know how to get and set these values :) I will add your proposed values of CFG_BUCK_V_TH and CFG_FLOAT_V_TH to my makerPowerSolar_init() function and will let you know how it works.

Also thank you for the idea to calculate the panel power. I'll definitely have a look on that :)

gon0 commented 4 years ago

Dear Dan,

today I had a day of testing with the new init-function which is run in "setup()" in the ESP32. These values are now set in both the makerPowerSolar running with the 7 Ah battery and in the makerPowerSolar running with the 17 Ah battery and:

void makerPowerSolar_init(){
  reg_CFG_PWR_OFF_TH = 11500;
  reg_CFG_PWR_ON_TH = 12500;
  (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH);
  (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

  reg_CFG_BUCK_V_TH = 14700;
  reg_CFG_FLOAT_V_TH = 13650;
  (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH);
  (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH);
}

Let's name the makerPowerSolar running with the 7 Ah battery "Solar1" and the makerPowerSolar running with the 17 Ah battery "Solar2".

All of the posts above refer to the Solar2. The Solar2 runs fine, even without sunlight: grafik So this problem seems to have been solved. Thank you very much! I am happy with the result.

Now we can have a look at the Solar1, running with the 7 Ah battery: grafik The current spikes are from a load which is switched on and off periodically. What seems strange to me is that the output is shut off again: After 15:30, the solar panel was in shadow. At 16:45 the makerPowerSolar was in FLOAT (shown in red color) charging state when the output was shut off. I would have expected that it changes to IDLE, later to NIGHT, instead of shutting off directly from FLOAT state. Since this is an outside unit, it is quite some work for me to get access to it. I am also reading out the Alert-state via I2C, which I would see in the graph if it would have been active.

This is how the last minutes before shutting off looked like: grafik

I'll have a look at the next days, hot the behavior looks like.

If you have any thoughts, I am happy to hear about them. Have a great day

danjulio commented 4 years ago

Everything for Solar1 seems fine. It seems like everything is operating properly until it shuts down.

Is there any way to query registers? It might be interesting to see what all register values are occasionally. I used this frequently while debugging the original code.

Otherwise maybe your hardware is bad? Did you buy this from me on tindie or from Crowd Supply? Certainly I want you to be happy so if you want to exchange the board I’ll send you a new one (I would like to get the suspect one back for analysis).

Regards, Dan

On Sep 15, 2020, at 11:13 AM, gon0 notifications@github.com wrote:

Dear Dan,

today I had a day of testing with the new init-function which is run in "setup()" in the ESP32. These values are now set in both the makerPowerSolar running with the 7 Ah battery and in the makerPowerSolar running with the 17 Ah battery and:

void makerPowerSolar_init(){ reg_CFG_PWR_OFF_TH = 11500; reg_CFG_PWR_ON_TH = 12500; (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH); (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

reg_CFG_BUCK_V_TH = 14700; reg_CFG_FLOAT_V_TH = 13650; (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH); (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH); } Let's name the makerPowerSolar running with the 7 Ah battery "Solar1" and the makerPowerSolar running with the 17 Ah battery "Solar2".

All of the posts above refer to the Solar2. The Solar2 runs fine, even without sunlight: https://user-images.githubusercontent.com/33236024/93240967-1730b300-f785-11ea-9be6-a0b22596c453.png So this problem seems to have been solved. Thank you very much! I am happy with the result.

Now we can have a look at the Solar1, running with the 7 Ah battery: https://user-images.githubusercontent.com/33236024/93241329-7c84a400-f785-11ea-9dad-9c8c8c7e789f.png The current spikes are from a load which is switched on and off periodically. What seems strange to me is that the output is shut off again: After 15:30, the solar panel was in shadow. At 16:45 the makerPowerSolar was in FLOAT (shown in red color) charging state when the output was shut off. I would have expected that it changes to IDLE, later to NIGHT, instead of shutting off directly from FLOAT state. Since this is an outside unit, it is quite some work for me to get access to it. I am also reading out the Alert-state via I2C, which I would see in the graph if it would have been active.

This is how the last minutes before shutting off looked like: https://user-images.githubusercontent.com/33236024/93242375-06813c80-f787-11ea-8a97-6173beb2e0e5.png I'll have a look at the next days, hot the behavior looks like.

If you have any thoughts, I am happy to hear about them. Have a great day

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/danjulio/MPPT-Solar-Charger/issues/2#issuecomment-692852907, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOB66UCTM3XTJ7IYRANAQDSF6OCTANCNFSM4QNKOGEQ.

gon0 commented 4 years ago

Dear Dan, I just now edited this post, and I would like to update it in some hours with new results. So please don't spend time reading it right now, I'll post an update after the units were running for some hours

gon0 commented 4 years ago

Dear Dan,

thank you for your quick answer.

Is there any way to query registers? It might be interesting to see what all register values are occasionally. I used this frequently while debugging the original code.

I did some testing in the last days. I have added to both Solar1 and Solar2 systems, that the ESP32s send register values to the database every 5 minutes as a log. Although the "makerPowerSolar_init()"-function (see below) is run in setup() in my arduino code, it seems both makerPowerSolar forget these values.

void makerPowerSolar_init(){
  reg_CFG_PWR_OFF_TH = 11500;
  reg_CFG_PWR_ON_TH = 12500;
  (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH);
  (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

  reg_CFG_BUCK_V_TH = 14700;
  reg_CFG_FLOAT_V_TH = 13650;
  (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH);
  (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH);
}

So I executed the "makerPowerSolar_init()"-function after each time the register values were logged (that means every 5 minutes). I seems that even within 5 minutes both makerPowerSolar forget these values sometimes. Long story short:

Maybe you can help me clarify: In my understanding, setting the values via the I2C-procedures used in the "makerPowerSolar_init()"-function, the makerPowerSolar should keep these values, is this correct? Are these values saved to EEPROM, so that when I power up a makerPowerSolar after being disconnected from a battery, that these values are set? Or do I always need a microcontroller, which sets these values on startup of the makerPowerSolar?

Otherwise maybe your hardware is bad? Did you buy this from me on tindie or from Crowd Supply? Certainly I want you to be happy so if you want to exchange the board I’ll send you a new one (I would like to get the suspect one back for analysis).

Thank you for your offer! I bought these units while the crowd funding was running on Crowd supply. I am very happy with this project, because your examples are helpful, you have a good documentation and you are doing a good support right now :) If you have any ideas left what I could check, I'll happily do it. If there is no other way than exchanging the units, I guess this is what needs to be done.

Here is the dashboard of the last hours today. I marked the logging showing the changed register values with a red box: grafik I saw these resetted values also with the Solar2-setup, but they seem to occur less often.

Here is the main part of my ESP32 arduino code (sorry, I did not clean it for posting it). Maybe there is an error in my code, so I'll also add my code to this post to make sure we don't send the makerPowerSolars around the globe because I did stupid programming mistakes ;)

 /*
 * MPPT Solar Charger + esp8266 driving Adafruit IO dashboard
 *
 * This program demonstrates displaying charger information on an Adafruit IO dashboard using
 * an esp8266 module.
 * 
 * Connections:
 *    MPPT Solar Charger GND => esp8266 GND
 *    MPPT Solar Charger 5V  => esp8266 +5V VIN (small module requires 3.3V external regulator)
 *    MPPT Solar Charger SDA => esp8266 D4
 *    MPPT Solar Charger SCL => esp8266 D2
 *
 * Required Libraries
 *    MPPT Solar Charger mpptChg Arduino library - https://github.com/danjulio/MPPT-Solar-Charger/tree/master/arduino
 *    Adafruit MPTT library - https://github.com/adafruit/Adafruit_MQTT_Library
 * 
 * You must have installed support for the esp8266 in the Arduino IDE.  In addition, you must have an account
 * at Adafruit (https://io.adafruit.com/).  Information about creating the dashboard is in the github respository
 * (https://github.com/danjulio/MPPT-Solar-Charger/tree/master/examples/esp8266).
 * 
 * This demo was tested on the Sparkfun ESP8266 WiFi Shield.  The built-in LED on pin 5 is used to indicate successful
 * connection to the local WiFi Network.  It may need to be changed for different esp8266 boards.
 * 
 * Distribured as-is; No warranty is given.
 * 
 */
#include "OTA.h"
#include <WiFiClientSecure.h>
//#include <ESP8266WiFi.h>
#include <mpptChg.h>
#include <PubSubClient.h>
#include <esp_task_wdt.h> // https://iotassistant.io/esp32/enable-hardware-watchdog-timer-esp32-arduino-ide/
//3 seconds WDT
#define WDT_TIMEOUT 15
#include <RunningMedian.h>
RunningMedian samples_Temp = RunningMedian(5);
RunningMedian samples_Volt = RunningMedian(5);
RunningMedian samples_Current = RunningMedian(5);
RunningMedian samples_Power = RunningMedian(5);
RunningMedian samples_IC = RunningMedian(5);
RunningMedian samples_V_MPPT = RunningMedian(5);

// I2C Bus pins
#define SDA_PIN 33
#define SCL_PIN 32

// Status LED pin
#define LED_PIN 5

// Number of feeds
#define NUM_FEEDS 7

// Charger status strings
#define I2C_ERR_INDEX 8

const char* status_msg[] = {
  "NIGHT",
  "IDLE",
  "VSRCV",
  "SCAN",
  "BULK",
  "ABSORPTION",
  "FLOAT",
  "ILLEGAL",
  "I2C FAIL"
};

// ========================================================================
// Variables
//

// Solar charger object
mpptChg chg;

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
//WiFiClient client;
WiFiClient client;
PubSubClient mqttClient(client);

// Charger values
uint16_t reg_status;
int16_t reg_vs;
int16_t reg_is;
int16_t reg_vb;
int16_t reg_ib;
int16_t reg_et;
float chg_watts;
float chg_batt_volts;
float chg_temp;
float chg_panel_volts;
float chg_batt_ic;

uint16_t reg_SYS_ID;
uint16_t reg_SYS_BUCK;
int16_t reg_VAL_IC;
int16_t reg_VAL_V_TH;
int16_t reg_VAL_V_MPPT;
uint16_t reg_CFG_BUCK_V_TH;
uint16_t reg_CFG_FLOAT_V_TH;
uint16_t reg_CFG_PWR_OFF_TH;
uint16_t reg_CFG_PWR_ON_TH;
uint16_t reg_CFG_BUCK_V_TH_readout;
uint16_t reg_CFG_FLOAT_V_TH_readout;
uint16_t reg_CFG_PWR_OFF_TH_readout;
uint16_t reg_CFG_PWR_ON_TH_readout;
bool Alert_state_active;
bool Night_state_active;

uint16_t reg_getWatchdogPoweroff;
uint8_t reg_getWatchdogTimeout;
bool Watchdog_state_active;

// Current status string index
int status_index = 0;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;  //will store last time LED was blinked
unsigned long previousMillis_read_charger = 0; 
const long Publish_data_interval = 5000;         // period at which to blink in ms
const long Read_charger_interval = 500;         // period at which to blink in ms

unsigned long previousMillis_reg_value = 0; 
const long Publish_reg_value_interval = 300000;           // this is the 5 minute-interval to send the log
// ========================================================================
// Arduino environment entry points
//

void setup() {
  // Configure the LED for diagnostics
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);  // LED is active low

    esp_task_wdt_init(WDT_TIMEOUT, true); //enable panic so ESP32 restarts
  esp_task_wdt_add(NULL); //add current thread to WDT watch

  // Use the hardware serial for diagnostics
  Serial.begin(115200);

  // Initialize the connection to the charger
  chg.begin(SDA_PIN, SCL_PIN);

  makerPowerSolar_init();

  esp_task_wdt_reset();
  setupOTA("ESP32_Solar1_Pflanzen");

  MQTT_setup();
  // Indicate success
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  int i;

  ArduinoOTA.handle();
  esp_task_wdt_reset();
  MQTT_reconnect_in_loop();

 currentMillis = millis(); // store the current time
   if (currentMillis - previousMillis_read_charger >= Read_charger_interval) { // check if 1000ms passed
     previousMillis_read_charger = currentMillis;   // save the last time print_mode();
      // Push one data value every 2 seconds (so not to overrun the free version of IO)
        // Update values from the charger
        chg_update();
   }
ArduinoOTA.handle();

   if (currentMillis - previousMillis >= Publish_data_interval) { // check if 1000ms passed
     previousMillis = currentMillis;   // save the last time print_mode();
      // Push one data value every 2 seconds (so not to overrun the free version of IO)
      for (i=0; i<NUM_FEEDS; i++) {
        publish_data(i);
      } 
   }

ArduinoOTA.handle();
    if (currentMillis - previousMillis_reg_value >= Publish_reg_value_interval) { // check if 1000ms passed
     previousMillis_reg_value = currentMillis;   // save the last time print_mode();
      // Push one data value every 2 seconds (so not to overrun the free version of IO)
      send_actual_register_values();
      makerPowerSolar_init();
   }

}

// ========================================================================
// Subroutines
//

void chg_update() {
  // Assume if we can read one value successfully, we can read them all
  if (chg.getStatusValue(SYS_STATUS, &reg_status)) {
    (void) chg.getIndexedValue(VAL_VS, &reg_vs);
    (void) chg.getIndexedValue(VAL_IS, &reg_is);
    (void) chg.getIndexedValue(VAL_VB, &reg_vb);
    (void) chg.getIndexedValue(VAL_IB, &reg_ib);
    (void) chg.getIndexedValue(VAL_EXT_TEMP, &reg_et);

    // Compute some values
    chg_watts = ((float) reg_vs * (float) reg_is) / 1000000.0;   // W = mA * mA / 1E6
    chg_batt_volts = (float) reg_vb / 1000.0;
    chg_temp = (float) reg_et / 10.0;

samples_Temp.add(chg_temp);
samples_Volt.add(chg_batt_volts);
samples_Current.add(reg_ib);
samples_Power.add(chg_watts);

    // Determine our charge state
    status_index = reg_status & MPPT_CHG_STATUS_CHG_ST_MASK;  // 3 low bits are charger state

    (void) chg.getIndexedValue(VAL_IC, &reg_VAL_IC);
    (void) chg.getIndexedValue(VAL_V_MPPT, &reg_VAL_V_MPPT);

chg_panel_volts = (float) reg_VAL_V_MPPT / 1000.0;
chg_batt_ic = (float)reg_VAL_IC;
//chg_batt_volts = (float) reg_VAL_V_MPPT / 1000.0;
samples_IC.add(chg_batt_ic);
samples_V_MPPT.add(chg_panel_volts);

  } else {
    status_index = I2C_ERR_INDEX;
    Serial.println(F("getStatusValue failed"));
  }
}

void publish_data(int i) {
  char hilfString[50];
  switch (i) {
    case 0:
      //if (!chg_status.publish((char*) status_msg[status_index])) {
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/debug_info",(char*) status_msg[status_index])) {
        Serial.println(F("Failed to publish status"));
      } else {
        Serial.print(F("\tPublished status "));
        Serial.print((char*) status_msg[status_index]);
      }
      if(Alert_state_active){
         String status_string = "1";
          status_string.toCharArray(hilfString,50);
        if (!mqttClient.publish("ESP32_Solar1_Pflanzen/alert",hilfString)) {
          Serial.println(F("Failed to publish status"));
        } else {
          Serial.print(F("\tPublished ALERT: "));
          Serial.print((char*) hilfString);
        }
      }
      break;

    case 1:
      //dtostrf(chg_watts, 1, 2, hilfString);
      dtostrf(samples_Power.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_watts", hilfString)) {
        Serial.println(F("Failed to publish power"));
      } else {
        Serial.print(F("\tPublished power = "));
        Serial.print(chg_watts);
      }
      break;

    case 2:
      //dtostrf(chg_batt_volts, 1, 2, hilfString);
       dtostrf(samples_Volt.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_batt_volts", hilfString)){ 
      //if (!chg_vb.publish(chg_batt_volts)) {
        Serial.println(F("Failed to publish vb"));
      } else {
        Serial.print(F("\tPublished vb = "));
        Serial.print(chg_batt_volts);
      }
      break;

    case 3:
      //dtostrf(reg_ib, 1, 2, hilfString);
      dtostrf(samples_Current.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/reg_ib", hilfString)){ 
      //if (!chg_ib.publish(reg_ib)) {
        Serial.println(F("Failed to publish ib"));
      } else {
        Serial.print(F("\tPublished ib = "));
        Serial.print(reg_ib);
      }
      break;

    case 4:
      //dtostrf(chg_temp, 1, 2, hilfString);
      dtostrf(samples_Temp.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_temp", hilfString)){ 
      //if (!chg_et.publish(chg_temp)) {
        Serial.println(F("Failed to publish temp"));
      } else {
        Serial.print(F("\tPublished temp = "));
        Serial.print(chg_temp);
      }
      break;

    case 5:
      //dtostrf(chg_temp, 1, 2, hilfString);
      dtostrf(samples_IC.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_ic", hilfString)){ 
      //if (!chg_et.publish(chg_temp)) {
        Serial.println(F("Failed to publish chg_ic"));
      } else {
        Serial.print(F("\tPublished chg_ic = "));
        Serial.print(samples_IC.getMedian());
      }
      break;

    case 6:
      //dtostrf(chg_temp, 1, 2, hilfString);
      dtostrf(samples_V_MPPT.getMedian(), 1, 2, hilfString);
      //status_string.toCharArray(hilfString,50);
      if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_v_mppt", hilfString)){ 
      //if (!chg_et.publish(chg_temp)) {
        Serial.println(F("Failed to publish chg_v_mppt"));
      } else {
        Serial.print(F("\tPublished chg_v_mppt = "));
        Serial.println(samples_V_MPPT.getMedian());
      }
      break;
  }
}

void makerPowerSolar_init(){
  reg_CFG_PWR_OFF_TH = 11500;
  reg_CFG_PWR_ON_TH = 12500;
  (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH);
  (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

  reg_CFG_BUCK_V_TH = 14700;
  reg_CFG_FLOAT_V_TH = 13650;
  (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH);
  (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH);
}

void send_actual_register_values(){
  if (chg.getStatusValue(SYS_STATUS, &reg_status)) {
    (void) chg.getIndexedValue(VAL_VS, &reg_vs);
    (void) chg.getIndexedValue(VAL_IS, &reg_is);
    (void) chg.getIndexedValue(VAL_VB, &reg_vb);
    (void) chg.getIndexedValue(VAL_IB, &reg_ib);
    (void) chg.getIndexedValue(VAL_EXT_TEMP, &reg_et);
    // Determine our charge state
    status_index = reg_status & MPPT_CHG_STATUS_CHG_ST_MASK;  // 3 low bits are charger state

    (void) chg.getStatusValue(SYS_ID, &reg_SYS_ID);
    (void) chg.getStatusValue(SYS_BUCK, &reg_SYS_BUCK);
    (void) chg.getIndexedValue(VAL_IC, &reg_VAL_IC);
    (void) chg.getIndexedValue(VAL_V_TH, &reg_VAL_V_TH);
    (void) chg.getIndexedValue(VAL_V_MPPT, &reg_VAL_V_MPPT);
    (void) chg.getConfigurationValue(CFG_BUCK_V_TH, &reg_CFG_BUCK_V_TH_readout);
    (void) chg.getConfigurationValue(CFG_FLOAT_V_TH, &reg_CFG_FLOAT_V_TH_readout);
    (void) chg.getConfigurationValue(CFG_PWR_OFF_TH, &reg_CFG_PWR_OFF_TH_readout);
    (void) chg.getConfigurationValue(CFG_PWR_ON_TH, &reg_CFG_PWR_ON_TH_readout);

    chg.getWatchdogTimeout(&reg_getWatchdogTimeout);
    chg.getWatchdogPoweroff(&reg_getWatchdogPoweroff);
    chg.getWatchdogEnable(&Watchdog_state_active);

    chg.isAlert(&Alert_state_active);
    chg.isNight(&Night_state_active);

  char hilfString[200];

String reg_actual = "reg_stat";
reg_actual += reg_status;
reg_actual += "\tstat_index";
reg_actual += status_index;
reg_actual += "\treg_vs ";
reg_actual += reg_vs;
reg_actual += "\treg_is ";
reg_actual += reg_is;
reg_actual += "\treg_vb ";
reg_actual += reg_vb;
reg_actual += "\treg_ib ";
reg_actual += reg_ib;
reg_actual += "\treg_et ";
reg_actual += reg_et;

Serial.print(reg_actual); 
reg_actual.toCharArray(hilfString,200);
mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_1", hilfString);
Serial.print("Stringlänge: "); 
Serial.println(reg_actual.length());
//hilfString[0] = '\0';
memset(hilfString, 0, 200);

reg_actual = "SYS_ID ";
reg_actual += reg_SYS_ID;
reg_actual += "\tSYS_BUCK ";
reg_actual += reg_SYS_BUCK;
reg_actual += "VAL_IC ";
reg_actual += reg_VAL_IC;
reg_actual += "\tVAL_V_TH ";
reg_actual += reg_VAL_V_TH;
reg_actual += "\tVAL_V_MPPT ";
reg_actual += reg_VAL_V_MPPT;
Serial.print(reg_actual); 
reg_actual.toCharArray(hilfString,200);
mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_2", hilfString);
Serial.print("Stringlänge: "); 
Serial.println(reg_actual.length());
//hilfString[0] = '\0';
memset(hilfString, 0, 200);

reg_actual = "CFG_BUCK_V_TH ";
reg_actual += reg_CFG_BUCK_V_TH_readout;
reg_actual += "\tCFG_FLOAT_V_TH ";
reg_actual += reg_CFG_FLOAT_V_TH_readout;
reg_actual += "\tCFG_PWR_OFF_TH ";
reg_actual += reg_CFG_PWR_OFF_TH_readout;
reg_actual += "\tCFG_PWR_ON_TH ";
reg_actual += reg_CFG_PWR_ON_TH_readout;
Serial.print(reg_actual); 
reg_actual.toCharArray(hilfString,200);
mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_3", hilfString);
Serial.print("Stringlänge: "); 
Serial.println(reg_actual.length());
//hilfString[0] = '\0';
memset(hilfString, 0, 200);

reg_actual = "getWdgTimeout ";
reg_actual += reg_getWatchdogTimeout;
reg_actual += "\tgetWdgPoweroff ";
reg_actual += reg_getWatchdogPoweroff;
reg_actual += "\tWdg_active ";
reg_actual += Watchdog_state_active;
reg_actual += "\tAlert ";
reg_actual += Alert_state_active;
reg_actual += "\tNight ";
reg_actual += Night_state_active;
Serial.print(reg_actual); 
reg_actual.toCharArray(hilfString,200);
mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_4", hilfString);
Serial.print("Stringlänge: "); 
Serial.println(reg_actual.length());
//hilfString[0] = '\0';
memset(hilfString, 0, 200);

  }
}
danjulio commented 4 years ago

Please see comments below:

On Sep 20, 2020, at 11:02 AM, gon0 notifications@github.com wrote:

Dear Dan,

thank you for your quick answer.

Is there any way to query registers? It might be interesting to see what all register values are occasionally. I used this frequently while debugging the original code.

I’m not sure what you are asking. It seems you are already querying them using the “get" methods in the driver. You can read all registers. You can write the parameter block and watchdog timer registers. Please see the manual for a more detailed explanation.

I did some testing in the last days. I have added to both Solar1 and Solar2 systems, that the ESP32s send register values to the database every 5 minutes as a log. Although the "makerPowerSolar_init()"-function (see below) is run in setup() in my arduino code, it seems both makerPowerSolar forget these values.

void makerPowerSolar_init(){ reg_CFG_PWR_OFF_TH = 11500; reg_CFG_PWR_ON_TH = 12500; (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH); (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

reg_CFG_BUCK_V_TH = 14700; reg_CFG_FLOAT_V_TH = 13650; (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH); (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH); } So I executed the "makerPowerSolar_init()"-function after each time the register values were logged (that means every 5 minutes). I seems that even within 5 minutes both makerPowerSolar forget these values sometimes. Long story short:

these 4 values are set each 5 minutes (there is no error message after setting these values) after 5 minutes these values are read out, sometimes alle values are still set, sometimes these values have been reset (e.g. CFG_PWR_OFF_TH is 13000 instead of 11500) (it seems random).

It is interesting that the default values are 11500, 12500, 14700 and 13650. These are the values the charger loads when it is first powered on. The fact that you see them change makes me think that perhaps your code is somehow changing them - or perhaps the I2C cycles are incorrect in some fashion that causes extraneous or incorrect writes. I have done extensive testing with Arduino, ESP8266 and Raspberry Pi. I did not test with ESP32. Maybe there is some issue with it’s I2C cycles and the charger. I don’t think there is a bug in the charger in this area because I have literally run millions of cycles against several units over a course of two years.

Maybe you can help me clarify: In my understanding, setting the values via the I2C-procedures used in the "makerPowerSolar_init()"-function, the makerPowerSolar should keep these values, is this correct? Are these values saved to EEPROM, so that when I power up a makerPowerSolar after being disconnected from a battery, that these values are set? Or do I always need a microcontroller, which sets these values on startup of the makerPowerSolar?

They are not saved to EEPROM. They are held in RAM-based registers. Upon reset the default values are reloaded.

Otherwise maybe your hardware is bad? Did you buy this from me on tindie or from Crowd Supply? Certainly I want you to be happy so if you want to exchange the board I’ll send you a new one (I would like to get the suspect one back for analysis).

Thank you for your offer! I bought these units while the crowd funding was running on Crowd supply. I am very happy with this project, because your examples are helpful, you have a good documentation and you are doing a good support right now :) If you have any ideas left what I could check, I'll happily do it. If there is no other way than exchanging the units, I guess this is what needs to be done.

Here is the dashboard of the last hours today. I marked the logging showing the changed register values with a red box: https://user-images.githubusercontent.com/33236024/93717034-70c52300-fb73-11ea-8bbe-4bdb4ea9d296.png I saw these resetted values also with the Solar2-setup, but they seem to occur less often.

Here is the main part of my ESP32 arduino code (sorry, I did not clean it for posting it). Maybe there is an error in my code, so I'll also add my code to this post to make sure we don't send the makerPowerSolars around the globe because I did stupid programming mistakes ;)

/*

  • MPPT Solar Charger + esp8266 driving Adafruit IO dashboard
  • This program demonstrates displaying charger information on an Adafruit IO dashboard using
  • an esp8266 module.
  • Connections:
  • MPPT Solar Charger GND => esp8266 GND
  • MPPT Solar Charger 5V => esp8266 +5V VIN (small module requires 3.3V external regulator)
  • MPPT Solar Charger SDA => esp8266 D4
  • MPPT Solar Charger SCL => esp8266 D2
  • Required Libraries
  • MPPT Solar Charger mpptChg Arduino library - https://github.com/danjulio/MPPT-Solar-Charger/tree/master/arduino
  • Adafruit MPTT library - https://github.com/adafruit/Adafruit_MQTT_Library
  • You must have installed support for the esp8266 in the Arduino IDE. In addition, you must have an account
  • at Adafruit (https://io.adafruit.com/). Information about creating the dashboard is in the github respository
  • (https://github.com/danjulio/MPPT-Solar-Charger/tree/master/examples/esp8266).
  • This demo was tested on the Sparkfun ESP8266 WiFi Shield. The built-in LED on pin 5 is used to indicate successful
  • connection to the local WiFi Network. It may need to be changed for different esp8266 boards.
  • Distribured as-is; No warranty is given.
  • */

    include "OTA.h"

    include

    //#include

    include

    include

    include // https://iotassistant.io/esp32/enable-hardware-watchdog-timer-esp32-arduino-ide/

    //3 seconds WDT

    define WDT_TIMEOUT 15

    include

    RunningMedian samples_Temp = RunningMedian(5); RunningMedian samples_Volt = RunningMedian(5); RunningMedian samples_Current = RunningMedian(5); RunningMedian samples_Power = RunningMedian(5); RunningMedian samples_IC = RunningMedian(5); RunningMedian samples_V_MPPT = RunningMedian(5);

// I2C Bus pins

define SDA_PIN 33

define SCL_PIN 32

// Status LED pin

define LED_PIN 5

// Number of feeds

define NUM_FEEDS 7

// Charger status strings

define I2C_ERR_INDEX 8

const char* status_msg[] = { "NIGHT", "IDLE", "VSRCV", "SCAN", "BULK", "ABSORPTION", "FLOAT", "ILLEGAL", "I2C FAIL" };

// ======================================================================== // Variables //

// Solar charger object mpptChg chg;

// Create an ESP8266 WiFiClient class to connect to the MQTT server. //WiFiClient client; WiFiClient client; PubSubClient mqttClient(client);

// Charger values uint16_t reg_status; int16_t reg_vs; int16_t reg_is; int16_t reg_vb; int16_t reg_ib; int16_t reg_et; float chg_watts; float chg_batt_volts; float chg_temp; float chg_panel_volts; float chg_batt_ic;

uint16_t reg_SYS_ID; uint16_t reg_SYS_BUCK; int16_t reg_VAL_IC; int16_t reg_VAL_V_TH; int16_t reg_VAL_V_MPPT; uint16_t reg_CFG_BUCK_V_TH; uint16_t reg_CFG_FLOAT_V_TH; uint16_t reg_CFG_PWR_OFF_TH; uint16_t reg_CFG_PWR_ON_TH; uint16_t reg_CFG_BUCK_V_TH_readout; uint16_t reg_CFG_FLOAT_V_TH_readout; uint16_t reg_CFG_PWR_OFF_TH_readout; uint16_t reg_CFG_PWR_ON_TH_readout; bool Alert_state_active; bool Night_state_active;

uint16_t reg_getWatchdogPoweroff; uint8_t reg_getWatchdogTimeout; bool Watchdog_state_active;

// Current status string index int status_index = 0;

unsigned long currentMillis = 0; unsigned long previousMillis = 0; //will store last time LED was blinked unsigned long previousMillis_read_charger = 0; const long Publish_data_interval = 5000; // period at which to blink in ms const long Read_charger_interval = 500; // period at which to blink in ms

unsigned long previousMillis_reg_value = 0; const long Publish_reg_value_interval = 300000; // this is the 5 minute-interval to send the log // ======================================================================== // Arduino environment entry points //

void setup() { // Configure the LED for diagnostics pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, HIGH); // LED is active low

esp_task_wdt_init(WDT_TIMEOUT, true); //enable panic so ESP32 restarts

esp_task_wdt_add(NULL); //add current thread to WDT watch

// Use the hardware serial for diagnostics Serial.begin(115200);

// Initialize the connection to the charger chg.begin(SDA_PIN, SCL_PIN);

makerPowerSolar_init();

esp_task_wdt_reset(); setupOTA("ESP32_Solar1_Pflanzen");

MQTT_setup(); // Indicate success digitalWrite(LED_PIN, LOW); }

void loop() { int i;

ArduinoOTA.handle(); esp_task_wdt_reset(); MQTT_reconnect_in_loop();

currentMillis = millis(); // store the current time if (currentMillis - previousMillis_read_charger >= Read_charger_interval) { // check if 1000ms passed previousMillis_read_charger = currentMillis; // save the last time print_mode(); // Push one data value every 2 seconds (so not to overrun the free version of IO) // Update values from the charger chg_update(); } ArduinoOTA.handle();

if (currentMillis - previousMillis >= Publish_data_interval) { // check if 1000ms passed previousMillis = currentMillis; // save the last time print_mode(); // Push one data value every 2 seconds (so not to overrun the free version of IO) for (i=0; i<NUM_FEEDS; i++) { publish_data(i); } }

ArduinoOTA.handle(); if (currentMillis - previousMillis_reg_value >= Publish_reg_value_interval) { // check if 1000ms passed previousMillis_reg_value = currentMillis; // save the last time print_mode(); // Push one data value every 2 seconds (so not to overrun the free version of IO) send_actual_register_values(); makerPowerSolar_init(); }

}

// ======================================================================== // Subroutines //

void chg_update() { // Assume if we can read one value successfully, we can read them all if (chg.getStatusValue(SYS_STATUS, &reg_status)) { (void) chg.getIndexedValue(VAL_VS, &reg_vs); (void) chg.getIndexedValue(VAL_IS, &reg_is); (void) chg.getIndexedValue(VAL_VB, &reg_vb); (void) chg.getIndexedValue(VAL_IB, &reg_ib); (void) chg.getIndexedValue(VAL_EXT_TEMP, &reg_et);

// Compute some values
chg_watts = ((float) reg_vs * (float) reg_is) / 1000000.0;   // W = mA * mA / 1E6
chg_batt_volts = (float) reg_vb / 1000.0;
chg_temp = (float) reg_et / 10.0;

samples_Temp.add(chg_temp); samples_Volt.add(chg_batt_volts); samples_Current.add(reg_ib); samples_Power.add(chg_watts);

// Determine our charge state
status_index = reg_status & MPPT_CHG_STATUS_CHG_ST_MASK;  // 3 low bits are charger state

(void) chg.getIndexedValue(VAL_IC, &reg_VAL_IC);
(void) chg.getIndexedValue(VAL_V_MPPT, &reg_VAL_V_MPPT);

chg_panel_volts = (float) reg_VAL_V_MPPT / 1000.0; chg_batt_ic = (float)reg_VAL_IC; //chg_batt_volts = (float) reg_VAL_V_MPPT / 1000.0; samples_IC.add(chg_batt_ic); samples_V_MPPT.add(chg_panel_volts);

} else { status_index = I2C_ERR_INDEX; Serial.println(F("getStatusValue failed")); } }

void publish_data(int i) { char hilfString[50]; switch (i) { case 0: //if (!chg_status.publish((char) status_msg[status_index])) { if (!mqttClient.publish("ESP32_Solar1_Pflanzen/debug_info",(char) status_msg[status_index])) { Serial.println(F("Failed to publish status")); } else { Serial.print(F("\tPublished status ")); Serial.print((char) status_msg[status_index]); } if(Alert_state_active){ String status_string = "1"; status_string.toCharArray(hilfString,50); if (!mqttClient.publish("ESP32_Solar1_Pflanzen/alert",hilfString)) { Serial.println(F("Failed to publish status")); } else { Serial.print(F("\tPublished ALERT: ")); Serial.print((char) hilfString); } } break;

case 1:
  //dtostrf(chg_watts, 1, 2, hilfString);
  dtostrf(samples_Power.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_watts", hilfString)) {
    Serial.println(F("Failed to publish power"));
  } else {
    Serial.print(F("\tPublished power = "));
    Serial.print(chg_watts);
  }
  break;

case 2:
  //dtostrf(chg_batt_volts, 1, 2, hilfString);
   dtostrf(samples_Volt.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_batt_volts", hilfString)){ 
  //if (!chg_vb.publish(chg_batt_volts)) {
    Serial.println(F("Failed to publish vb"));
  } else {
    Serial.print(F("\tPublished vb = "));
    Serial.print(chg_batt_volts);
  }
  break;

case 3:
  //dtostrf(reg_ib, 1, 2, hilfString);
  dtostrf(samples_Current.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/reg_ib", hilfString)){ 
  //if (!chg_ib.publish(reg_ib)) {
    Serial.println(F("Failed to publish ib"));
  } else {
    Serial.print(F("\tPublished ib = "));
    Serial.print(reg_ib);
  }
  break;

case 4:
  //dtostrf(chg_temp, 1, 2, hilfString);
  dtostrf(samples_Temp.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_temp", hilfString)){ 
  //if (!chg_et.publish(chg_temp)) {
    Serial.println(F("Failed to publish temp"));
  } else {
    Serial.print(F("\tPublished temp = "));
    Serial.print(chg_temp);
  }
  break;

case 5:
  //dtostrf(chg_temp, 1, 2, hilfString);
  dtostrf(samples_IC.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_ic", hilfString)){ 
  //if (!chg_et.publish(chg_temp)) {
    Serial.println(F("Failed to publish chg_ic"));
  } else {
    Serial.print(F("\tPublished chg_ic = "));
    Serial.print(samples_IC.getMedian());
  }
  break;

case 6:
  //dtostrf(chg_temp, 1, 2, hilfString);
  dtostrf(samples_V_MPPT.getMedian(), 1, 2, hilfString);
  //status_string.toCharArray(hilfString,50);
  if (!mqttClient.publish("ESP32_Solar1_Pflanzen/chg_v_mppt", hilfString)){ 
  //if (!chg_et.publish(chg_temp)) {
    Serial.println(F("Failed to publish chg_v_mppt"));
  } else {
    Serial.print(F("\tPublished chg_v_mppt = "));
    Serial.println(samples_V_MPPT.getMedian());
  }
  break;

} }

void makerPowerSolar_init(){ reg_CFG_PWR_OFF_TH = 11500; reg_CFG_PWR_ON_TH = 12500; (void) chg.setConfigurationValue(CFG_PWR_OFF_TH, reg_CFG_PWR_OFF_TH); (void) chg.setConfigurationValue(CFG_PWR_ON_TH, reg_CFG_PWR_ON_TH);

reg_CFG_BUCK_V_TH = 14700; reg_CFG_FLOAT_V_TH = 13650; (void) chg.setConfigurationValue(CFG_BUCK_V_TH, reg_CFG_BUCK_V_TH); (void) chg.setConfigurationValue(CFG_FLOAT_V_TH, reg_CFG_FLOAT_V_TH); }

void send_actual_register_values(){ if (chg.getStatusValue(SYS_STATUS, &reg_status)) { (void) chg.getIndexedValue(VAL_VS, &reg_vs); (void) chg.getIndexedValue(VAL_IS, &reg_is); (void) chg.getIndexedValue(VAL_VB, &reg_vb); (void) chg.getIndexedValue(VAL_IB, &reg_ib); (void) chg.getIndexedValue(VAL_EXT_TEMP, &reg_et); // Determine our charge state status_index = reg_status & MPPT_CHG_STATUS_CHG_ST_MASK; // 3 low bits are charger state

(void) chg.getStatusValue(SYS_ID, &reg_SYS_ID);
(void) chg.getStatusValue(SYS_BUCK, &reg_SYS_BUCK);
(void) chg.getIndexedValue(VAL_IC, &reg_VAL_IC);
(void) chg.getIndexedValue(VAL_V_TH, &reg_VAL_V_TH);
(void) chg.getIndexedValue(VAL_V_MPPT, &reg_VAL_V_MPPT);
(void) chg.getConfigurationValue(CFG_BUCK_V_TH, &reg_CFG_BUCK_V_TH_readout);
(void) chg.getConfigurationValue(CFG_FLOAT_V_TH, &reg_CFG_FLOAT_V_TH_readout);
(void) chg.getConfigurationValue(CFG_PWR_OFF_TH, &reg_CFG_PWR_OFF_TH_readout);
(void) chg.getConfigurationValue(CFG_PWR_ON_TH, &reg_CFG_PWR_ON_TH_readout);

chg.getWatchdogTimeout(&reg_getWatchdogTimeout);
chg.getWatchdogPoweroff(&reg_getWatchdogPoweroff);
chg.getWatchdogEnable(&Watchdog_state_active);

chg.isAlert(&Alert_state_active);
chg.isNight(&Night_state_active);

char hilfString[200];

String reg_actual = "reg_stat"; reg_actual += reg_status; reg_actual += "\tstat_index"; reg_actual += status_index; reg_actual += "\treg_vs "; reg_actual += reg_vs; reg_actual += "\treg_is "; reg_actual += reg_is; reg_actual += "\treg_vb "; reg_actual += reg_vb; reg_actual += "\treg_ib "; reg_actual += reg_ib; reg_actual += "\treg_et "; reg_actual += reg_et;

Serial.print(reg_actual); reg_actual.toCharArray(hilfString,200); mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_1", hilfString); Serial.print("Stringlänge: "); Serial.println(reg_actual.length()); //hilfString[0] = '\0'; memset(hilfString, 0, 200);

reg_actual = "SYS_ID "; reg_actual += reg_SYS_ID; reg_actual += "\tSYS_BUCK "; reg_actual += reg_SYS_BUCK; reg_actual += "VAL_IC "; reg_actual += reg_VAL_IC; reg_actual += "\tVAL_V_TH "; reg_actual += reg_VAL_V_TH; reg_actual += "\tVAL_V_MPPT "; reg_actual += reg_VAL_V_MPPT; Serial.print(reg_actual); reg_actual.toCharArray(hilfString,200); mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_2", hilfString); Serial.print("Stringlänge: "); Serial.println(reg_actual.length()); //hilfString[0] = '\0'; memset(hilfString, 0, 200);

reg_actual = "CFG_BUCK_V_TH "; reg_actual += reg_CFG_BUCK_V_TH_readout; reg_actual += "\tCFG_FLOAT_V_TH "; reg_actual += reg_CFG_FLOAT_V_TH_readout; reg_actual += "\tCFG_PWR_OFF_TH "; reg_actual += reg_CFG_PWR_OFF_TH_readout; reg_actual += "\tCFG_PWR_ON_TH "; reg_actual += reg_CFG_PWR_ON_TH_readout; Serial.print(reg_actual); reg_actual.toCharArray(hilfString,200); mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_3", hilfString); Serial.print("Stringlänge: "); Serial.println(reg_actual.length()); //hilfString[0] = '\0'; memset(hilfString, 0, 200);

reg_actual = "getWdgTimeout "; reg_actual += reg_getWatchdogTimeout; reg_actual += "\tgetWdgPoweroff "; reg_actual += reg_getWatchdogPoweroff; reg_actual += "\tWdg_active "; reg_actual += Watchdog_state_active; reg_actual += "\tAlert "; reg_actual += Alert_state_active; reg_actual += "\tNight "; reg_actual += Night_state_active; Serial.print(reg_actual); reg_actual.toCharArray(hilfString,200); mqttClient.publish("ESP32_Solar1_Pflanzen/reg_values1_4", hilfString); Serial.print("Stringlänge: "); Serial.println(reg_actual.length()); //hilfString[0] = '\0'; memset(hilfString, 0, 200);

} }

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/danjulio/MPPT-Solar-Charger/issues/2#issuecomment-695810332, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOB66R7L5N7K36R7NTF33TSGYYR5ANCNFSM4QNKOGEQ.

gon0 commented 4 years ago

Hello Dan,

maybe here were some misunderstandings. I'll try to clarify these first: First: grafik

Second: I had the impression, that the default values in the charger are: CFG_BUCK_V_TH 15000 CFG_FLOAT_V_TH 14000 CFG_PWR_OFF_TH 13000 CFG_PWR_ON_TH 13000 Because on my first tries, I have never set or get these values. When I first did read out these values, I saw these values. All happenend with the ESP32.

Via your provided set-functions, which I am executing in " void makerPowerSolar_init()", I set these values (According to your proposed values): CFG_BUCK_V_TH 14700 CFG_FLOAT_V_TH 13650 CFG_PWR_OFF_TH 11500 CFG_PWR_ON_TH 12500

Assuming the ESP32's I2C is working correctly: at seemingly random points in time the default values seem to become active.

However, I have now modified both makerPowerSolar Solar1 and Solar2 running on ESP8266. Every 5 minutes the read out register values are written to the database. I'll let this setup be running for some days and report back. If it runs fine, it seems to be the ESP32's fault and I can happily go on with the rest of the project :)

gon0 commented 4 years ago

Hello Dan,

I am astonished. Since I switched to ESP8266 instead of ESP32, both units are running flawless for 3 days:

grafik

This is awesome! I checked the logs for the string "15000" and did not find a single instance. I had previous issues with the ESP32 and I2C in other projects. I think the ESP8266 is really the better choice for reliable I2C.

Thank you very much for your patience and helpfulness. I'll close this issue, since I think this is solved.

Good luck and keep on with your good work!

gon0 commented 4 years ago

Dear Dan, I have to add that both makerPower Solar ran flawlessly for the last weeks. Also the shutoff at 11.5 V and turning back on when the sun shines works like a charm. I am still wondering that it didn't work with ESP32, but with ESP8266. I learned again, that I have to stay skeptical :) Have a great day

danjulio commented 4 years ago

I’m glad it is working!

Would you mind sharing the code you use to access the charger from the ESP32? I could try to duplicate it. I think that the charger should be able to work with an ESP32. But maybe there is something there I don’t understand.

Thanks, Dan

On Oct 18, 2020, at 7:32 AM, gon0 notifications@github.com wrote:

Dear Dan, ich habe to add that both makerPower Solar ran flawless for the last weeks. Also the shutoff at 11.5 V and turning back on when the sun shines works like a charm. I am still wondering that it didn't work with ESP32s, but with ESP8266. I learned again, that I have to stay skeptical :) Have a great day

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/danjulio/MPPT-Solar-Charger/issues/2#issuecomment-711168705, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABOB66STM73TLDGXE6FBWN3SLLVABANCNFSM4QNKOGEQ.

gon0 commented 4 years ago

Dear Dan,

the ESP32 code is the code I posted above in this post: https://github.com/danjulio/MPPT-Solar-Charger/issues/2#issuecomment-695810332

The code above references to an OTA.h file, which looks like this (the file credentials.h holds my Wifi SSID and Password):

#ifdef ESP32
#include <WiFi.h>
#include <ESPmDNS.h>
#else
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#endif

#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <TelnetStream.h>
#include <credentials.h>

const char* ssid = WIFI_SSID;
const char* password = WIFI_PASSWORD;

#if defined(ESP32_RTOS) && defined(ESP32)
void taskOne( void * parameter )
{
  ArduinoOTA.handle();
  delay(3500);
}
#endif

void setupOTA(const char* nameprefix) {
  const int maxlen = 40;
  char fullhostname[maxlen];
  uint8_t mac[6];
  WiFi.macAddress(mac);
  snprintf(fullhostname, maxlen, "%s-%02x%02x%02x", nameprefix, mac[3], mac[4], mac[5]);
  ArduinoOTA.setHostname(fullhostname);

  // the IP address for the shield:
  IPAddress ip(192, 168, 122, 213);
  IPAddress gateway(192, 168, 122, 1);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress dns(192, 168, 122, 1);
  WiFi.config(ip, dns, gateway, subnet);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
  .onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH)
      type = "sketch";
    else // U_SPIFFS
      type = "filesystem";

    // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA
  .onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA
  .onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA
  .onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });

  ArduinoOTA.begin();
  TelnetStream.begin();

  Serial.println("OTA Initialized");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

#if defined(ESP32_RTOS) && defined(ESP32)
  xTaskCreate(
    ota_handle,          /* Task function. */
    "OTA_HANDLE",        /* String with name of task. */
    10000,            /* Stack size in bytes. */
    NULL,             /* Parameter passed as input of the task */
    1,                /* Priority of the task. */
    NULL);            /* Task handle. */
#endif
}

Furthermore and just for completeness, I have a file MQTT_Routines.ino which uses this code (I am sorry, this is really a mess, but I am just posting it, because I am too lazy to clean it up):

// Add your MQTT Broker IP address, example:
//const char* mqtt_server = "192.168.1.144";
const char* mqtt_server = "192.168.122.40";

long lastMsg = 0;
char msg[50];
int value = 0;
bool reset_log_sent = 0;
int reconnect_counter = 0;

void MQTT_setup(){
  mqttClient.setServer(mqtt_server, 1883);
  mqttClient.setCallback(callback);
  MQTT_reconnect_in_loop();

  MQTT_init_message();

}
void MQTT_reconnect_in_loop(){
    if (!mqttClient.connected()) {
      ArduinoOTA.handle();
    Serial.println(F("reconnect(); starting"));
    reconnect_counter++;
    reconnect();
    Serial.println(F("reconnect(); done"));
  }
  mqttClient.loop();
}

void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". 
  // Changes the output state according to the message
  if (String(topic) == "ESP32_SOLAR2/PCLicht_regal_unten") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
    if (String(topic) == "ESP32_SOLAR2/PCLicht_regal_hinten") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/PCLicht_Spot") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/PC_on") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/Wohnzimmer1") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
    if (String(topic) == "ESP32_SOLAR2/Wohnzimmer2") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
   if (String(topic) == "ESP32_SOLAR2/Wohnzimmer3") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
   if (String(topic) == "ESP32_SOLAR2/TV") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/Radio") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/TVLicht_Spot") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
  if (String(topic) == "ESP32_SOLAR2/TVLicht_ambient") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
    }
    else if(messageTemp == "off"){
      Serial.println("off");
    }
  }
}

void reconnect() {
  // Loop until we're reconnected

    Serial.print("Attempting MQTT connection...");
    String start = "Attempting MQTT connection...";
    /*if(!Telegram_MQTT_reconnect_info_sent){
      bot.sendMessage(UserID_Chris, start);
      Telegram_MQTT_reconnect_info_sent = true;
    }*/
    // Attempt to connect
    if (mqttClient.connect("ESP32_SOLAR1_Client")) {
      Serial.println("connected");
      // Subscribe
      //start = "MQTT connection established";
      //bot.sendMessage(UserID_Chris, start);
     /* //Telegram_MQTT_reconnect_info_sent = false;
      mqttClient.subscribe("ESP32_SOLAR2/PCLicht_regal_unten");
      mqttClient.subscribe("ESP32_SOLAR2/PCLicht_regal_hinten");
      mqttClient.subscribe("ESP32_SOLAR2/PCLicht_Spot");
      mqttClient.subscribe("ESP32_SOLAR2/PC_on");
      mqttClient.subscribe("ESP32_SOLAR2/Wohnzimmer1");
      mqttClient.subscribe("ESP32_SOLAR2/Wohnzimmer2");
      mqttClient.subscribe("ESP32_SOLAR2/Wohnzimmer3");
      mqttClient.subscribe("ESP32_SOLAR2/TV");
      mqttClient.subscribe("ESP32_SOLAR2/Radio");
      mqttClient.subscribe("ESP32_SOLAR2/TVLicht_Spot");
      mqttClient.subscribe("ESP32_SOLAR2/TVLicht_ambient"); */
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      //Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      //delay(5000);
    }

}

/*
void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    messageTemp += (char)message[i];
  }
  Serial.println();

  // Feel free to add more if statements to control more GPIOs with MQTT

  // If a message is received on the topic esp32/output, you check if the message is either "on" or "off". 
  // Changes the output state according to the message
  if (String(topic) == "esp32/output") {
    Serial.print("Changing output to ");
    if(messageTemp == "on"){
      Serial.println("on");
      digitalWrite(ledPin, HIGH);
    }
    else if(messageTemp == "off"){
      Serial.println("off");
      digitalWrite(ledPin, LOW);
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    ESP.wdtFeed();
    wdt_reset(); // Watchdog zurückstellen. Deaktivieren mit "wdt_disable();"
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Subscribe
      client.subscribe("esp8266_Wetterbox/output");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
*/
void MQTT_init_message(){
    String status_string = "ESP32_SOLAR1 connected to MQTT";
      char hilfString[50];
  status_string.toCharArray(hilfString,50);
  mqttClient.publish("ESP32_Solar1_Pflanzen/debug_info", "ESP32_Solar1_Pflanzen connected to MQTT");
}

void ESP32_setup_finished_before_first_loop(){
  String status_string = "1";
  char hilfString[50];
  status_string.toCharArray(hilfString,50);
  mqttClient.publish("ESP32_Solar1_Pflanzen/reset_logger", hilfString);
}

void ESP32_setup_finished_after_first_loop(){
  if (!reset_log_sent){
    String status_string = "0";
    char hilfString[50];
    status_string.toCharArray(hilfString,50);
    mqttClient.publish("ESP32_Solar1_Pflanzen/reset_logger", hilfString);
    reset_log_sent = 1;
  }
}

So you have the whole ESP32 project from me now. I am happy with the ESP8266, so you don't need to put too much effort in it to port it to ESP32. My ESP32 was an ESP32-DODWQ6.

If you have any questions, I am happy to help. Have a good day