[kostalinverter] Fix to, prevent randomly stops of binding. (#12124)

* [kostalinverter] Fix to, prevent randomly stops of binding.

Signed-off-by: basse04 <orjan.backsell@gmail.com>
This commit is contained in:
basse04 2022-02-06 11:02:32 +01:00 committed by GitHub
parent a3bd8caba9
commit caed360c37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 159 additions and 158 deletions

View File

@ -229,7 +229,7 @@ You optionally can define a `userName` and a `password` parameter if the access
### Second generation devices (PIKO 10-20, PIKO NEW GENERATION) ### Second generation devices (PIKO 10-20, PIKO NEW GENERATION)
Second generation inverters require 5 mandatory parameters: Second generation inverters require 4 mandatory parameters and 1 optional (hasBattery):
| Parameter | Description | Type | Unit | Default value | Example value | | Parameter | Description | Type | Unit | Default value | Example value |
|--------------------------|--------------------------------------------------------|---------|---------|---------------|---------------| |--------------------------|--------------------------------------------------------|---------|---------|---------------|---------------|

View File

@ -13,6 +13,7 @@
package org.openhab.binding.kostalinverter.internal.secondgeneration; package org.openhab.binding.kostalinverter.internal.secondgeneration;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -157,8 +158,7 @@ public class SecondGenerationHandler extends BaseThingHandler {
channelConfigsConfigurable = SecondGenerationChannelConfiguration.getChannelConfigurationConfigurable(); channelConfigsConfigurable = SecondGenerationChannelConfiguration.getChannelConfigurationConfigurable();
// Set inverter configuration parameters // Set inverter configuration parameters
final SecondGenerationInverterConfig inverterConfig = getConfigAs(SecondGenerationInverterConfig.class); inverterConfig = getConfigAs(SecondGenerationInverterConfig.class);
this.inverterConfig = inverterConfig;
// Temporary value during initializing // Temporary value during initializing
updateStatus(ThingStatus.UNKNOWN); updateStatus(ThingStatus.UNKNOWN);
@ -172,17 +172,8 @@ public class SecondGenerationHandler extends BaseThingHandler {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
scheduleWithFixedDelayException.getClass().getName() + ":" scheduleWithFixedDelayException.getClass().getName() + ":"
+ scheduleWithFixedDelayException.getMessage()); + scheduleWithFixedDelayException.getMessage());
} catch (InterruptedException interruptedException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
interruptedException.getClass().getName() + ":" + interruptedException.getMessage());
} catch (ExecutionException executionException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
executionException.getClass().getName() + ":" + executionException.getMessage());
} catch (TimeoutException timeoutException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
timeoutException.getClass().getName() + ":" + timeoutException.getMessage());
} }
}, 0, SecondGenerationInverterConfig.REFRESHINTERVAL_SEC, TimeUnit.SECONDS); }, 0, inverterConfig.refreshInterval, TimeUnit.SECONDS);
} }
@Override @Override
@ -195,161 +186,171 @@ public class SecondGenerationHandler extends BaseThingHandler {
} }
} }
private void refresh() throws InterruptedException, ExecutionException, TimeoutException { private void refresh() {
// Build posts for dxsEntries part try {
String dxsEntriesCall = inverterConfig.url + "/api/dxs.json?dxsEntries=" + channelConfigs.get(0).dxsEntries; // Build posts for dxsEntries part
for (int i = 1; i < channelConfigs.size(); i++) { String dxsEntriesCall = inverterConfig.url + "/api/dxs.json?dxsEntries=" + channelConfigs.get(0).dxsEntries;
dxsEntriesCall += ("&dxsEntries=" + channelConfigs.get(i).dxsEntries); for (int i = 1; i < channelConfigs.size(); i++) {
} dxsEntriesCall += ("&dxsEntries=" + channelConfigs.get(i).dxsEntries);
String jsonDxsEntriesResponse = callURL(dxsEntriesCall);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainer = gson.fromJson(jsonDxsEntriesResponse,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPosts = new String[23];
int channelPostsCounter = 0;
for (SecondGenerationDxsEntries dxsentries : dxsEntriesContainer.dxsEntries) {
channelPosts[channelPostsCounter] = dxsentries.getName();
channelPostsCounter++;
}
channelPostsTemp = List.of(channelPosts);
// Build posts for dxsEntriesExt part
String dxsEntriesCallExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigs.size(); i++) {
dxsEntriesCallExt += ("&dxsEntries=" + channelConfigsExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExt = callURL(dxsEntriesCallExt);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExt = gson.fromJson(jsonDxsEntriesResponseExt,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExt = new String[23];
int channelPostsCounterExt = 0;
for (SecondGenerationDxsEntries dxsentriesExt : dxsEntriesContainerExt.dxsEntries) {
channelPostsExt[channelPostsCounterExt] = dxsentriesExt.getName();
channelPostsCounterExt++;
}
channelPostsTempExt = List.of(channelPostsExt);
// Build posts for dxsEntriesExtExt part
String dxsEntriesCallExtExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExtExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigsExtExt.size(); i++) {
dxsEntriesCallExtExt += ("&dxsEntries=" + channelConfigsExtExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExtExt = callURL(dxsEntriesCallExtExt);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExtExt = gson.fromJson(jsonDxsEntriesResponseExtExt,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExtExt = new String[3];
int channelPostsCounterExtExt = 0;
for (SecondGenerationDxsEntries dxsentriesExtExt : dxsEntriesContainerExtExt.dxsEntries) {
channelPostsExtExt[channelPostsCounterExtExt] = dxsentriesExtExt.getName();
channelPostsCounterExtExt++;
}
channelPostsTempExtExt = List.of(channelPostsExtExt);
// Concatenate posts for all parts except configurable channels
channelPostsTempAll = combinePostsLists(channelPostsTemp, channelPostsTempExt, channelPostsTempExtExt);
String[] channelPostsTempAll1 = channelPostsTempAll.toArray(new String[0]);
// Build posts for dxsEntriesConfigureable part
String dxsEntriesCallConfigurable = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsConfigurable.get(0).dxsEntries;
for (int i = 1; i < channelConfigsConfigurable.size(); i++) {
dxsEntriesCallConfigurable += ("&dxsEntries=" + channelConfigsConfigurable.get(i).dxsEntries);
}
String jsonDxsEntriesResponseConfigurable = callURL(dxsEntriesCallConfigurable);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerConfigurable = gson
.fromJson(jsonDxsEntriesResponseConfigurable, SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsConfigurable = new String[5];
int channelPostsCounterConfigurable = 0;
for (SecondGenerationDxsEntries dxsentriesConfigurable : dxsEntriesContainerConfigurable.dxsEntries) {
channelPostsConfigurable[channelPostsCounterConfigurable] = dxsentriesConfigurable.getName();
channelPostsCounterConfigurable++;
}
// Create and update actual values for non-configurable channels
if (!inverterConfig.hasBattery) {
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
}
}
// Create and update actual values for all channels
if (inverterConfig.hasBattery) {
// Part for updating non-configurable channels
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
// Update the non-configurable channels
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
} }
String jsonDxsEntriesResponse = callURL(dxsEntriesCall, httpClient);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainer = gson.fromJson(jsonDxsEntriesResponse,
SecondGenerationDxsEntriesContainerDTO.class);
// Part for updating configurable channels String[] channelPosts = new String[23];
int channelValuesCounterConfigurable = 0; int channelPostsCounter = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsConfigurable) { for (SecondGenerationDxsEntries dxsentries : dxsEntriesContainer.dxsEntries) {
String channel = cConfig.id; channelPosts[channelPostsCounter] = dxsentries.getName();
String value = channelPostsConfigurable[channelValuesCounterConfigurable]; channelPostsCounter++;
int dxsEntriesCheckCounter = 3; }
if (cConfig.dxsEntries.equals("33556484")) { channelPostsTemp = List.of(channelPosts);
dxsEntriesCheckCounter = 1;
// Build posts for dxsEntriesExt part
String dxsEntriesCallExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigs.size(); i++) {
dxsEntriesCallExt += ("&dxsEntries=" + channelConfigsExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExt = callURL(dxsEntriesCallExt, httpClient);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExt = gson.fromJson(jsonDxsEntriesResponseExt,
SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExt = new String[23];
int channelPostsCounterExt = 0;
for (SecondGenerationDxsEntries dxsentriesExt : dxsEntriesContainerExt.dxsEntries) {
channelPostsExt[channelPostsCounterExt] = dxsentriesExt.getName();
channelPostsCounterExt++;
}
channelPostsTempExt = List.of(channelPostsExt);
// Build posts for dxsEntriesExtExt part
String dxsEntriesCallExtExt = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsExtExt.get(0).dxsEntries;
for (int i = 1; i < channelConfigsExtExt.size(); i++) {
dxsEntriesCallExtExt += ("&dxsEntries=" + channelConfigsExtExt.get(i).dxsEntries);
}
String jsonDxsEntriesResponseExtExt = callURL(dxsEntriesCallExtExt, httpClient);
SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerExtExt = gson
.fromJson(jsonDxsEntriesResponseExtExt, SecondGenerationDxsEntriesContainerDTO.class);
String[] channelPostsExtExt = new String[3];
int channelPostsCounterExtExt = 0;
for (SecondGenerationDxsEntries dxsentriesExtExt : dxsEntriesContainerExtExt.dxsEntries) {
channelPostsExtExt[channelPostsCounterExtExt] = dxsentriesExtExt.getName();
channelPostsCounterExtExt++;
}
channelPostsTempExtExt = List.of(channelPostsExtExt);
// Concatenate posts for all parts except configurable channels
channelPostsTempAll = combinePostsLists(channelPostsTemp, channelPostsTempExt, channelPostsTempExtExt);
String[] channelPostsTempAll1 = channelPostsTempAll.toArray(new String[0]);
// Build posts for dxsEntriesConfigureable part
String[] channelPostsConfigurable = new String[5];
if (inverterConfig.hasBattery) {
String dxsEntriesCallConfigurable = inverterConfig.url + "/api/dxs.json?dxsEntries="
+ channelConfigsConfigurable.get(0).dxsEntries;
for (int i = 1; i < channelConfigsConfigurable.size(); i++) {
dxsEntriesCallConfigurable += ("&dxsEntries=" + channelConfigsConfigurable.get(i).dxsEntries);
} }
if (cConfig.dxsEntries.equals("33556482")) { String jsonDxsEntriesResponseConfigurable = callURL(dxsEntriesCallConfigurable, httpClient);
dxsEntriesCheckCounter = 2; SecondGenerationDxsEntriesContainerDTO dxsEntriesContainerConfigurable = gson
} .fromJson(jsonDxsEntriesResponseConfigurable, SecondGenerationDxsEntriesContainerDTO.class);
switch (dxsEntriesCheckCounter) { int channelPostsCounterConfigurable = 0;
case 1: for (SecondGenerationDxsEntries dxsentriesConfigurable : dxsEntriesContainerConfigurable.dxsEntries) {
if (value.equals("false")) { channelPostsConfigurable[channelPostsCounterConfigurable] = dxsentriesConfigurable.getName();
updateState(channel, OnOffType.OFF); channelPostsCounterConfigurable++;
}
if (value.equals("true")) {
updateState(channel, OnOffType.ON);
}
channelValuesCounterConfigurable++;
break;
case 2:
if (value.equals("false")) {
State stateFalse = new StringType("0");
updateState(channel, stateFalse);
}
if (value.equals("true")) {
State stateTrue = new StringType("1");
updateState(channel, stateTrue);
}
channelValuesCounterConfigurable++;
break;
case 3:
State stateOther = getState(channelPostsConfigurable[channelValuesCounterConfigurable],
cConfig.unit);
updateState(channel, stateOther);
channelValuesCounterConfigurable++;
break;
} }
} }
// Create and update actual values for non-configurable channels
if (!inverterConfig.hasBattery) {
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
}
}
// Create and update actual values for all channels
if (inverterConfig.hasBattery) {
// Part for updating non-configurable channels
channelConfigsAll = combineChannelConfigLists(channelConfigs, channelConfigsExt, channelConfigsExtExt);
// Update the non-configurable channels
int channelValuesCounterAll = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsAll) {
String channel = cConfig.id;
updateState(channel, getState(channelPostsTempAll1[channelValuesCounterAll], cConfig.unit));
channelValuesCounterAll++;
}
// Part for updating configurable channels
int channelValuesCounterConfigurable = 0;
for (SecondGenerationChannelConfiguration cConfig : channelConfigsConfigurable) {
String channel = cConfig.id;
String value = channelPostsConfigurable[channelValuesCounterConfigurable];
int dxsEntriesCheckCounter = 3;
if (cConfig.dxsEntries.equals("33556484")) {
dxsEntriesCheckCounter = 1;
}
if (cConfig.dxsEntries.equals("33556482")) {
dxsEntriesCheckCounter = 2;
}
switch (dxsEntriesCheckCounter) {
case 1:
if ("false".equals(value)) {
updateState(channel, OnOffType.OFF);
}
if ("true".equals(value)) {
updateState(channel, OnOffType.ON);
}
channelValuesCounterConfigurable++;
break;
case 2:
if ("false".equals(value)) {
State stateFalse = new StringType("0");
updateState(channel, stateFalse);
}
if ("true".equals(value)) {
State stateTrue = new StringType("1");
updateState(channel, stateTrue);
}
channelValuesCounterConfigurable++;
break;
case 3:
State stateOther = getState(channelPostsConfigurable[channelValuesCounterConfigurable],
cConfig.unit);
updateState(channel, stateOther);
channelValuesCounterConfigurable++;
break;
}
}
}
} catch (final RuntimeException e) {
logger.debug("Updating inverter status failed: ", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} }
} }
// Help method of handleCommand to with SecondGenerationConfigurationHandler.executeConfigurationChanges method send // Help method of handleCommand to with SecondGenerationConfigurationHandler.executeConfigurationChanges method send
// configuration changes. // configuration changes.
private final void preSetExecuteConfigurationChanges(HttpClient httpClient, String url, String username, private final void preSetExecuteConfigurationChanges(HttpClient httpClientHandleCommand, String url,
String password, String dxsEntriesConf, String valueConfiguration) { String username, String password, String dxsEntriesConf, String valueConfiguration) {
try { try {
SecondGenerationConfigurationHandler.executeConfigurationChanges(httpClient, url, username, password, SecondGenerationConfigurationHandler.executeConfigurationChanges(httpClientHandleCommand, url, username,
dxsEntriesConf, valueConfiguration); password, dxsEntriesConf, valueConfiguration);
} catch (Exception handleCommandException) { } catch (InterruptedException | ExecutionException | TimeoutException | NoSuchAlgorithmException e) {
logger.debug("Handle command for {} on channel {}: {}: {}: {}: {}", thing.getUID(), httpClient, url, logger.debug("Connection to inverter disturbed during configuration");
dxsEntriesConf, valueConfiguration, handleCommandException.getMessage());
} }
} }
// Method callURL connect to inverter for value scraping // Method callURL connect to inverter for value scraping
private final String callURL(String dxsEntriesCall) private final String callURL(String dxsEntriesCall, HttpClient httpClient) {
throws InterruptedException, ExecutionException, TimeoutException { String jsonDxsResponse = "";
String jsonDxsResponse = httpClient.GET(dxsEntriesCall).getContentAsString(); try {
jsonDxsResponse = httpClient.GET(dxsEntriesCall).getContentAsString();
} catch (InterruptedException | ExecutionException | TimeoutException e2) {
logger.debug("Connection to inverter disturbed during scrape");
}
return jsonDxsResponse; return jsonDxsResponse;
} }

View File

@ -25,12 +25,11 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
@NonNullByDefault @NonNullByDefault
public class SecondGenerationInverterConfig { public class SecondGenerationInverterConfig {
public static final long REFRESHINTERVAL_SEC = 60;
public String url = ""; public String url = "";
public String username = ""; public String username = "";
public String password = ""; public String password = "";
public int refreshInterval = 60;
public String dxsIdConf = ""; public String dxsIdConf = "";
public String valueConf = ""; public String valueConf = "";
public boolean hasBattery; public boolean hasBattery = false;
} }

View File

@ -23,9 +23,10 @@
<description>Refresh Interval in seconds.</description> <description>Refresh Interval in seconds.</description>
<default>60</default> <default>60</default>
</parameter> </parameter>
<parameter name="hasBattery" type="boolean" required="true"> <parameter name="hasBattery" type="boolean" required="false">
<label>Inverter Type</label> <label>Inverter Type</label>
<description>Type of inverter, with/without battery.</description> <description>Type of inverter, with/without battery.</description>
<default>false</default>
</parameter> </parameter>
</config-description> </config-description>
</config-description:config-descriptions> </config-description:config-descriptions>

View File

@ -926,7 +926,7 @@
<channel-type id="device-local-external-module-control-set"> <channel-type id="device-local-external-module-control-set">
<item-type>String</item-type> <item-type>String</item-type>
<label>External Module Control Set</label> <label>External Module Control Set</label>
<description>Set External Module Control</description> <description>Set external module control</description>
<category>Energy</category> <category>Energy</category>
<state readOnly="false"/> <state readOnly="false"/>
</channel-type> </channel-type>