Skip to content

Commit

Permalink
[senechome] Fix ArrayIndexOutOfBoundsException when less than 4 pac…
Browse files Browse the repository at this point in the history
…ks (openhab#17299)

* Fix issue and warnings
* Fix operator

Signed-off-by: Leo Siepel <leosiepel@gmail.com>
  • Loading branch information
lsiepel authored and matchews committed Oct 18, 2024
1 parent aaed708 commit 8fe2139
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.MimeTypes;
import org.openhab.binding.senechome.internal.json.SenecHomeResponse;
import org.openhab.binding.senechome.internal.dto.SenecHomeResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.senechome.internal.json.SenecHomeResponse;
import org.openhab.binding.senechome.internal.dto.SenecHomeResponse;
import org.openhab.core.cache.ExpiringCache;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
Expand Down Expand Up @@ -67,8 +67,6 @@ public class SenecHomeHandler extends BaseThingHandler {
private static final BigDecimal DIVISOR_MILLI_TO_KILO = BigDecimal.valueOf(1000000);
// divisor to transform from milli to "iso" UNIT (e.g. mV => V)
private static final BigDecimal DIVISOR_MILLI_TO_ISO = BigDecimal.valueOf(1000);
// divisor to transform from "iso" to kilo UNIT (e.g. W => kW)
private static final BigDecimal DIVISOR_ISO_TO_KILO = BigDecimal.valueOf(1000);
// ix (x=1,3,8) types => hex encoded integer value
private static final String VALUE_TYPE_INT1 = "i1";
public static final String VALUE_TYPE_INT3 = "i3";
Expand All @@ -82,7 +80,7 @@ public class SenecHomeHandler extends BaseThingHandler {

private @Nullable ScheduledFuture<?> refreshJob;
private @Nullable PowerLimitationStatusDTO limitationStatus = null;
private final @Nullable SenecHomeApi senecHomeApi;
private final SenecHomeApi senecHomeApi;
private SenecHomeConfigurationDTO config = new SenecHomeConfigurationDTO();
private final ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofSeconds(5), this::refreshState);

Expand Down Expand Up @@ -133,6 +131,18 @@ private void refresh() {
refreshCache.getValue();
}

private <Q extends Quantity<Q>> void updateQtyStateIfAvailable(String channel, String @Nullable [] valueArray,
int arrayIndex, int scale, Unit<Q> unit) {
updateQtyStateIfAvailable(channel, valueArray, arrayIndex, scale, unit, null);
}

private <Q extends Quantity<Q>> void updateQtyStateIfAvailable(String channel, String @Nullable [] valueArray,
int arrayIndex, int scale, Unit<Q> unit, @Nullable BigDecimal divisor) {
if (valueArray != null && valueArray.length > arrayIndex) {
updateQtyState(channel, valueArray[arrayIndex], scale, unit, divisor);
}
}

public @Nullable Boolean refreshState() {
SenecHomeResponse response = null;
try {
Expand Down Expand Up @@ -197,65 +207,68 @@ private void refresh() {
updateQtyState(CHANNEL_SENEC_GRID_VOLTAGE_PH3, response.grid.currentGridVoltagePerPhase[2], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_GRID_FREQUENCY, response.grid.currentGridFrequency, 2, Units.HERTZ);

if (response.battery.chargedEnergy != null) {
updateQtyState(CHANNEL_SENEC_CHARGED_ENERGY_PACK1, response.battery.chargedEnergy[0], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_CHARGED_ENERGY_PACK2, response.battery.chargedEnergy[1], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_CHARGED_ENERGY_PACK3, response.battery.chargedEnergy[2], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_CHARGED_ENERGY_PACK4, response.battery.chargedEnergy[3], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
}
if (response.battery.dischargedEnergy != null) {
updateQtyState(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK1, response.battery.dischargedEnergy[0], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK2, response.battery.dischargedEnergy[1], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK3, response.battery.dischargedEnergy[2], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyState(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK4, response.battery.dischargedEnergy[3], 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
}
updateQtyStateIfAvailable(CHANNEL_SENEC_CHARGED_ENERGY_PACK1, response.battery.chargedEnergy, 0, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_CHARGED_ENERGY_PACK2, response.battery.chargedEnergy, 1, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_CHARGED_ENERGY_PACK3, response.battery.chargedEnergy, 2, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_CHARGED_ENERGY_PACK4, response.battery.chargedEnergy, 3, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);

updateQtyStateIfAvailable(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK1, response.battery.dischargedEnergy, 0, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK2, response.battery.dischargedEnergy, 1, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK3, response.battery.dischargedEnergy, 2, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);
updateQtyStateIfAvailable(CHANNEL_SENEC_DISCHARGED_ENERGY_PACK4, response.battery.dischargedEnergy, 3, 2,
Units.KILOWATT_HOUR, DIVISOR_MILLI_TO_KILO);

if (response.battery.cycles != null) {
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK1, response.battery.cycles[0]);
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK2, response.battery.cycles[1]);
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK3, response.battery.cycles[2]);
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK4, response.battery.cycles[3]);
}
if (response.battery.current != null) {
updateQtyState(CHANNEL_SENEC_CURRENT_PACK1, response.battery.current[0], 2, Units.AMPERE);
updateQtyState(CHANNEL_SENEC_CURRENT_PACK2, response.battery.current[1], 2, Units.AMPERE);
updateQtyState(CHANNEL_SENEC_CURRENT_PACK3, response.battery.current[2], 2, Units.AMPERE);
updateQtyState(CHANNEL_SENEC_CURRENT_PACK4, response.battery.current[3], 2, Units.AMPERE);
}
if (response.battery.voltage != null) {
updateQtyState(CHANNEL_SENEC_VOLTAGE_PACK1, response.battery.voltage[0], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_VOLTAGE_PACK2, response.battery.voltage[1], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_VOLTAGE_PACK3, response.battery.voltage[2], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_VOLTAGE_PACK4, response.battery.voltage[3], 2, Units.VOLT);
}
if (response.battery.maxCellVoltage != null) {
updateQtyState(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK1, response.battery.maxCellVoltage[0], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK2, response.battery.maxCellVoltage[1], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK3, response.battery.maxCellVoltage[2], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK4, response.battery.maxCellVoltage[3], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
}
if (response.battery.minCellVoltage != null) {
updateQtyState(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK1, response.battery.minCellVoltage[0], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK2, response.battery.minCellVoltage[1], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK3, response.battery.minCellVoltage[2], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
updateQtyState(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK4, response.battery.minCellVoltage[3], 3, Units.VOLT,
DIVISOR_MILLI_TO_ISO);
int length = response.battery.cycles.length;
if (length > 0) {
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK1, response.battery.cycles[0]);
}
if (length > 1) {
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK2, response.battery.cycles[1]);
}
if (length > 2) {
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK3, response.battery.cycles[2]);
}
if (length > 3) {
updateDecimalState(CHANNEL_SENEC_CYCLES_PACK4, response.battery.cycles[3]);
}
}

updateQtyStateIfAvailable(CHANNEL_SENEC_CURRENT_PACK1, response.battery.current, 0, 2, Units.AMPERE);
updateQtyStateIfAvailable(CHANNEL_SENEC_CURRENT_PACK2, response.battery.current, 1, 2, Units.AMPERE);
updateQtyStateIfAvailable(CHANNEL_SENEC_CURRENT_PACK3, response.battery.current, 2, 2, Units.AMPERE);
updateQtyStateIfAvailable(CHANNEL_SENEC_CURRENT_PACK4, response.battery.current, 3, 2, Units.AMPERE);

updateQtyStateIfAvailable(CHANNEL_SENEC_VOLTAGE_PACK1, response.battery.voltage, 0, 2, Units.VOLT);
updateQtyStateIfAvailable(CHANNEL_SENEC_VOLTAGE_PACK2, response.battery.voltage, 1, 2, Units.VOLT);
updateQtyStateIfAvailable(CHANNEL_SENEC_VOLTAGE_PACK3, response.battery.voltage, 2, 2, Units.VOLT);
updateQtyStateIfAvailable(CHANNEL_SENEC_VOLTAGE_PACK4, response.battery.voltage, 3, 2, Units.VOLT);

updateQtyStateIfAvailable(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK1, response.battery.maxCellVoltage, 0, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK2, response.battery.maxCellVoltage, 1, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK3, response.battery.maxCellVoltage, 2, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK4, response.battery.maxCellVoltage, 3, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);

updateQtyStateIfAvailable(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK1, response.battery.minCellVoltage, 0, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK2, response.battery.minCellVoltage, 1, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK3, response.battery.minCellVoltage, 2, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);
updateQtyStateIfAvailable(CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK4, response.battery.minCellVoltage, 3, 3,
Units.VOLT, DIVISOR_MILLI_TO_ISO);

if (response.temperature != null) {
updateQtyState(CHANNEL_SENEC_BATTERY_TEMPERATURE, response.temperature.batteryTemperature, 0,
SIUnits.CELSIUS);
Expand Down Expand Up @@ -376,9 +389,10 @@ private static BigDecimal parseFloatValue(String value) {
}

protected void updatePowerLimitationStatus(Channel channel, boolean status, int duration) {
if (this.limitationStatus != null) {
if (this.limitationStatus.state == status) {
long stateSince = new Date().getTime() - this.limitationStatus.time;
PowerLimitationStatusDTO limitationStatus = this.limitationStatus;
if (limitationStatus != null) {
if (limitationStatus.state == status) {
long stateSince = new Date().getTime() - limitationStatus.time;

if (((int) (stateSince / 1000)) < duration) {
// skip updating state (possible flapping state)
Expand All @@ -387,15 +401,17 @@ protected void updatePowerLimitationStatus(Channel channel, boolean status, int
logger.debug("{} longer than required duration {}", status, duration);
}
} else {
this.limitationStatus.state = status;
this.limitationStatus.time = new Date().getTime();
limitationStatus.state = status;
limitationStatus.time = new Date().getTime();
this.limitationStatus = limitationStatus;

// skip updating state (state changed, possible flapping state)
return;
}
} else {
this.limitationStatus = new PowerLimitationStatusDTO();
this.limitationStatus.state = status;
limitationStatus = new PowerLimitationStatusDTO();
limitationStatus.state = status;
this.limitationStatus = limitationStatus;
}

logger.debug("Updating power limitation state {}", status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
*/
package org.openhab.binding.senechome.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* The {@link SenecSystemStatus} class defines available Senec specific
* system states.
*
* @author Steven Schwarznau - Initial contribution
*
*/
@NonNullByDefault
public enum SenecSystemStatus {

INITIALSTATE(0, "INITIAL STATE"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
*/
package org.openhab.binding.senechome.internal;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
* Enum with available Senec specific wallbox states.
*
* @author Erwin Guib - Initial Contribution
*/
@NonNullByDefault
public enum SenecWallboxStatus {
WAIT_FOR_EV(0xA1, "Waiting for EV"),
EV_ASKING_CHARGE(0xB1, "EV asking for charge"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
package org.openhab.binding.senechome.internal.dto;

import java.io.Serializable;
import java.util.Arrays;
Expand Down

0 comments on commit 8fe2139

Please sign in to comment.