Fix: inverter power limits precision
Hoymiles inverters allow setting relative limits with a precision of 0.1 %. this changeset allows to utilize this precision. * preserve accuracy when decoding power limit * Web API: process floating point limits * MQTT: process floating point limits * use appropriate accuracy for limits in web UI * HASS: step for relative inverter limit is 0.1 %
This commit is contained in:
parent
86a49a781a
commit
6ee6eaf0b2
@ -63,7 +63,7 @@ private:
|
||||
void publishDtuBinarySensor(const char* name, const char* device_class, const char* category, const char* payload_on, const char* payload_off, const char* subTopic = "");
|
||||
void publishInverterField(std::shared_ptr<InverterAbstract> inv, const ChannelType_t type, const ChannelNum_t channel, const byteAssign_fieldDeviceClass_t fieldType, const 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, const int16_t min = 1, const int16_t max = 100);
|
||||
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, const int16_t min = 1, const int16_t max = 100, float step = 1.0);
|
||||
void publishInverterBinarySensor(std::shared_ptr<InverterAbstract> inv, const char* caption, const char* subTopic, const char* payload_on, const char* payload_off);
|
||||
|
||||
static void createInverterInfo(JsonDocument& doc, std::shared_ptr<InverterAbstract> inv);
|
||||
|
||||
@ -85,7 +85,7 @@ bool ActivePowerControlCommand::handleResponse(const fragment_t fragment[], cons
|
||||
|
||||
float ActivePowerControlCommand::getLimit() const
|
||||
{
|
||||
const uint16_t l = (((uint16_t)_payload[12] << 8) | _payload[13]);
|
||||
const float l = (((uint16_t)_payload[12] << 8) | _payload[13]);
|
||||
return l / 10;
|
||||
}
|
||||
|
||||
|
||||
@ -73,8 +73,8 @@ void MqttHandleHassClass::publishConfig()
|
||||
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", "%", 0, 100);
|
||||
publishInverterNumber(inv, "Limit Persistent Relative", "mdi:speedometer", "config", "cmd/limit_persistent_relative", "status/limit_relative", "%", 0, 100);
|
||||
publishInverterNumber(inv, "Limit NonPersistent Relative", "mdi:speedometer", "config", "cmd/limit_nonpersistent_relative", "status/limit_relative", "%", 0, 100, 0.1);
|
||||
publishInverterNumber(inv, "Limit Persistent Relative", "mdi:speedometer", "config", "cmd/limit_persistent_relative", "status/limit_relative", "%", 0, 100, 0.1);
|
||||
|
||||
publishInverterNumber(inv, "Limit NonPersistent Absolute", "mdi:speedometer", "config", "cmd/limit_nonpersistent_absolute", "status/limit_absolute", "W", 0, MAX_INVERTER_LIMIT);
|
||||
publishInverterNumber(inv, "Limit Persistent Absolute", "mdi:speedometer", "config", "cmd/limit_persistent_absolute", "status/limit_absolute", "W", 0, MAX_INVERTER_LIMIT);
|
||||
@ -215,7 +215,7 @@ void MqttHandleHassClass::publishInverterButton(std::shared_ptr<InverterAbstract
|
||||
void MqttHandleHassClass::publishInverterNumber(
|
||||
std::shared_ptr<InverterAbstract> inv, const char* caption, const char* icon, const char* category,
|
||||
const char* commandTopic, const char* stateTopic, const char* unitOfMeasure,
|
||||
const int16_t min, const int16_t max)
|
||||
const int16_t min, const int16_t max, float step)
|
||||
{
|
||||
const String serial = inv->serialString();
|
||||
|
||||
@ -243,6 +243,7 @@ void MqttHandleHassClass::publishInverterNumber(
|
||||
root["unit_of_meas"] = unitOfMeasure;
|
||||
root["min"] = min;
|
||||
root["max"] = max;
|
||||
root["step"] = step;
|
||||
|
||||
createInverterInfo(root, inv);
|
||||
|
||||
|
||||
@ -183,7 +183,7 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
char* strlimit = new char[len + 1];
|
||||
memcpy(strlimit, payload, len);
|
||||
strlimit[len] = '\0';
|
||||
const int32_t payload_val = strtol(strlimit, NULL, 10);
|
||||
const float payload_val = strtof(strlimit, NULL);
|
||||
delete[] strlimit;
|
||||
|
||||
if (payload_val < 0) {
|
||||
@ -193,17 +193,17 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
|
||||
if (!strcmp(setting, TOPIC_SUB_LIMIT_PERSISTENT_RELATIVE)) {
|
||||
// Set inverter limit relative persistent
|
||||
MessageOutput.printf("Limit Persistent: %d %%\r\n", payload_val);
|
||||
MessageOutput.printf("Limit Persistent: %.1f %%\r\n", payload_val);
|
||||
inv->sendActivePowerControlRequest(payload_val, PowerLimitControlType::RelativPersistent);
|
||||
|
||||
} else if (!strcmp(setting, TOPIC_SUB_LIMIT_PERSISTENT_ABSOLUTE)) {
|
||||
// Set inverter limit absolute persistent
|
||||
MessageOutput.printf("Limit Persistent: %d W\r\n", payload_val);
|
||||
MessageOutput.printf("Limit Persistent: %.1f W\r\n", payload_val);
|
||||
inv->sendActivePowerControlRequest(payload_val, PowerLimitControlType::AbsolutPersistent);
|
||||
|
||||
} else if (!strcmp(setting, TOPIC_SUB_LIMIT_NONPERSISTENT_RELATIVE)) {
|
||||
// Set inverter limit relative non persistent
|
||||
MessageOutput.printf("Limit Non-Persistent: %d %%\r\n", payload_val);
|
||||
MessageOutput.printf("Limit Non-Persistent: %.1f %%\r\n", payload_val);
|
||||
if (!properties.retain) {
|
||||
inv->sendActivePowerControlRequest(payload_val, PowerLimitControlType::RelativNonPersistent);
|
||||
} else {
|
||||
@ -212,7 +212,7 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
|
||||
} else if (!strcmp(setting, TOPIC_SUB_LIMIT_NONPERSISTENT_ABSOLUTE)) {
|
||||
// Set inverter limit absolute non persistent
|
||||
MessageOutput.printf("Limit Non-Persistent: %d W\r\n", payload_val);
|
||||
MessageOutput.printf("Limit Non-Persistent: %.1f W\r\n", payload_val);
|
||||
if (!properties.retain) {
|
||||
inv->sendActivePowerControlRequest(payload_val, PowerLimitControlType::AbsolutNonPersistent);
|
||||
} else {
|
||||
@ -221,8 +221,8 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
|
||||
} else if (!strcmp(setting, TOPIC_SUB_POWER)) {
|
||||
// Turn inverter on or off
|
||||
MessageOutput.printf("Set inverter power to: %d\r\n", payload_val);
|
||||
inv->sendPowerControlRequest(payload_val > 0);
|
||||
MessageOutput.printf("Set inverter power to: %d\r\n", static_cast<int32_t>(payload_val));
|
||||
inv->sendPowerControlRequest(static_cast<int32_t>(payload_val) > 0);
|
||||
|
||||
} else if (!strcmp(setting, TOPIC_SUB_RESTART)) {
|
||||
// Restart inverter
|
||||
@ -230,7 +230,7 @@ void MqttHandleInverterClass::onMqttMessage(const espMqttClientTypes::MessagePro
|
||||
if (!properties.retain && payload_val == 1) {
|
||||
inv->sendRestartControlRequest();
|
||||
} else {
|
||||
MessageOutput.println("Ignored because retained");
|
||||
MessageOutput.println("Ignored because retained or numeric value not '1'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
||||
return;
|
||||
}
|
||||
|
||||
if (root["limit_value"].as<uint16_t>() > MAX_INVERTER_LIMIT) {
|
||||
if (root["limit_value"].as<float>() > MAX_INVERTER_LIMIT) {
|
||||
retMsg["message"] = "Limit must between 0 and " STR(MAX_INVERTER_LIMIT) "!";
|
||||
retMsg["code"] = WebApiError::LimitInvalidLimit;
|
||||
retMsg["param"]["max"] = MAX_INVERTER_LIMIT;
|
||||
@ -102,7 +102,7 @@ void WebApiLimitClass::onLimitPost(AsyncWebServerRequest* request)
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t limit = root["limit_value"].as<uint16_t>();
|
||||
float limit = root["limit_value"].as<float>();
|
||||
PowerLimitControlType type = root["limit_type"].as<PowerLimitControlType>();
|
||||
|
||||
auto inv = Hoymiles.getInverterBySerial(serial);
|
||||
|
||||
@ -35,12 +35,18 @@ LOCALES.forEach((locale) => {
|
||||
decimalNoDigits: {
|
||||
style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0
|
||||
},
|
||||
decimalOneDigit: {
|
||||
style: 'decimal', minimumFractionDigits: 1, maximumFractionDigits: 1
|
||||
},
|
||||
decimalTwoDigits: {
|
||||
style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2
|
||||
},
|
||||
percent: {
|
||||
style: 'percent',
|
||||
},
|
||||
percentOneDigit: {
|
||||
style: 'percent', minimumFractionDigits: 1, maximumFractionDigits: 1
|
||||
},
|
||||
byte: {
|
||||
style: 'unit', unit: 'byte',
|
||||
},
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
<div style="padding-right: 2em;">
|
||||
{{ $t('home.CurrentLimit') }}<template v-if="inverter.limit_absolute > -1"> {{
|
||||
$n(inverter.limit_absolute, 'decimalNoDigits')
|
||||
}} W | </template>{{ $n(inverter.limit_relative / 100, 'percent') }}
|
||||
}} W | </template>{{ $n(inverter.limit_relative / 100, 'percentOneDigit') }}
|
||||
</div>
|
||||
<div style="padding-right: 2em;">
|
||||
{{ $t('home.DataAge') }} {{ $t('home.Seconds', {'val': $n(inverter.data_age) }) }}
|
||||
@ -416,13 +416,13 @@ export default defineComponent({
|
||||
currentLimitAbsolute(): string {
|
||||
if (this.currentLimitList.max_power > 0) {
|
||||
return this.$n(this.currentLimitList.limit_relative * this.currentLimitList.max_power / 100,
|
||||
'decimalTwoDigits');
|
||||
'decimalNoDigits');
|
||||
}
|
||||
return "0";
|
||||
},
|
||||
currentLimitRelative(): string {
|
||||
return this.$n(this.currentLimitList.limit_relative,
|
||||
'decimalTwoDigits');
|
||||
'decimalOneDigit');
|
||||
},
|
||||
inverterData(): Inverter[] {
|
||||
return this.liveData.inverters.slice().sort((a: Inverter, b: Inverter) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user