mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-09 23:16:38 +02:00
Major Updates active power limit
See the User_Manual.md for more information about the functionality of the active power limit.
This commit is contained in:
parent
8a02c62995
commit
6ac3876092
7 changed files with 247 additions and 18 deletions
132
tools/esp8266/User_Manual.md
Normal file
132
tools/esp8266/User_Manual.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# User Manual Ahoy DTU (on ESP8266)
|
||||
15.08.2022
|
||||
## Introduction
|
||||
see the repository [here](https://github.com/grindylow/ahoy/blob/main/tools/esp8266/README.md)
|
||||
|
||||
## Setup
|
||||
Assuming you have a running ahoy-dtu and you can access te setup page.
|
||||
In the initial case or after click "erease settings" the fields for the inverter setup are empty.
|
||||
|
||||
Set at least the serial number and a name for each inverter, check the "reboot after save" and click the "Save" button.
|
||||
|
||||
## Active Power Limit via Setup Page
|
||||
I you leave the field "Active Power Limit" empty during the setup and reboot the ahoy-dtu a value of 65535 will be filled in.
|
||||
That is the value you have to fill in case you want to operate the inverter without a active power limit.
|
||||
If the value is 65535 or -1 after another reboot the value will be seted automatically to "100" and in the drop-down menu "relativ in percent persistent" will be seted. Of course you can do this also by your self.
|
||||
|
||||
You can change the setting in the following manner.
|
||||
Decide if you want to set
|
||||
- an absolut value in Watt
|
||||
- an relativ value in percent based on the maximum Power cababilities of the inverter
|
||||
and if this settings shall be
|
||||
- persistent
|
||||
- not persistent
|
||||
after a power cylce of the inverter (P_DC=0 and P_AC=0 for at least 10 seconds)
|
||||
|
||||
The user has to ensure sensfule settings. Remember that for the inverters of 3rd generation the relative active power limit is in the range of 2% up to 100%.
|
||||
Also an absolut active power limit below approx. 30Watt is not senseful because of the control capabilities and reactive power load.
|
||||
|
||||
## Active Power Limit via MQTT
|
||||
The ahoy-dtu subscribes on the topic <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/# if the mqtt broker is set-up correctly. The default topic is inverter/devcontrol/#.
|
||||
|
||||
To set the absolut active power limit you have four options.
|
||||
|
||||
|
||||
| topic | payload | note |
|
||||
| --------------------------------------------------------------- | ----------- | -------------------------------------------- |
|
||||
| <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/11 OR <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/11/0 | [0..65535] | active power limit in Watt, not persistent |
|
||||
| <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/11/256 | [0...65535] | active power limit in Watt, persistent |
|
||||
| <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/11/1 | [2...100] | active power limit in percent not persistent |
|
||||
| <CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/11/257 | [2...100] | active power limit in percent persistent |
|
||||
|
||||
### Developer Information MQTT Interface
|
||||
<CHOOSEN_TOPIC_FROM_SETUP>/devcontrol/<INVERTER_ID>/<DevControlCmdType>/<DATA2>
|
||||
|
||||
The implementation allows to set any of the available <DevCntrlType> Commands:
|
||||
```C
|
||||
typedef enum {
|
||||
TurnOn = 0, // 0x00
|
||||
TurnOff = 1, // 0x01
|
||||
Restart = 2, // 0x02
|
||||
Lock = 3, // 0x03
|
||||
Unlock = 4, // 0x04
|
||||
ActivePowerContr = 11, // 0x0b
|
||||
ReactivePowerContr = 12, // 0x0c
|
||||
PFSet = 13, // 0x0d
|
||||
CleanState_LockAndAlarm = 20, // 0x14
|
||||
SelfInspection = 40, // 0x28, self-inspection of grid-connected protection files
|
||||
Init = 0xff
|
||||
} DevControlCmdType;
|
||||
```
|
||||
The MQTT payload will be seted on first to bytes and DATA2 will be seted on the second two bytes if the corresponding DevControlCmdType supports 4 byte data.
|
||||
|
||||
So as example sending any payload on inverter/devcontrol/0/1 will switch off the inverter.
|
||||
|
||||
## Active Power Limit via REST API
|
||||
It is also implemented to set the power limit via REST API call. Therefore send a POST request to the endpoint /api.
|
||||
The response will always be a json with {success:true}
|
||||
The payload shall be a json formated string in the following manner
|
||||
```json
|
||||
{
|
||||
"inverter":<INVERTER_ID>,
|
||||
"tx_request": <TX_REQUEST_BYTE>,
|
||||
"cmd": <SUB_CMD_BYTE>,
|
||||
"payload": <PAYLOAD_INTEGER_TWO_BYTES>,
|
||||
"payload2": <PAYLOAD_INTEGER_TWO_BYTES>
|
||||
}
|
||||
```
|
||||
With the following value ranges
|
||||
|
||||
|
||||
| Value | range | note |
|
||||
| --------------------------- | ----------- | ------------------------------- |
|
||||
| <TX_REQUEST_BYTE> | 81 or 21 | integer uint8, (0x15 or 0x51) |
|
||||
| <SUB_CMD_BYTE> | [0...255] | integer uint8, subcmds eg. 0x0b |
|
||||
| <PAYLOAD_INTEGER_TWO_BYTES> | [0...65535] | uint16 |
|
||||
| <INVERTER_ID> | [0...3] | integer uint8 |
|
||||
|
||||
Example to set the active power limit non persistent to 10%
|
||||
```json
|
||||
{
|
||||
"inverter":0,
|
||||
"tx_request": 81,
|
||||
"cmd": 11,
|
||||
"payload": 10,
|
||||
"payload2": 1
|
||||
}
|
||||
```
|
||||
Example to set the active power limit persistent to 600Watt
|
||||
```json
|
||||
{
|
||||
"inverter":0,
|
||||
"tx_request": 81,
|
||||
"cmd": 11,
|
||||
"payload": 600,
|
||||
"payload2": 256
|
||||
}
|
||||
```
|
||||
|
||||
### Developer Information REST API
|
||||
In the same approach as for MQTT any other SubCmd can be applied and the respsine payload can be observed in the serial logs. Eg. request the Alarm Data.
|
||||
|
||||
|
||||
## Issues and Debuging for active power limit settings
|
||||
Turn on the serial debuging in the setup. Try to have find out if the behavior is deterministic. That means can you reproduce the behavior. Be patient and wait on inverter reactions at least some minutes and beware that the DC-Power is sufficient.
|
||||
In case of issues please report:
|
||||
1. Version of firmware
|
||||
2. The output of the serial debug esp. the TX messages starting with "0x51" and the RX messages starting with "0xD1" or "0xF1"
|
||||
3. Which case you have tried: Setup-Page, MQTT, REST API and at what was shown on the "Visualization Page" at the Location "Limit"
|
||||
4. The setting means payload, relativ, absolut, persisten, not persisten (see tables above)
|
||||
|
||||
|
||||
**Developer Information General for Active Power Limit**
|
||||
⚡To be verified by field tests and feedback
|
||||
Internally this values will be seted for the second two bytes for MainCmd: 0x51 SubCmd: 0x0b --> DevControl set ActivePowerLimit
|
||||
```C
|
||||
typedef enum { // ToDo: to be verified by field tests
|
||||
AbsolutNonPersistent = 0x0000, // 0
|
||||
RelativNonPersistent = 0x0001, // 1
|
||||
AbsolutPersistent = 0x0100, // 256
|
||||
RelativPersistent = 0x0101 // 257
|
||||
} PowerLimitControlType;
|
||||
```
|
|
@ -146,11 +146,12 @@ void app::loop(void) {
|
|||
if (iv->devControlCmd >= ActivePowerContr && iv->devControlCmd <= PFSet){ // ok inverter accepted the set point copy it to dtu eeprom
|
||||
if (iv->powerLimit[1]>0){ // User want to have it persistent
|
||||
mEep->write(ADDR_INV_PWR_LIM + iv->id * 2,iv->powerLimit[0]);
|
||||
mEep->write(ADDR_INV_PWR_LIM_CON + iv->id * 2,iv->powerLimit[1]);
|
||||
updateCrc();
|
||||
mEep->commit();
|
||||
DPRINTLN(DBG_INFO, F("Inverter has accepted power limit set point, written to dtu eeprom"));
|
||||
DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]) + F(", written to dtu eeprom"));
|
||||
} else {
|
||||
DPRINTLN(DBG_INFO, F("Inverter has accepted power limit set point"));
|
||||
DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]));
|
||||
}
|
||||
iv->devControlCmd = Init;
|
||||
}
|
||||
|
@ -159,6 +160,7 @@ void app::loop(void) {
|
|||
if (iv->devControlCmd == ActivePowerContr){
|
||||
//case inverter did not accept the sent limit; set back to last stored limit
|
||||
mEep->read(ADDR_INV_PWR_LIM + iv->id * 2, (uint16_t *)&(iv->powerLimit[0]));
|
||||
mEep->read(ADDR_INV_PWR_LIM_CON + iv->id * 2, (uint16_t *)&(iv->powerLimit[1]));
|
||||
DPRINTLN(DBG_INFO, F("Inverter has not accepted power limit set point"));
|
||||
}
|
||||
iv->devControlCmd = Init;
|
||||
|
@ -430,6 +432,7 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) {
|
|||
if (std::strcmp(token,"devcontrol")==0){
|
||||
token = strtok(NULL, "/");
|
||||
uint8_t iv_id = std::stoi(token);
|
||||
uint8_t powerLimitControl = 0;
|
||||
if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS){
|
||||
Inverter<> *iv = this->mSys->getInverterByPos(iv_id);
|
||||
if(NULL != iv) {
|
||||
|
@ -437,11 +440,24 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) {
|
|||
token = strtok(NULL, "/");
|
||||
switch ( std::stoi(token) ){
|
||||
case ActivePowerContr: // Active Power Control
|
||||
token = strtok(NULL, "/"); // get ControlMode aka "PowerPF.Desc" in DTU-Pro Code from topic string
|
||||
if (token == NULL) // default via mqtt ommit the LimitControlMode
|
||||
powerLimitControl = AbsolutNonPersistent;
|
||||
else
|
||||
powerLimitControl = std::stoi(token);
|
||||
// 0x0001 -> relativ limit in percent
|
||||
// 0x0000 -> absolut limit in Watt
|
||||
// 0x0101 -> persisten limit in percent (?)
|
||||
// ...
|
||||
if (true){ // if (std::stoi((char*)payload) > 0) error handling powerlimit needed?
|
||||
iv->devControlCmd = ActivePowerContr;
|
||||
iv->powerLimit[0] = std::stoi((char*)payload);
|
||||
iv->powerLimit[1] = 0x0000; // if power limit is set via external interface --> set it temporay
|
||||
DPRINTLN(DBG_DEBUG, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") );
|
||||
if (powerLimitControl >= AbsolutNonPersistent && powerLimitControl <= RelativNonPersistent)
|
||||
iv->powerLimit[1] = powerLimitControl;
|
||||
if (iv->powerLimit[1] & 0x0001)
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("%") );
|
||||
else
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") );
|
||||
}
|
||||
iv->devControlRequest = true;
|
||||
break;
|
||||
|
@ -557,7 +573,12 @@ String app::getLiveData(void) {
|
|||
}
|
||||
|
||||
modHtml += F("<div class=\"iv\">"
|
||||
"<div class=\"ch-iv\"><span class=\"head\">") + String(iv->name) + F(" Limit ") + String(iv->powerLimit[0]) + F(" W</span>");
|
||||
"<div class=\"ch-iv\"><span class=\"head\">") + String(iv->name) + F(" Limit ") + String(iv->powerLimit[0]);
|
||||
if (iv->powerLimit[1] & 0x0001){
|
||||
modHtml += F(" %</span>");
|
||||
} else {
|
||||
modHtml += F(" W</span>");
|
||||
}
|
||||
uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PCT, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_PRA, FLD_ALARM_MES_ID};
|
||||
|
||||
for(uint8_t fld = 0; fld < 12; fld++) {
|
||||
|
@ -825,13 +846,19 @@ void app::loadEEpconfig(void) {
|
|||
mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4);
|
||||
if(0ULL != invSerial) {
|
||||
iv = mSys->addInverter(name, invSerial, modPwr);
|
||||
if(NULL != iv) {
|
||||
if(NULL != iv) { // will run once on every dtu boot
|
||||
mEep->read(ADDR_INV_PWR_LIM + (i * 2),(uint16_t *)&(iv->powerLimit[0]));
|
||||
if (iv->powerLimit[0] != 0xffff) { // only set it, if it is changed by user. Default value in the html setup page is -1 = 0xffff
|
||||
iv->powerLimit[1] = 0x0001; // set the limit as persistent
|
||||
mEep->read(ADDR_INV_PWR_LIM_CON + (i * 2),(uint16_t *)&(iv->powerLimit[1]));
|
||||
// only set it, if it is changed by user. Default value in the html setup page is -1 = 0xffff
|
||||
// it is "doppelt-gemoppelt" because the inverter shall remember the setting if the dtu makes a power cycle / reboot
|
||||
if (iv->powerLimit[0] != 0xffff) {
|
||||
iv->devControlCmd = ActivePowerContr; // set active power limit
|
||||
iv->devControlRequest = true; // set to true to update the active power limit from setup html page
|
||||
DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0]));
|
||||
if (iv->powerLimit[1] & 0x0001){
|
||||
DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0]) + " in %");
|
||||
} else {
|
||||
DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0]) + " in Watt");
|
||||
}
|
||||
}
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH);
|
||||
|
@ -858,6 +885,7 @@ void app::saveValues(void) {
|
|||
if(NULL != iv) {
|
||||
mEep->write(ADDR_INV_ADDR + (i * 8), iv->serial.u64);
|
||||
mEep->write(ADDR_INV_PWR_LIM + i * 2, iv->powerLimit[0]);
|
||||
mEep->write(ADDR_INV_PWR_LIM_CON + i * 2, iv->powerLimit[1]);
|
||||
mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), iv->name, MAX_NAME_LENGTH);
|
||||
// max channel power / name
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
|
|
|
@ -57,6 +57,13 @@ typedef enum {
|
|||
Init = 0xff
|
||||
} DevControlCmdType;
|
||||
|
||||
typedef enum { // ToDo: to be verified by field tests
|
||||
AbsolutNonPersistent = 0x0000, // 0
|
||||
RelativNonPersistent = 0x0001, // 1
|
||||
AbsolutPersistent = 0x0100, // 256
|
||||
RelativPersistent = 0x0101 // 257
|
||||
} PowerLimitControlType;
|
||||
|
||||
// minimum serial interval
|
||||
#define MIN_SERIAL_INTERVAL 5
|
||||
|
||||
|
@ -161,8 +168,9 @@ typedef struct {
|
|||
#define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN
|
||||
#define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN
|
||||
#define ADDR_INV_PWR_LIM ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN
|
||||
#define ADDR_INV_PWR_LIM_CON ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN
|
||||
|
||||
#define ADDR_NEXT ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN
|
||||
#define ADDR_NEXT ADDR_INV_PWR_LIM_CON + INV_PWR_LIM_LEN
|
||||
|
||||
|
||||
#define ADDR_SETTINGS_CRC ADDR_NEXT + 2
|
||||
|
|
|
@ -84,7 +84,7 @@ class Inverter {
|
|||
Inverter() {
|
||||
ts = 0;
|
||||
powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited
|
||||
powerLimit[1] = 0x0001; // 0x0000 --> set temporary , 0x0001 --> set persistent
|
||||
powerLimit[1] = 0x0000; //
|
||||
devControlRequest = false;
|
||||
devControlCmd = 0xff;
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -137,7 +137,7 @@
|
|||
|
||||
<p class="des"> </p>
|
||||
<label for="reboot">Reboot device after successful save</label>
|
||||
<input type="checkbox" class="cb" name="reboot" checked/>
|
||||
<input type="checkbox" class="cb" name="reboot"/>
|
||||
<input type="submit" value="save" class="btn" />
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -169,24 +169,41 @@ void web::showSetup(void) {
|
|||
iv = mMain->mSys->getInverterByPos(i);
|
||||
|
||||
inv += F("<p class=\"subdes\">Inverter ") + String(i) + "</p>";
|
||||
inv += F("<label for=\"inv") + String(i) + F("Addr\">Address</label>");
|
||||
inv += F("<label for=\"inv") + String(i) + F("Addr\">Address*</label>");
|
||||
inv += F("<input type=\"text\" class=\"text\" name=\"inv") + String(i) + F("Addr\" value=\"");
|
||||
if(NULL != iv)
|
||||
inv += String(iv->serial.u64, HEX);
|
||||
inv += F("\"/ maxlength=\"12\" onkeyup=\"checkSerial()\">");
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("Name\">Name</label>");
|
||||
inv += F("<label for=\"inv") + String(i) + F("Name\">Name*</label>");
|
||||
inv += F("<input type=\"text\" class=\"text\" name=\"inv") + String(i) + F("Name\" value=\"");
|
||||
if(NULL != iv)
|
||||
inv += String(iv->name);
|
||||
inv += F("\"/ maxlength=\"") + String(MAX_NAME_LENGTH) + "\">";
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("ActivePowerLimit\">Active Power Limit (W)</label>");
|
||||
inv += F("<label for=\"inv") + String(i) + F("ActivePowerLimit\">Active Power Limit</label>");
|
||||
inv += F("<input type=\"text\" class=\"text\" name=\"inv") + String(i) + F("ActivePowerLimit\" value=\"");
|
||||
if(NULL != iv)
|
||||
inv += String(iv->powerLimit[0]);
|
||||
inv += F("\"/ maxlength=\"") + String(6) + "\">";
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("ActivePowerLimitConType\">Active Power Limit Control Type</label>");
|
||||
inv += F("<select name=\"inv") + String(i);
|
||||
// UGLY! But I do not know it a better way
|
||||
// ToDo: Need Cookies, IndexDB or PWA for that or in general client browser storage
|
||||
if(NULL != iv){
|
||||
if(iv->powerLimit[1] == AbsolutNonPersistent)
|
||||
inv += F("PowerLimitControl\"><option value=\"0\">absolute in Watt non persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"257\">relativ in percent persistent</option></select>");
|
||||
if(iv->powerLimit[1] == RelativNonPersistent)
|
||||
inv += F("PowerLimitControl\"><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"257\">relativ in percent persistent</option></select>");
|
||||
if(iv->powerLimit[1] == AbsolutPersistent)
|
||||
inv += F("PowerLimitControl\"><option value=\"256\">absolute in Watt persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option><option value=\"257\">relativ in percent persistent</option></select>");
|
||||
if(iv->powerLimit[1] == RelativPersistent)
|
||||
inv += F("PowerLimitControl\"><option value=\"257\">relativ in percent persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option></select>");
|
||||
} else
|
||||
inv += F("PowerLimitControl\"><option value=\"0\">absolute in Watt non persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"257\">relativ in percent persistent</option></select>");
|
||||
// UGLY! But I do not know it a better way --//
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("ModPwr0\" name=\"lbl") + String(i);
|
||||
inv += F("ModPwr\">Max Module Power (Wp)</label>");
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
|
@ -285,8 +302,25 @@ void web::showSave(void) {
|
|||
|
||||
// active power limit
|
||||
uint16_t actPwrLimit = mWeb->arg("inv" + String(i) + "ActivePowerLimit").toInt();
|
||||
if (actPwrLimit != 0xffff && actPwrLimit > 0)
|
||||
uint16_t actPwrLimitControl = mWeb->arg("inv" + String(i) + "PowerLimitControl").toInt();
|
||||
if (actPwrLimit != 0xffff && actPwrLimit > 0){
|
||||
iv->powerLimit[0] = actPwrLimit;
|
||||
iv->powerLimit[1] = actPwrLimitControl;
|
||||
iv->devControlCmd = ActivePowerContr;
|
||||
iv->devControlRequest = true;
|
||||
if (iv->powerLimit[1] & 0x0001)
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("%") );
|
||||
else
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") );
|
||||
DPRINTLN(DBG_INFO, F("Power Limit Control Setting ") + String(iv->powerLimit[1]));
|
||||
}
|
||||
if (actPwrLimit == 0xffff){ // set to 100%
|
||||
iv->powerLimit[0] = 100;
|
||||
iv->powerLimit[1] = RelativPersistent;
|
||||
iv->devControlCmd = ActivePowerContr;
|
||||
iv->devControlRequest = true;
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to unlimted"));
|
||||
}
|
||||
|
||||
// name
|
||||
mWeb->arg("inv" + String(i) + "Name").toCharArray(iv->name, MAX_NAME_LENGTH);
|
||||
|
@ -337,6 +371,8 @@ void web::showSave(void) {
|
|||
|
||||
mConfig->serialDebug = (mWeb->arg("serEn") == "on");
|
||||
mConfig->serialShowIv = (mWeb->arg("serDbg") == "on");
|
||||
// Needed to log TX buffers to serial console
|
||||
mMain->mSys->Radio.mSerialDebug = mConfig->serialDebug;
|
||||
}
|
||||
|
||||
mMain->saveValues();
|
||||
|
@ -397,5 +433,30 @@ void web::showWebApi(void) {
|
|||
mMain->mSys->InfoCmd = payload["cmd"];
|
||||
DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(mMain->mSys->InfoCmd));
|
||||
}
|
||||
if (payload["tx_request"] == (uint8_t)TX_REQ_DEVCONTROL){
|
||||
if(payload["cmd"] == (uint8_t)ActivePowerContr){
|
||||
uint8_t iv_id = payload["inverter"];
|
||||
if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS){
|
||||
Inverter<> *iv = mMain->mSys->getInverterByPos(iv_id);
|
||||
uint16_t webapiPayload = payload["payload"];
|
||||
uint16_t webapiPayload2 = payload["payload2"];
|
||||
if (webapiPayload > 0 && webapiPayload < 10000){
|
||||
iv->devControlCmd = ActivePowerContr;
|
||||
iv->powerLimit[0] = webapiPayload;
|
||||
if (webapiPayload2 > 0){
|
||||
iv->powerLimit[1] = webapiPayload2; // dev option, no sanity check
|
||||
} else { // if not set, set it to 0x0000 default
|
||||
iv->powerLimit[1] = AbsolutNonPersistent; // payload will be seted temporay in Watt absolut
|
||||
}
|
||||
if (iv->powerLimit[1] & 0x0001 ){
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("% via REST API") );
|
||||
} else {
|
||||
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W via REST API") );
|
||||
}
|
||||
iv->devControlRequest = true; // queue it in the request loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mWeb->send ( 200, "text/json", "{success:true}" );
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue