Merge remote-tracking branch 'tbnobody/OpenDTU/master'
This commit is contained in:
commit
6b4129c400
15
README.md
15
README.md
@ -115,7 +115,7 @@ A heavily incomplete list of trusted hardware shops in germany is:
|
|||||||
This list is for your convenience only, the project is not related to any of these shops.
|
This list is for your convenience only, the project is not related to any of these shops.
|
||||||
|
|
||||||
### Power supply
|
### Power supply
|
||||||
Use a power suppy with 5V and 1A. The USB cable connected to your PC/Notebook may be powerful enough or may be not.
|
Use a power suppy with 5 V and 1 A. The USB cable connected to your PC/Notebook may be powerful enough or may be not.
|
||||||
|
|
||||||
|
|
||||||
## Wiring up
|
## Wiring up
|
||||||
@ -146,11 +146,14 @@ This can be achieved by editing the 'platformio.ini' file and add/change one or
|
|||||||
* Install git and enable git in vscode - [git download](https://git-scm.com/downloads/) - [Instructions](https://www.jcchouinard.com/install-git-in-vscode/)
|
* Install git and enable git in vscode - [git download](https://git-scm.com/downloads/) - [Instructions](https://www.jcchouinard.com/install-git-in-vscode/)
|
||||||
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur): Inside vscode open the command palette by pressing `CTRL` + `SHIFT` + `P`. Enter `git clone`, add the repository-URL `https://github.com/tbnobody/OpenDTU`. Next you have to choose (or create) a target directory.
|
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur): Inside vscode open the command palette by pressing `CTRL` + `SHIFT` + `P`. Enter `git clone`, add the repository-URL `https://github.com/tbnobody/OpenDTU`. Next you have to choose (or create) a target directory.
|
||||||
* In vscode, choose File --> Open Folder and select the previously downloaded source code. (You have to select the folder which contains the "platformio.ini" file)
|
* In vscode, choose File --> Open Folder and select the previously downloaded source code. (You have to select the folder which contains the "platformio.ini" file)
|
||||||
* There is a short [Video](https://youtu.be/9cA_esv3zeA) showing these steps.
|
|
||||||
* Adjust the COM port in the file "platformio.ini" for your USB-serial-converter. It occurs twice:
|
* Adjust the COM port in the file "platformio.ini" for your USB-serial-converter. It occurs twice:
|
||||||
* upload_port
|
* upload_port
|
||||||
* monitor_port
|
* monitor_port
|
||||||
* Select the arrow button in the status bar (PlatformIO: Upload) to compile and upload the firmware. During the compilation, all required libraries are downloaded automatically.
|
* Select the arrow button in the status bar (PlatformIO: Upload) to compile and upload the firmware. During the compilation, all required libraries are downloaded automatically.
|
||||||
|
* There are two videos showing these steps:
|
||||||
|
* [Git Clone and compilation](https://youtu.be/9cA_esv3zeA)
|
||||||
|
* [Full installation and compilation](https://youtu.be/xs6TqHn7QWM)
|
||||||
|
|
||||||
### on the commandline with PlatformIO Core
|
### on the commandline with PlatformIO Core
|
||||||
* Install [PlatformIO Core](https://platformio.org/install/cli)
|
* Install [PlatformIO Core](https://platformio.org/install/cli)
|
||||||
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur)
|
* Clone this repository (you really have to clone it, don't just download the ZIP file. During the build process the git hash gets embedded into the firmware. If you download the ZIP file a build error will occur)
|
||||||
@ -244,11 +247,11 @@ A documentation of all available MQTT Topics can be found here: [MQTT Documentat
|
|||||||
* First: When there is no light on the solar panels, the inverter completely turns off and does not answer to OpenDTU! So if you assembled your OpenDTU in the evening, wait until tomorrow.
|
* First: When there is no light on the solar panels, the inverter completely turns off and does not answer to OpenDTU! So if you assembled your OpenDTU in the evening, wait until tomorrow.
|
||||||
* When there is no data received from the inverter(s) - try to reduce the distance between the openDTU and the inverter (e.g. move it to the window towards the roof)
|
* When there is no data received from the inverter(s) - try to reduce the distance between the openDTU and the inverter (e.g. move it to the window towards the roof)
|
||||||
* Under Settings -> DTU Settings you can increase the transmit power "PA level". Default is "minimum".
|
* Under Settings -> DTU Settings you can increase the transmit power "PA level". Default is "minimum".
|
||||||
* The NRF24L01+ needs relatively much current. With bad power supply (and especially bad cables!) a 10uF capacitor soldered directly to the NRF24L01+ board connector brings more stability (pin 1+2 are the power supply). Note the polarity of the capacitor....
|
* The NRF24L01+ needs relatively much current. With bad power supply (and especially bad cables!) a 10 µF capacitor soldered directly to the NRF24L01+ board connector brings more stability (pin 1+2 are the power supply). Note the polarity of the capacitor…
|
||||||
* You can try to use an USB power supply with 1A or more instead of connecting the ESP32 to the computer.
|
* You can try to use an USB power supply with 1 A or more instead of connecting the ESP32 to the computer.
|
||||||
* Try a different USB cable. Once again, a stable power source is important. Some USB cables are made of much plastic and very little copper inside.
|
* Try a different USB cable. Once again, a stable power source is important. Some USB cables are made of much plastic and very little copper inside.
|
||||||
* Double-Check that you have a radio module NRF24L01+ with a plus sign at the end. NRF24L01 module without the plus are not compatible with this project.
|
* Double check that you have a radio module NRF24L01+ with a plus sign at the end. NRF24L01 module without the plus are not compatible with this project.
|
||||||
* There is no possibility of auto-discovering the inverters. Double-Check you have entered the serial numbers of the inverters correctly.
|
* There is no possibility of auto-discovering the inverters. Double check you have entered the serial numbers of the inverters correctly.
|
||||||
* OpenDTU needs access to a working NTP server to get the current date & time.
|
* OpenDTU needs access to a working NTP server to get the current date & time.
|
||||||
* If your problem persists, check the [Issues on Github](https://github.com/tbnobody/OpenDTU/issues). Please inspect not only the open issues, also the closed issues contain useful information.
|
* If your problem persists, check the [Issues on Github](https://github.com/tbnobody/OpenDTU/issues). Please inspect not only the open issues, also the closed issues contain useful information.
|
||||||
* Another source of information are the [Discussions](https://github.com/tbnobody/OpenDTU/discussions/)
|
* Another source of information are the [Discussions](https://github.com/tbnobody/OpenDTU/discussions/)
|
||||||
|
|||||||
@ -11,7 +11,7 @@ installed_pkgs = {pkg.key for pkg in pkg_resources.working_set}
|
|||||||
missing_pkgs = required_pkgs - installed_pkgs
|
missing_pkgs = required_pkgs - installed_pkgs
|
||||||
|
|
||||||
if missing_pkgs:
|
if missing_pkgs:
|
||||||
env.Execute('"$PYTHONEXE" -m pip install dulwich --global-option="--pure"')
|
env.Execute('"$PYTHONEXE" -m pip install dulwich')
|
||||||
|
|
||||||
from dulwich import porcelain
|
from dulwich import porcelain
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
#include <Hoymiles.h>
|
#include <Hoymiles.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -59,6 +60,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
|
void publishField(std::shared_ptr<InverterAbstract> inv, uint8_t channel, byteAssign_fieldDeviceClass_t fieldType, bool clear = false);
|
||||||
|
void publishInverterButton(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* deviceClass, const char* subTopic, const char* payload);
|
||||||
|
void publishInverterNumber(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* commandTopic, const char* stateTopic, const char* unitOfMeasure, int16_t min = 1, int16_t max = 100);
|
||||||
|
void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||||
|
void createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv);
|
||||||
|
|
||||||
bool _wasConnected = false;
|
bool _wasConnected = false;
|
||||||
bool _updateForced = false;
|
bool _updateForced = false;
|
||||||
|
|||||||
@ -13,8 +13,8 @@ public:
|
|||||||
void init();
|
void init();
|
||||||
void performReconnect();
|
void performReconnect();
|
||||||
bool getConnected();
|
bool getConnected();
|
||||||
void publish(String subtopic, String payload);
|
void publish(const String& subtopic, const String& payload);
|
||||||
void publishHass(String subtopic, String payload);
|
void publishHass(const String& subtopic, const String& payload);
|
||||||
|
|
||||||
String getPrefix();
|
String getPrefix();
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ bool HM_1CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_1CH::typeName()
|
String HM_1CH::typeName()
|
||||||
{
|
{
|
||||||
return String(F("HM-300, HM-350, HM-400"));
|
return F("HM-300, HM-350, HM-400");
|
||||||
}
|
}
|
||||||
|
|
||||||
const byteAssign_t* HM_1CH::getByteAssignment()
|
const byteAssign_t* HM_1CH::getByteAssignment()
|
||||||
|
|||||||
@ -25,7 +25,7 @@ bool HM_2CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_2CH::typeName()
|
String HM_2CH::typeName()
|
||||||
{
|
{
|
||||||
return String(F("HM-600, HM-700, HM-800"));
|
return F("HM-600, HM-700, HM-800");
|
||||||
}
|
}
|
||||||
|
|
||||||
const byteAssign_t* HM_2CH::getByteAssignment()
|
const byteAssign_t* HM_2CH::getByteAssignment()
|
||||||
|
|||||||
@ -25,7 +25,7 @@ bool HM_4CH::isValidSerial(uint64_t serial)
|
|||||||
|
|
||||||
String HM_4CH::typeName()
|
String HM_4CH::typeName()
|
||||||
{
|
{
|
||||||
return String(F("HM-1000, HM-1200, HM-1500"));
|
return F("HM-1000, HM-1200, HM-1500");
|
||||||
}
|
}
|
||||||
|
|
||||||
const byteAssign_t* HM_4CH::getByteAssignment()
|
const byteAssign_t* HM_4CH::getByteAssignment()
|
||||||
|
|||||||
@ -5,6 +5,13 @@
|
|||||||
InverterAbstract::InverterAbstract(uint64_t serial)
|
InverterAbstract::InverterAbstract(uint64_t serial)
|
||||||
{
|
{
|
||||||
_serial.u64 = serial;
|
_serial.u64 = serial;
|
||||||
|
|
||||||
|
char serial_buff[sizeof(uint64_t) * 8 + 1];
|
||||||
|
snprintf(serial_buff, sizeof(serial_buff), "%0x%08x",
|
||||||
|
((uint32_t)((serial >> 32) & 0xFFFFFFFF)),
|
||||||
|
((uint32_t)(serial & 0xFFFFFFFF)));
|
||||||
|
_serialString = serial_buff;
|
||||||
|
|
||||||
_alarmLogParser.reset(new AlarmLogParser());
|
_alarmLogParser.reset(new AlarmLogParser());
|
||||||
_devInfoParser.reset(new DevInfoParser());
|
_devInfoParser.reset(new DevInfoParser());
|
||||||
_powerCommandParser.reset(new PowerCommandParser());
|
_powerCommandParser.reset(new PowerCommandParser());
|
||||||
@ -26,6 +33,11 @@ uint64_t InverterAbstract::serial()
|
|||||||
return _serial.u64;
|
return _serial.u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const String& InverterAbstract::serialString()
|
||||||
|
{
|
||||||
|
return _serialString;
|
||||||
|
}
|
||||||
|
|
||||||
void InverterAbstract::setName(const char* name)
|
void InverterAbstract::setName(const char* name)
|
||||||
{
|
{
|
||||||
uint8_t len = strlen(name);
|
uint8_t len = strlen(name);
|
||||||
|
|||||||
@ -33,6 +33,7 @@ public:
|
|||||||
explicit InverterAbstract(uint64_t serial);
|
explicit InverterAbstract(uint64_t serial);
|
||||||
void init();
|
void init();
|
||||||
uint64_t serial();
|
uint64_t serial();
|
||||||
|
const String& serialString();
|
||||||
void setName(const char* name);
|
void setName(const char* name);
|
||||||
const char* name();
|
const char* name();
|
||||||
virtual String typeName() = 0;
|
virtual String typeName() = 0;
|
||||||
@ -64,6 +65,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
serial_u _serial;
|
serial_u _serial;
|
||||||
|
String _serialString;
|
||||||
char _name[MAX_NAME_LENGTH] = "";
|
char _name[MAX_NAME_LENGTH] = "";
|
||||||
fragment_t _rxFragmentBuffer[MAX_RF_FRAGMENT_COUNT];
|
fragment_t _rxFragmentBuffer[MAX_RF_FRAGMENT_COUNT];
|
||||||
uint8_t _rxFragmentMaxPacketId = 0;
|
uint8_t _rxFragmentMaxPacketId = 0;
|
||||||
|
|||||||
@ -59,214 +59,214 @@ void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry_t* entry)
|
|||||||
|
|
||||||
switch (entry->MessageId) {
|
switch (entry->MessageId) {
|
||||||
case 1:
|
case 1:
|
||||||
entry->Message = String(F("Inverter start"));
|
entry->Message = F("Inverter start");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
entry->Message = String(F("DTU command failed"));
|
entry->Message = F("DTU command failed");
|
||||||
break;
|
break;
|
||||||
case 121:
|
case 121:
|
||||||
entry->Message = String(F("Over temperature protection"));
|
entry->Message = F("Over temperature protection");
|
||||||
break;
|
break;
|
||||||
case 124:
|
case 124:
|
||||||
entry->Message = String(F("Shut down by remote control"));
|
entry->Message = F("Shut down by remote control");
|
||||||
break;
|
break;
|
||||||
case 125:
|
case 125:
|
||||||
entry->Message = String(F("Grid configuration parameter error"));
|
entry->Message = F("Grid configuration parameter error");
|
||||||
break;
|
break;
|
||||||
case 126:
|
case 126:
|
||||||
entry->Message = String(F("Software error code 126"));
|
entry->Message = F("Software error code 126");
|
||||||
break;
|
break;
|
||||||
case 127:
|
case 127:
|
||||||
entry->Message = String(F("Firmware error"));
|
entry->Message = F("Firmware error");
|
||||||
break;
|
break;
|
||||||
case 128:
|
case 128:
|
||||||
entry->Message = String(F("Software error code 128"));
|
entry->Message = F("Software error code 128");
|
||||||
break;
|
break;
|
||||||
case 129:
|
case 129:
|
||||||
entry->Message = String(F("Abnormal bias"));
|
entry->Message = F("Abnormal bias");
|
||||||
break;
|
break;
|
||||||
case 130:
|
case 130:
|
||||||
entry->Message = String(F("Offline"));
|
entry->Message = F("Offline");
|
||||||
break;
|
break;
|
||||||
case 141:
|
case 141:
|
||||||
entry->Message = String(F("Grid: Grid overvoltage"));
|
entry->Message = F("Grid: Grid overvoltage");
|
||||||
break;
|
break;
|
||||||
case 142:
|
case 142:
|
||||||
entry->Message = String(F("Grid: 10 min value grid overvoltage"));
|
entry->Message = F("Grid: 10 min value grid overvoltage");
|
||||||
break;
|
break;
|
||||||
case 143:
|
case 143:
|
||||||
entry->Message = String(F("Grid: Grid undervoltage"));
|
entry->Message = F("Grid: Grid undervoltage");
|
||||||
break;
|
break;
|
||||||
case 144:
|
case 144:
|
||||||
entry->Message = String(F("Grid: Grid overfrequency"));
|
entry->Message = F("Grid: Grid overfrequency");
|
||||||
break;
|
break;
|
||||||
case 145:
|
case 145:
|
||||||
entry->Message = String(F("Grid: Grid underfrequency"));
|
entry->Message = F("Grid: Grid underfrequency");
|
||||||
break;
|
break;
|
||||||
case 146:
|
case 146:
|
||||||
entry->Message = String(F("Grid: Rapid grid frequency change rate"));
|
entry->Message = F("Grid: Rapid grid frequency change rate");
|
||||||
break;
|
break;
|
||||||
case 147:
|
case 147:
|
||||||
entry->Message = String(F("Grid: Power grid outage"));
|
entry->Message = F("Grid: Power grid outage");
|
||||||
break;
|
break;
|
||||||
case 148:
|
case 148:
|
||||||
entry->Message = String(F("Grid: Grid disconnection"));
|
entry->Message = F("Grid: Grid disconnection");
|
||||||
break;
|
break;
|
||||||
case 149:
|
case 149:
|
||||||
entry->Message = String(F("Grid: Island detected"));
|
entry->Message = F("Grid: Island detected");
|
||||||
break;
|
break;
|
||||||
case 205:
|
case 205:
|
||||||
entry->Message = String(F("MPPT-A: Input overvoltage"));
|
entry->Message = F("MPPT-A: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 206:
|
case 206:
|
||||||
entry->Message = String(F("MPPT-B: Input overvoltage"));
|
entry->Message = F("MPPT-B: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 207:
|
case 207:
|
||||||
entry->Message = String(F("MPPT-A: Input undervoltage"));
|
entry->Message = F("MPPT-A: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 208:
|
case 208:
|
||||||
entry->Message = String(F("MPPT-B: Input undervoltage"));
|
entry->Message = F("MPPT-B: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 209:
|
case 209:
|
||||||
entry->Message = String(F("PV-1: No input"));
|
entry->Message = F("PV-1: No input");
|
||||||
break;
|
break;
|
||||||
case 210:
|
case 210:
|
||||||
entry->Message = String(F("PV-2: No input"));
|
entry->Message = F("PV-2: No input");
|
||||||
break;
|
break;
|
||||||
case 211:
|
case 211:
|
||||||
entry->Message = String(F("PV-3: No input"));
|
entry->Message = F("PV-3: No input");
|
||||||
break;
|
break;
|
||||||
case 212:
|
case 212:
|
||||||
entry->Message = String(F("PV-4: No input"));
|
entry->Message = F("PV-4: No input");
|
||||||
break;
|
break;
|
||||||
case 213:
|
case 213:
|
||||||
entry->Message = String(F("MPPT-A: PV-1 & PV-2 abnormal wiring"));
|
entry->Message = F("MPPT-A: PV-1 & PV-2 abnormal wiring");
|
||||||
break;
|
break;
|
||||||
case 214:
|
case 214:
|
||||||
entry->Message = String(F("MPPT-B: PV-3 & PV-4 abnormal wiring"));
|
entry->Message = F("MPPT-B: PV-3 & PV-4 abnormal wiring");
|
||||||
break;
|
break;
|
||||||
case 215:
|
case 215:
|
||||||
entry->Message = String(F("PV-1: Input overvoltage"));
|
entry->Message = F("PV-1: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 216:
|
case 216:
|
||||||
entry->Message = String(F("PV-1: Input undervoltage"));
|
entry->Message = F("PV-1: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 217:
|
case 217:
|
||||||
entry->Message = String(F("PV-2: Input overvoltage"));
|
entry->Message = F("PV-2: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 218:
|
case 218:
|
||||||
entry->Message = String(F("PV-2: Input undervoltage"));
|
entry->Message = F("PV-2: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 219:
|
case 219:
|
||||||
entry->Message = String(F("PV-3: Input overvoltage"));
|
entry->Message = F("PV-3: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 220:
|
case 220:
|
||||||
entry->Message = String(F("PV-3: Input undervoltage"));
|
entry->Message = F("PV-3: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 221:
|
case 221:
|
||||||
entry->Message = String(F("PV-4: Input overvoltage"));
|
entry->Message = F("PV-4: Input overvoltage");
|
||||||
break;
|
break;
|
||||||
case 222:
|
case 222:
|
||||||
entry->Message = String(F("PV-4: Input undervoltage"));
|
entry->Message = F("PV-4: Input undervoltage");
|
||||||
break;
|
break;
|
||||||
case 301:
|
case 301:
|
||||||
entry->Message = String(F("Hardware error code 301"));
|
entry->Message = F("Hardware error code 301");
|
||||||
break;
|
break;
|
||||||
case 302:
|
case 302:
|
||||||
entry->Message = String(F("Hardware error code 302"));
|
entry->Message = F("Hardware error code 302");
|
||||||
break;
|
break;
|
||||||
case 303:
|
case 303:
|
||||||
entry->Message = String(F("Hardware error code 303"));
|
entry->Message = F("Hardware error code 303");
|
||||||
break;
|
break;
|
||||||
case 304:
|
case 304:
|
||||||
entry->Message = String(F("Hardware error code 304"));
|
entry->Message = F("Hardware error code 304");
|
||||||
break;
|
break;
|
||||||
case 305:
|
case 305:
|
||||||
entry->Message = String(F("Hardware error code 305"));
|
entry->Message = F("Hardware error code 305");
|
||||||
break;
|
break;
|
||||||
case 306:
|
case 306:
|
||||||
entry->Message = String(F("Hardware error code 306"));
|
entry->Message = F("Hardware error code 306");
|
||||||
break;
|
break;
|
||||||
case 307:
|
case 307:
|
||||||
entry->Message = String(F("Hardware error code 307"));
|
entry->Message = F("Hardware error code 307");
|
||||||
break;
|
break;
|
||||||
case 308:
|
case 308:
|
||||||
entry->Message = String(F("Hardware error code 308"));
|
entry->Message = F("Hardware error code 308");
|
||||||
break;
|
break;
|
||||||
case 309:
|
case 309:
|
||||||
entry->Message = String(F("Hardware error code 309"));
|
entry->Message = F("Hardware error code 309");
|
||||||
break;
|
break;
|
||||||
case 310:
|
case 310:
|
||||||
entry->Message = String(F("Hardware error code 310"));
|
entry->Message = F("Hardware error code 310");
|
||||||
break;
|
break;
|
||||||
case 311:
|
case 311:
|
||||||
entry->Message = String(F("Hardware error code 311"));
|
entry->Message = F("Hardware error code 311");
|
||||||
break;
|
break;
|
||||||
case 312:
|
case 312:
|
||||||
entry->Message = String(F("Hardware error code 312"));
|
entry->Message = F("Hardware error code 312");
|
||||||
break;
|
break;
|
||||||
case 313:
|
case 313:
|
||||||
entry->Message = String(F("Hardware error code 313"));
|
entry->Message = F("Hardware error code 313");
|
||||||
break;
|
break;
|
||||||
case 314:
|
case 314:
|
||||||
entry->Message = String(F("Hardware error code 314"));
|
entry->Message = F("Hardware error code 314");
|
||||||
break;
|
break;
|
||||||
case 5041:
|
case 5041:
|
||||||
entry->Message = String(F("Error code-04 Port 1"));
|
entry->Message = F("Error code-04 Port 1");
|
||||||
break;
|
break;
|
||||||
case 5042:
|
case 5042:
|
||||||
entry->Message = String(F("Error code-04 Port 2"));
|
entry->Message = F("Error code-04 Port 2");
|
||||||
break;
|
break;
|
||||||
case 5043:
|
case 5043:
|
||||||
entry->Message = String(F("Error code-04 Port 3"));
|
entry->Message = F("Error code-04 Port 3");
|
||||||
break;
|
break;
|
||||||
case 5044:
|
case 5044:
|
||||||
entry->Message = String(F("Error code-04 Port 4"));
|
entry->Message = F("Error code-04 Port 4");
|
||||||
break;
|
break;
|
||||||
case 5051:
|
case 5051:
|
||||||
entry->Message = String(F("PV Input 1 Overvoltage/Undervoltage"));
|
entry->Message = F("PV Input 1 Overvoltage/Undervoltage");
|
||||||
break;
|
break;
|
||||||
case 5052:
|
case 5052:
|
||||||
entry->Message = String(F("PV Input 2 Overvoltage/Undervoltage"));
|
entry->Message = F("PV Input 2 Overvoltage/Undervoltage");
|
||||||
break;
|
break;
|
||||||
case 5053:
|
case 5053:
|
||||||
entry->Message = String(F("PV Input 3 Overvoltage/Undervoltage"));
|
entry->Message = F("PV Input 3 Overvoltage/Undervoltage");
|
||||||
break;
|
break;
|
||||||
case 5054:
|
case 5054:
|
||||||
entry->Message = String(F("PV Input 4 Overvoltage/Undervoltage"));
|
entry->Message = F("PV Input 4 Overvoltage/Undervoltage");
|
||||||
break;
|
break;
|
||||||
case 5060:
|
case 5060:
|
||||||
entry->Message = String(F("Abnormal bias"));
|
entry->Message = F("Abnormal bias");
|
||||||
break;
|
break;
|
||||||
case 5070:
|
case 5070:
|
||||||
entry->Message = String(F("Over temperature protection"));
|
entry->Message = F("Over temperature protection");
|
||||||
break;
|
break;
|
||||||
case 5080:
|
case 5080:
|
||||||
entry->Message = String(F("Grid Overvoltage/Undervoltage"));
|
entry->Message = F("Grid Overvoltage/Undervoltage");
|
||||||
break;
|
break;
|
||||||
case 5090:
|
case 5090:
|
||||||
entry->Message = String(F("Grid Overfrequency/Underfrequency"));
|
entry->Message = F("Grid Overfrequency/Underfrequency");
|
||||||
break;
|
break;
|
||||||
case 5100:
|
case 5100:
|
||||||
entry->Message = String(F("Island detected"));
|
entry->Message = F("Island detected");
|
||||||
break;
|
break;
|
||||||
case 5120:
|
case 5120:
|
||||||
entry->Message = String(F("EEPROM reading and writing error"));
|
entry->Message = F("EEPROM reading and writing error");
|
||||||
break;
|
break;
|
||||||
case 5150:
|
case 5150:
|
||||||
entry->Message = String(F("10 min value grid overvoltage"));
|
entry->Message = F("10 min value grid overvoltage");
|
||||||
break;
|
break;
|
||||||
case 5200:
|
case 5200:
|
||||||
entry->Message = String(F("Firmware error"));
|
entry->Message = F("Firmware error");
|
||||||
break;
|
break;
|
||||||
case 8310:
|
case 8310:
|
||||||
entry->Message = String(F("Shut down"));
|
entry->Message = F("Shut down");
|
||||||
break;
|
break;
|
||||||
case 9000:
|
case 9000:
|
||||||
entry->Message = String(F("Microinverter is suspected of being stolen"));
|
entry->Message = F("Microinverter is suspected of being stolen");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
entry->Message = String(F("Unknown"));
|
entry->Message = F("Unknown");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
* Copyright (C) 2022 Thomas Basler and others
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
*/
|
*/
|
||||||
#include "MqttHassPublishing.h"
|
#include "MqttHassPublishing.h"
|
||||||
#include "ArduinoJson.h"
|
|
||||||
#include "MqttPublishing.h"
|
#include "MqttPublishing.h"
|
||||||
#include "MqttSettings.h"
|
#include "MqttSettings.h"
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
@ -52,6 +51,19 @@ void MqttHassPublishingClass::publishConfig()
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
|
publishInverterButton(inv, "Turn Inverter Off", "mdi:power-plug-off", "config", "", "cmd/power", "0");
|
||||||
|
publishInverterButton(inv, "Turn Inverter On", "mdi:power-plug", "config", "", "cmd/power", "1");
|
||||||
|
publishInverterButton(inv, "Restart Inverter", "", "config", "restart", "cmd/restart", "1");
|
||||||
|
|
||||||
|
publishInverterNumber(inv, "Limit NonPersistent Relative", "mdi:speedometer", "config", "cmd/limit_nonpersistent_relative", "status/limit_relative", "%");
|
||||||
|
publishInverterNumber(inv, "Limit Persistent Relative", "mdi:speedometer", "config", "cmd/limit_persistent_relative", "status/limit_relative", "%");
|
||||||
|
|
||||||
|
publishInverterNumber(inv, "Limit NonPersistent Absolute", "mdi:speedometer", "config", "cmd/limit_nonpersistent_absolute", "status/limit_absolute", "W", 10, 1500);
|
||||||
|
publishInverterNumber(inv, "Limit Persistent Absolute", "mdi:speedometer", "config", "cmd/limit_persistent_absolute", "status/limit_absolute", "W", 10, 1500);
|
||||||
|
|
||||||
|
publishInverterBinarySensor(inv, "Reachable", "status/reachable", "1", "0");
|
||||||
|
publishInverterBinarySensor(inv, "Producing", "status/producing", "1", "0");
|
||||||
|
|
||||||
// Loop all channels
|
// Loop all channels
|
||||||
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
for (uint8_t c = 0; c <= inv->Statistics()->getChannelCount(); c++) {
|
||||||
for (uint8_t f = 0; f < DEVICE_CLS_ASSIGN_LIST_LEN; f++) {
|
for (uint8_t f = 0; f < DEVICE_CLS_ASSIGN_LIST_LEN; f++) {
|
||||||
@ -73,10 +85,7 @@ void MqttHassPublishingClass::publishField(std::shared_ptr<InverterAbstract> inv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char serial[sizeof(uint64_t) * 8 + 1];
|
String serial = inv->serialString();
|
||||||
snprintf(serial, sizeof(serial), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
String fieldName;
|
String fieldName;
|
||||||
if (channel == CH0 && fieldType.fieldId == FLD_PDC) {
|
if (channel == CH0 && fieldType.fieldId == FLD_PDC) {
|
||||||
@ -85,7 +94,7 @@ void MqttHassPublishingClass::publishField(std::shared_ptr<InverterAbstract> inv
|
|||||||
fieldName = inv->Statistics()->getChannelFieldName(channel, fieldType.fieldId);
|
fieldName = inv->Statistics()->getChannelFieldName(channel, fieldType.fieldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
String configTopic = "sensor/dtu_" + String(serial)
|
String configTopic = "sensor/dtu_" + serial
|
||||||
+ "/" + "ch" + String(channel) + "_" + fieldName
|
+ "/" + "ch" + String(channel) + "_" + fieldName
|
||||||
+ "/config";
|
+ "/config";
|
||||||
|
|
||||||
@ -101,21 +110,15 @@ void MqttHassPublishingClass::publishField(std::shared_ptr<InverterAbstract> inv
|
|||||||
name = String(inv->name()) + " CH" + String(channel) + " " + fieldName;
|
name = String(inv->name()) + " CH" + String(channel) + " " + fieldName;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument deviceDoc(512);
|
|
||||||
deviceDoc[F("name")] = inv->name();
|
|
||||||
deviceDoc[F("ids")] = String(serial);
|
|
||||||
deviceDoc[F("cu")] = String(F("http://")) + String(WiFi.localIP().toString());
|
|
||||||
deviceDoc[F("mf")] = F("OpenDTU");
|
|
||||||
deviceDoc[F("mdl")] = inv->typeName();
|
|
||||||
deviceDoc[F("sw")] = AUTO_GIT_HASH;
|
|
||||||
JsonObject deviceObj = deviceDoc.as<JsonObject>();
|
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(1024);
|
||||||
root[F("name")] = name;
|
root[F("name")] = name;
|
||||||
root[F("stat_t")] = stateTopic;
|
root[F("stat_t")] = stateTopic;
|
||||||
root[F("unit_of_meas")] = inv->Statistics()->getChannelFieldUnit(channel, fieldType.fieldId);
|
root[F("unit_of_meas")] = inv->Statistics()->getChannelFieldUnit(channel, fieldType.fieldId);
|
||||||
root[F("uniq_id")] = String(serial) + "_ch" + String(channel) + "_" + fieldName;
|
root[F("uniq_id")] = serial + "_ch" + String(channel) + "_" + fieldName;
|
||||||
root[F("dev")] = deviceObj;
|
|
||||||
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
if (Configuration.get().Mqtt_Hass_Expire) {
|
if (Configuration.get().Mqtt_Hass_Expire) {
|
||||||
root[F("exp_aft")] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 2;
|
root[F("exp_aft")] = Hoymiles.getNumInverters() * Configuration.get().Mqtt_PublishInterval * 2;
|
||||||
}
|
}
|
||||||
@ -129,8 +132,120 @@ void MqttHassPublishingClass::publishField(std::shared_ptr<InverterAbstract> inv
|
|||||||
char buffer[512];
|
char buffer[512];
|
||||||
serializeJson(root, buffer);
|
serializeJson(root, buffer);
|
||||||
MqttSettings.publishHass(configTopic, buffer);
|
MqttSettings.publishHass(configTopic, buffer);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
MqttSettings.publishHass(configTopic, "");
|
MqttSettings.publishHass(configTopic, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MqttHassPublishingClass::publishInverterButton(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category, const char* deviceClass, const char* subTopic, const char* payload)
|
||||||
|
{
|
||||||
|
String serial = inv->serialString();
|
||||||
|
|
||||||
|
String buttonId = caption;
|
||||||
|
buttonId.replace(" ", "_");
|
||||||
|
buttonId.toLowerCase();
|
||||||
|
|
||||||
|
String configTopic = "button/dtu_" + serial
|
||||||
|
+ "/" + buttonId
|
||||||
|
+ "/config";
|
||||||
|
|
||||||
|
String cmdTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
||||||
|
|
||||||
|
DynamicJsonDocument root(1024);
|
||||||
|
root[F("name")] = caption;
|
||||||
|
root[F("uniq_id")] = serial + "_" + buttonId;
|
||||||
|
if (strcmp(icon, "")) {
|
||||||
|
root[F("ic")] = icon;
|
||||||
|
}
|
||||||
|
if (strcmp(deviceClass, "")) {
|
||||||
|
root[F("dev_cla")] = deviceClass;
|
||||||
|
}
|
||||||
|
root[F("ent_cat")] = category;
|
||||||
|
root[F("cmd_t")] = cmdTopic;
|
||||||
|
root[F("payload_press")] = payload;
|
||||||
|
|
||||||
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
serializeJson(root, buffer);
|
||||||
|
MqttSettings.publishHass(configTopic, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttHassPublishingClass::publishInverterNumber(
|
||||||
|
std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category,
|
||||||
|
const char* commandTopic, const char* stateTopic, const char* unitOfMeasure,
|
||||||
|
int16_t min, int16_t max)
|
||||||
|
{
|
||||||
|
String serial = inv->serialString();
|
||||||
|
|
||||||
|
String buttonId = caption;
|
||||||
|
buttonId.replace(" ", "_");
|
||||||
|
buttonId.toLowerCase();
|
||||||
|
|
||||||
|
String configTopic = "number/dtu_" + serial
|
||||||
|
+ "/" + buttonId
|
||||||
|
+ "/config";
|
||||||
|
|
||||||
|
String cmdTopic = MqttSettings.getPrefix() + serial + "/" + commandTopic;
|
||||||
|
String statTopic = MqttSettings.getPrefix() + serial + "/" + stateTopic;
|
||||||
|
|
||||||
|
DynamicJsonDocument root(1024);
|
||||||
|
root[F("name")] = caption;
|
||||||
|
root[F("uniq_id")] = serial + "_" + buttonId;
|
||||||
|
if (strcmp(icon, "")) {
|
||||||
|
root[F("ic")] = icon;
|
||||||
|
}
|
||||||
|
root[F("ent_cat")] = category;
|
||||||
|
root[F("cmd_t")] = cmdTopic;
|
||||||
|
root[F("stat_t")] = statTopic;
|
||||||
|
root[F("unit_of_meas")] = unitOfMeasure;
|
||||||
|
root[F("min")] = min;
|
||||||
|
root[F("max")] = max;
|
||||||
|
|
||||||
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
serializeJson(root, buffer);
|
||||||
|
MqttSettings.publishHass(configTopic, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttHassPublishingClass::publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off)
|
||||||
|
{
|
||||||
|
String serial = inv->serialString();
|
||||||
|
|
||||||
|
String sensorId = caption;
|
||||||
|
sensorId.replace(" ", "_");
|
||||||
|
sensorId.toLowerCase();
|
||||||
|
|
||||||
|
String configTopic = "binary_sensor/dtu_" + serial
|
||||||
|
+ "/" + sensorId
|
||||||
|
+ "/config";
|
||||||
|
|
||||||
|
String statTopic = MqttSettings.getPrefix() + serial + "/" + subTopic;
|
||||||
|
|
||||||
|
DynamicJsonDocument root(1024);
|
||||||
|
root[F("name")] = caption;
|
||||||
|
root[F("uniq_id")] = serial + "_" + sensorId;
|
||||||
|
root[F("stat_t")] = statTopic;
|
||||||
|
root[F("pl_on")] = payload_on;
|
||||||
|
root[F("pl_off")] = payload_off;
|
||||||
|
|
||||||
|
JsonObject deviceObj = root.createNestedObject("dev");
|
||||||
|
createDeviceInfo(deviceObj, inv);
|
||||||
|
|
||||||
|
char buffer[512];
|
||||||
|
serializeJson(root, buffer);
|
||||||
|
MqttSettings.publishHass(configTopic, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MqttHassPublishingClass::createDeviceInfo(JsonObject& object, std::shared_ptr<InverterAbstract> inv)
|
||||||
|
{
|
||||||
|
object[F("name")] = inv->name();
|
||||||
|
object[F("ids")] = inv->serialString();
|
||||||
|
object[F("cu")] = String(F("http://")) + WiFi.localIP().toString();
|
||||||
|
object[F("mf")] = F("OpenDTU");
|
||||||
|
object[F("mdl")] = inv->typeName();
|
||||||
|
object[F("sw")] = AUTO_GIT_HASH;
|
||||||
|
}
|
||||||
@ -33,11 +33,7 @@ void MqttPublishingClass::loop()
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
String subtopic = inv->serialString();
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
String subtopic = String(buffer);
|
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
MqttSettings.publish(subtopic + "/name", inv->name());
|
MqttSettings.publish(subtopic + "/name", inv->name());
|
||||||
@ -110,12 +106,6 @@ String MqttPublishingClass::getTopic(std::shared_ptr<InverterAbstract> inv, uint
|
|||||||
return String("");
|
return String("");
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
String invSerial = String(buffer);
|
|
||||||
|
|
||||||
String chanName;
|
String chanName;
|
||||||
if (channel == 0 && fieldId == FLD_PDC) {
|
if (channel == 0 && fieldId == FLD_PDC) {
|
||||||
chanName = "powerdc";
|
chanName = "powerdc";
|
||||||
@ -124,5 +114,5 @@ String MqttPublishingClass::getTopic(std::shared_ptr<InverterAbstract> inv, uint
|
|||||||
chanName.toLowerCase();
|
chanName.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
return invSerial + "/" + String(channel) + "/" + chanName;
|
return inv->serialString() + "/" + String(channel) + "/" + chanName;
|
||||||
}
|
}
|
||||||
@ -233,14 +233,14 @@ String MqttSettingsClass::getPrefix()
|
|||||||
return Configuration.get().Mqtt_Topic;
|
return Configuration.get().Mqtt_Topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::publish(String subtopic, String payload)
|
void MqttSettingsClass::publish(const String& subtopic, const String& payload)
|
||||||
{
|
{
|
||||||
String topic = getPrefix();
|
String topic = getPrefix();
|
||||||
topic += subtopic;
|
topic += subtopic;
|
||||||
mqttClient->publish(topic.c_str(), 0, Configuration.get().Mqtt_Retain, payload.c_str());
|
mqttClient->publish(topic.c_str(), 0, Configuration.get().Mqtt_Retain, payload.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::publishHass(String subtopic, String payload)
|
void MqttSettingsClass::publishHass(const String& subtopic, const String& payload)
|
||||||
{
|
{
|
||||||
String topic = Configuration.get().Mqtt_Hass_Topic;
|
String topic = Configuration.get().Mqtt_Hass_Topic;
|
||||||
topic += subtopic;
|
topic += subtopic;
|
||||||
|
|||||||
@ -375,7 +375,7 @@ String NetworkSettingsClass::macAddress()
|
|||||||
return WiFi.macAddress();
|
return WiFi.macAddress();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return String("");
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,13 +29,7 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request)
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
// Inverter Serial is read as HEX
|
JsonObject devInfoObj = root[inv->serialString()].createNestedObject();
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
JsonObject devInfoObj = root[buffer].createNestedObject();
|
|
||||||
devInfoObj[F("valid_data")] = inv->DevInfo()->getLastUpdate() > 0;
|
devInfoObj[F("valid_data")] = inv->DevInfo()->getLastUpdate() > 0;
|
||||||
devInfoObj[F("fw_bootloader_version")] = inv->DevInfo()->getFwBootloaderVersion();
|
devInfoObj[F("fw_bootloader_version")] = inv->DevInfo()->getFwBootloaderVersion();
|
||||||
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
|
devInfoObj[F("fw_build_version")] = inv->DevInfo()->getFwBuildVersion();
|
||||||
|
|||||||
@ -34,16 +34,12 @@ void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request)
|
|||||||
auto inv = Hoymiles.getInverterBySerial(serial);
|
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||||
|
|
||||||
if (inv != nullptr) {
|
if (inv != nullptr) {
|
||||||
// Inverter Serial is read as HEX
|
String serial = inv->serialString();
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
uint8_t logEntryCount = inv->EventLog()->getEntryCount();
|
uint8_t logEntryCount = inv->EventLog()->getEntryCount();
|
||||||
|
|
||||||
root[buffer]["count"] = logEntryCount;
|
root[serial]["count"] = logEntryCount;
|
||||||
JsonArray eventsArray = root[buffer].createNestedArray(F("events"));
|
JsonArray eventsArray = root[serial].createNestedArray(F("events"));
|
||||||
|
|
||||||
for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) {
|
for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) {
|
||||||
JsonObject eventsObject = eventsArray.createNestedObject();
|
JsonObject eventsObject = eventsArray.createNestedObject();
|
||||||
|
|||||||
@ -29,14 +29,10 @@ void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
// Inverter Serial is read as HEX
|
String serial = inv->serialString();
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
root[buffer]["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
root[serial]["limit_relative"] = inv->SystemConfigPara()->getLimitPercent();
|
||||||
root[buffer]["max_power"] = inv->DevInfo()->getMaxPower();
|
root[serial]["max_power"] = inv->DevInfo()->getMaxPower();
|
||||||
|
|
||||||
LastCommandSuccess status = inv->SystemConfigPara()->getLastLimitCommandSuccess();
|
LastCommandSuccess status = inv->SystemConfigPara()->getLastLimitCommandSuccess();
|
||||||
String limitStatus = "Unknown";
|
String limitStatus = "Unknown";
|
||||||
@ -49,7 +45,7 @@ void WebApiLimitClass::onLimitStatus(AsyncWebServerRequest* request)
|
|||||||
else if (status == LastCommandSuccess::CMD_PENDING) {
|
else if (status == LastCommandSuccess::CMD_PENDING) {
|
||||||
limitStatus = "Pending";
|
limitStatus = "Pending";
|
||||||
}
|
}
|
||||||
root[buffer]["limit_set_status"] = limitStatus;
|
root[serial]["limit_set_status"] = limitStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
|
|||||||
@ -29,12 +29,6 @@ void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request)
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
// Inverter Serial is read as HEX
|
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
LastCommandSuccess status = inv->PowerCommand()->getLastPowerCommandSuccess();
|
LastCommandSuccess status = inv->PowerCommand()->getLastPowerCommandSuccess();
|
||||||
String limitStatus = "Unknown";
|
String limitStatus = "Unknown";
|
||||||
if (status == LastCommandSuccess::CMD_OK) {
|
if (status == LastCommandSuccess::CMD_OK) {
|
||||||
@ -44,7 +38,7 @@ void WebApiPowerClass::onPowerStatus(AsyncWebServerRequest* request)
|
|||||||
} else if (status == LastCommandSuccess::CMD_PENDING) {
|
} else if (status == LastCommandSuccess::CMD_PENDING) {
|
||||||
limitStatus = "Pending";
|
limitStatus = "Pending";
|
||||||
}
|
}
|
||||||
root[buffer]["power_set_status"] = limitStatus;
|
root[inv->serialString()]["power_set_status"] = limitStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
|
|||||||
@ -77,12 +77,7 @@ void WebApiWsLiveClass::generateJsonResponse(JsonVariant& root)
|
|||||||
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
auto inv = Hoymiles.getInverterByPos(i);
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
|
||||||
char buffer[sizeof(uint64_t) * 8 + 1];
|
root[i][F("serial")] = inv->serialString();
|
||||||
snprintf(buffer, sizeof(buffer), "%0x%08x",
|
|
||||||
((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)),
|
|
||||||
((uint32_t)(inv->serial() & 0xFFFFFFFF)));
|
|
||||||
|
|
||||||
root[i][F("serial")] = String(buffer);
|
|
||||||
root[i][F("name")] = inv->name();
|
root[i][F("name")] = inv->name();
|
||||||
root[i][F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
root[i][F("data_age")] = (millis() - inv->Statistics()->getLastUpdate()) / 1000;
|
||||||
root[i][F("reachable")] = inv->isReachable();
|
root[i][F("reachable")] = inv->isReachable();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user