[senechome] issue #10679: Extend with additional channels; refactor and various improvements (#10687)

* [senechome] Extend with additional channels; refactor; improve error handling (#10679). Merged PR 9535 (rename batteryState to system state)

- charge/discharge energy/current/voltage/min/maxCellVoltage/load cycles per battery pack
- current/power/voltage per MPP
- liveHouseConsumption/livePowerGenerator
- battery,case,MCU temperature
- wallbox1: state, charging power/current, liveEnergy
- improve error handling, catch malformed JSON exception to prevent crashing the binding
- merged PR: 9535 (rename batteryState to systemState)
- renamed SenecHomeLimitation to SenecHomePower and added more channels
- refactored SenecHomeHandler to reduce code duplication (added some nice helper methods)

Signed-off-by: Erwin Guib <eguib@web.de>
This commit is contained in:
eguib 2021-05-29 14:29:20 +02:00 committed by GitHub
parent 04507d98fc
commit 3875d2aca5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1227 additions and 290 deletions

View File

@ -251,7 +251,7 @@
/bundles/org.openhab.binding.samsungtv/ @paulianttila
/bundles/org.openhab.binding.satel/ @druciak
/bundles/org.openhab.binding.semsportal/ @itb3
/bundles/org.openhab.binding.senechome/ @vctender @KorbinianP
/bundles/org.openhab.binding.senechome/ @vctender @KorbinianP @eguib
/bundles/org.openhab.binding.seneye/ @nikotanghe
/bundles/org.openhab.binding.sensebox/ @hakan42
/bundles/org.openhab.binding.sensibo/ @seime

View File

@ -11,8 +11,13 @@ Examples: Lights, pool filters, wash machines, ...
| Thing type id | Name |
|----------------------|-----------------------------------------------|
| senechome | Senec Home Lithium Battery, V2.0, V2.1 and V3 |
| senechome | Senec Home Lithium Battery, V2.0, V2.1, V3 and V3duo |
**Note:** Not all channels are available for all Senec Home types. E.g.
* only V3, V3duo have a power generator and thus MPPs (V3 has 2 MPP, V3duo has 3 MPP)
* not equipped battery packs will return 0 for all ...Pack channels
* currently channels for the first wallbox are implemented (senec could handle 4 wallboxes)
## Thing Configuration
@ -34,12 +39,23 @@ The property `limitationTresholdValue` is used as threshold for channel `powerLi
|-----------------------|-----------|--------------------------------------------------------------------------|
| powerLimitation | percent | How much is your pv generator limited (0% if not limited anyway) |
| powerLimitationState | ON/OFF | Power limitation active (based on configuration) |
| currentMPP1 | ampere | PV generator current on MPP1 |
| currentMPP2 | ampere | PV generator current on MPP2 |
| currentMPP3 | ampere | PV generator current on MPP3 |
| powerMPP1 | watt | PV generator power on MPP1 |
| powerMPP2 | watt | PV generator power on MPP2 |
| powerMPP3 | watt | PV generator power on MPP3 |
| voltageMPP1 | volt | PV generator voltage on MPP1 |
| voltageMPP2 | volt | PV generator voltage on MPP2 |
| voltageMPP3 | volt | PV generator voltage on MPP3 |
| houseConsumption | watt | Current power consumption of your house/living |
| energyProduction | watt | Energy generated by your pv / inverter |
| batteryPower | watt | Energy processed by batterie itself, for example while charging |
| batteryPower | watt | Energy processed by battery negative discharge, positive charge |
| batteryCurrent | ampere | Battery current negative discharge, positive charge |
| batteryVoltage | volt | Battery Voltage |
| batteryFuelCharge | percent | Fuel charge of your battery (0 - 100%) |
| batteryState | | Text describing current action of battery (e.g. CHARGE) |
| batteryStateValue | | Value describing current action of battery (e.g. 14) |
| systemState | | Text describing current action of the senec home system (e.g. CHARGE) |
| systemStateValue | | Value describing current action of the senec home system (e.g. 14) |
| gridPower | watt | Grid power level, negative for supply, positive values for drawing power |
| gridPowerDraw | watt | Absolute power level of power draw, zero while supplying |
| gridPowerSupply | watt | Absolute power level of power supply, zero while drawing |
@ -53,11 +69,50 @@ The property `limitationTresholdValue` is used as threshold for channel `powerLi
| gridVoltagePhase2 | volt | Grid voltage on Phase 2 |
| gridVoltagePhase3 | volt | Grid voltage on Phase 3 |
| gridFrequency | hertz | Grid frequency |
| SenecBatteryVoltage | volt | Battery Voltage |
| SenecLiveBatCharge | watt hour | Live Bat Charge |
| SenecLiveBatDischarge | watt hour | Live Bat Discharge |
| SenecLiveGridImport | watt hour | Live Grid Import |
| SenecLiveGridExport | watt hour | Live Grid Export |
| liveBatCharge | kilo watt hour | Live Total Bat Charge |
| liveBatDischarge | kilo watt hour | Live Total Bat Discharge |
| liveGridImport | kilo watt hour | Live Total Grid Import |
| liveGridExport | kilo watt hour | Live Total Grid Export |
| liveHouseConsumption | kilo watt hour | Live Total House Consumption (without WB) |
| livePowerGenerator | kilo watt hour | Live Total PV generator generated energy |
| liveEnergyWallbox1 | kilo watt hour | Live Total Wallbox 1 charged energy |
| chargedEnergyPack1 | kilo watt hour | total charged energy battery pack 1 |
| chargedEnergyPack2 | kilo watt hour | total charged energy battery pack 2 |
| chargedEnergyPack3 | kilo watt hour | total charged energy battery pack 3 |
| chargedEnergyPack4 | kilo watt hour | total charged energy battery pack 4 |
| dischargedEnergyPack1 | kilo watt hour | total discharged energy battery pack 1 |
| dischargedEnergyPack2 | kilo watt hour | total discharged energy battery pack 2 |
| dischargedEnergyPack3 | kilo watt hour | total discharged energy battery pack 3 |
| dischargedEnergyPack4 | kilo watt hour | total discharged energy battery pack 4 |
| cyclesPack1 | | battery charge/discharge cycles pack 1 |
| cyclesPack2 | | battery charge/discharge cycles pack 2 |
| cyclesPack3 | | battery charge/discharge cycles pack 3 |
| cyclesPack4 | | battery charge/discharge cycles pack 4 |
| currentPack1 | ampere | battery current pack 1 |
| currentPack2 | ampere | battery current pack 2 |
| currentPack3 | ampere | battery current pack 3 |
| currentPack4 | ampere | battery current pack 4 |
| voltagePack1 | volt | battery voltage pack 1 |
| voltagePack2 | volt | battery voltage pack 2 |
| voltagePack3 | volt | battery voltage pack 3 |
| voltagePack4 | volt | battery voltage pack 4 |
| maxCellVoltagePack1 | volt | maximum cell voltage battery pack 1 |
| maxCellVoltagePack2 | volt | maximum cell voltage battery pack 2 |
| maxCellVoltagePack3 | volt | maximum cell voltage battery pack 3 |
| maxCellVoltagePack4 | volt | maximum cell voltage battery pack 4 |
| minCellVoltagePack1 | volt | minimum cell voltage battery pack 1 |
| minCellVoltagePack2 | volt | minimum cell voltage battery pack 2 |
| minCellVoltagePack3 | volt | minimum cell voltage battery pack 3 |
| minCellVoltagePack4 | volt | minimum cell voltage battery pack 4 |
| batteryTemperature | celsius | battery temperature (maximum of all battery packs) |
| caseTemperature | celsius | case temperature |
| mcuTemperature | celsius | MCU (main control unit) temperature |
| wallbox1State | | Wallbox 1 state as Text (e.g. Charging) |
| wallbox1StateValue | | Wallbox 1 state as value (e.g. 194) |
| wallbox1ChargingCurrentPhase1 | ampere | Wallbox 1 charging current Phase 1 |
| wallbox1ChargingCurrentPhase2 | ampere | Wallbox 1 charging current Phase 2 |
| wallbox1ChargingCurrentPhase3 | ampere | Wallbox 1 charging current Phase 3 |
| wallbox1ChargingPower | watt | Wallbox 1 charging power |
## Items
@ -70,8 +125,8 @@ Number SenecHouseConsumption "Current power consumption [%d W]" <e
Number SenecEnergyProduction "Energy generated by pv [%d W]" <energy> { channel="senechome:senechome:pvbattery:energyProduction" }
Number SenecBatteryPower "Energy processed by battery [%d W]" <energy> { channel="senechome:senechome:pvbattery:batteryPower" }
Number SenecBatteryFuelCharge "State of Charge [%d %%]" <batterylevel> { channel="senechome:senechome:pvbattery:batteryFuelCharge" }
String SenecBatteryState "Current action [%s]" <text> { channel="senechome:senechome:pvbattery:batteryState" }
Number SenecBatteryStateValue "Current action [%d]" <text> { channel="senechome:senechome:pvbattery:batteryStateValue" }
String SenecSystemState "Current system state [%s]" <text> { channel="senechome:senechome:pvbattery:systemState" }
Number SenecSystemStateValue "Current system state [%d]" <text> { channel="senechome:senechome:pvbattery:systemStateValue" }
Number SenecGridPower "Grid power level [%d W]" <energy> { channel="senechome:senechome:pvbattery:gridPower" }
Number SenecGridPowerDraw "Power draw from grid [%d W]" <energy> { channel="senechome:senechome:pvbattery:gridPowerDraw" }
Number SenecGridPowerSupply "Power supply to grid [%d W]" <energy> { channel="senechome:senechome:pvbattery:gridPowerSupply" }
@ -105,8 +160,8 @@ Text label="Power Grid"{
Default item=SenecEnergyProduction
Default item=SenecBatteryPower
Default item=SenecBatteryFuelCharge
Default item=SenecBatteryState
Default item=SenecBatteryStateValue
Default item=SenecSystemState
Default item=SenecSystemStateValue
Default item=SenecGridPower
Default item=SenecGridPowerDraw
Default item=SenecGridPowerSupply

View File

@ -65,7 +65,6 @@ public class SenecHomeApi {
*
* To receive new values, just modify the Json objects and add them to the thing channels
*
* @param hostname Hostname or ip address of senec battery
* @return Instance of SenecHomeResponse
* @throws MalformedURLException Configuration/URL is wrong
* @throws IOException Communication failed

View File

@ -27,14 +27,30 @@ public class SenecHomeBindingConstants {
private static final String THING_BASE_ID = "senechome";
public static final ThingTypeUID THING_TYPE_SENEC_HOME_BATTERY = new ThingTypeUID(BINDING_ID, THING_BASE_ID);
// SenecHomePower
public static final String CHANNEL_SENEC_POWER_LIMITATION = "powerLimitation";
public static final String CHANNEL_SENEC_POWER_LIMITATION_STATE = "powerLimitationState";
public static final String CHANNEL_SENEC_BATTERY_STATE = "batteryState";
public static final String CHANNEL_SENEC_BATTERY_STATE_VALUE = "batteryStateValue";
public static final String CHANNEL_SENEC_CURRENT_MPP1 = "currentMpp1";
public static final String CHANNEL_SENEC_CURRENT_MPP2 = "currentMpp2";
public static final String CHANNEL_SENEC_CURRENT_MPP3 = "currentMpp3";
public static final String CHANNEL_SENEC_POWER_MPP1 = "powerMpp1";
public static final String CHANNEL_SENEC_POWER_MPP2 = "powerMpp2";
public static final String CHANNEL_SENEC_POWER_MPP3 = "powerMpp3";
public static final String CHANNEL_SENEC_VOLTAGE_MPP1 = "voltageMpp1";
public static final String CHANNEL_SENEC_VOLTAGE_MPP2 = "voltageMpp2";
public static final String CHANNEL_SENEC_VOLTAGE_MPP3 = "voltageMpp3";
// SenecHomeEnergy
public static final String CHANNEL_SENEC_SYSTEM_STATE = "systemState";
public static final String CHANNEL_SENEC_SYSTEM_STATE_VALUE = "systemStateValue";
public static final String CHANNEL_SENEC_POWER_CONSUMPTION = "houseConsumption";
public static final String CHANNEL_SENEC_ENERGY_PRODUCTION = "energyProduction";
public static final String CHANNEL_SENEC_BATTERY_POWER = "batteryPower";
public static final String CHANNEL_SENEC_BATTERY_FUEL_CHARGE = "batteryFuelCharge";
public static final String CHANNEL_SENEC_BATTERY_VOLTAGE = "batteryVoltage";
public static final String CHANNEL_SENEC_BATTERY_CURRENT = "batteryCurrent";
// SenecHomeGrid
public static final String CHANNEL_SENEC_GRID_POWER = "gridPower";
public static final String CHANNEL_SENEC_GRID_POWER_SUPPLY = "gridPowerSupply";
public static final String CHANNEL_SENEC_GRID_POWER_DRAW = "gridPowerDraw";
@ -48,9 +64,56 @@ public class SenecHomeBindingConstants {
public static final String CHANNEL_SENEC_GRID_VOLTAGE_PH2 = "gridVoltagePhase2";
public static final String CHANNEL_SENEC_GRID_VOLTAGE_PH3 = "gridVoltagePhase3";
public static final String CHANNEL_SENEC_GRID_FREQUENCY = "gridFrequency";
// SenecHomeStatistics
public static final String CHANNEL_SENEC_LIVE_BAT_CHARGE = "liveBatCharge";
public static final String CHANNEL_SENEC_LIVE_BAT_DISCHARGE = "liveBatDischarge";
public static final String CHANNEL_SENEC_LIVE_GRID_IMPORT = "liveGridImport";
public static final String CHANNEL_SENEC_LIVE_GRID_EXPORT = "liveGridExport";
public static final String CHANNEL_SENEC_BATTERY_VOLTAGE = "batteryVoltage";
public static final String CHANNEL_SENEC_LIVE_HOUSE_CONSUMPTION = "liveHouseConsumption";
public static final String CHANNEL_SENEC_LIVE_POWER_GENERATOR = "livePowerGenerator";
public static final String CHANNEL_SENEC_LIVE_ENERGY_WALLBOX1 = "liveEnergyWallbox1";
// SenecHomeBattery
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK1 = "chargedEnergyPack1";
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK2 = "chargedEnergyPack2";
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK3 = "chargedEnergyPack3";
public static final String CHANNEL_SENEC_CHARGED_ENERGY_PACK4 = "chargedEnergyPack4";
public static final String CHANNEL_SENEC_DISCHARGED_ENERGY_PACK1 = "dischargedEnergyPack1";
public static final String CHANNEL_SENEC_DISCHARGED_ENERGY_PACK2 = "dischargedEnergyPack2";
public static final String CHANNEL_SENEC_DISCHARGED_ENERGY_PACK3 = "dischargedEnergyPack3";
public static final String CHANNEL_SENEC_DISCHARGED_ENERGY_PACK4 = "dischargedEnergyPack4";
public static final String CHANNEL_SENEC_CYCLES_PACK1 = "cyclesPack1";
public static final String CHANNEL_SENEC_CYCLES_PACK2 = "cyclesPack2";
public static final String CHANNEL_SENEC_CYCLES_PACK3 = "cyclesPack3";
public static final String CHANNEL_SENEC_CYCLES_PACK4 = "cyclesPack4";
public static final String CHANNEL_SENEC_CURRENT_PACK1 = "currentPack1";
public static final String CHANNEL_SENEC_CURRENT_PACK2 = "currentPack2";
public static final String CHANNEL_SENEC_CURRENT_PACK3 = "currentPack3";
public static final String CHANNEL_SENEC_CURRENT_PACK4 = "currentPack4";
public static final String CHANNEL_SENEC_VOLTAGE_PACK1 = "voltagePack1";
public static final String CHANNEL_SENEC_VOLTAGE_PACK2 = "voltagePack2";
public static final String CHANNEL_SENEC_VOLTAGE_PACK3 = "voltagePack3";
public static final String CHANNEL_SENEC_VOLTAGE_PACK4 = "voltagePack4";
public static final String CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK1 = "maxCellVoltagePack1";
public static final String CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK2 = "maxCellVoltagePack2";
public static final String CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK3 = "maxCellVoltagePack3";
public static final String CHANNEL_SENEC_MAX_CELL_VOLTAGE_PACK4 = "maxCellVoltagePack4";
public static final String CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK1 = "minCellVoltagePack1";
public static final String CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK2 = "minCellVoltagePack2";
public static final String CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK3 = "minCellVoltagePack3";
public static final String CHANNEL_SENEC_MIN_CELL_VOLTAGE_PACK4 = "minCellVoltagePack4";
// SenecHomeTemperature
public static final String CHANNEL_SENEC_BATTERY_TEMPERATURE = "batteryTemperature";
public static final String CHANNEL_SENEC_CASE_TEMPERATURE = "caseTemperature";
public static final String CHANNEL_SENEC_MCU_TEMPERATURE = "mcuTemperature";
// SenecHomeWallbox
public static final String CHANNEL_SENEC_WALLBOX1_STATE = "wallbox1State";
public static final String CHANNEL_SENEC_WALLBOX1_STATE_VALUE = "wallbox1StateValue";
public static final String CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH1 = "wallbox1ChargingCurrentPhase1";
public static final String CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH2 = "wallbox1ChargingCurrentPhase2";
public static final String CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH3 = "wallbox1ChargingCurrentPhase3";
public static final String CHANNEL_SENEC_WALLBOX1_CHARGING_POWER = "wallbox1ChargingPower";
}

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.senechome.internal;
import static org.openhab.binding.senechome.internal.SenecHomeBindingConstants.*;
import static org.openhab.core.types.RefreshType.REFRESH;
import java.io.IOException;
@ -23,13 +24,10 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import javax.measure.quantity.Dimensionless;
import javax.measure.quantity.ElectricCurrent;
import javax.measure.quantity.ElectricPotential;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Frequency;
import javax.measure.quantity.Power;
import javax.measure.Quantity;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -40,6 +38,7 @@ import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
@ -51,21 +50,35 @@ import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
import com.google.gson.JsonParseException;
/**
* The {@link SenecHomeHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Steven Schwarznau - Initial contribution
* @author Erwin Guib - added more channels, added some convenience methods to reduce code duplication
*/
@NonNullByDefault
public class SenecHomeHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(SenecHomeHandler.class);
private final static String VALUE_TYPE_INT = "u3";
private final static String VALUE_TYPE_UNSIGNED_INT = "u8";
private final static String VALUE_TYPE_FLOAT = "fl";
// divisor to transform from milli to kilo UNIT (e.g. mW => kW)
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";
public static final String VALUE_TYPE_INT8 = "i8";
// ux (x=1,3,6,8) types => hex encoded unsigned value
private static final String VALUE_TYPE_DECIMAL = "u";
// fl => hex encoded float
private static final String VALUE_TYPE_FLOAT = "fl";
// st => string
// public static final String VALUE_TYPE_STRING = "st";
private @Nullable ScheduledFuture<?> refreshJob;
private @Nullable PowerLimitationStatusDTO limitationStatus = null;
@ -126,160 +139,146 @@ public class SenecHomeHandler extends BaseThingHandler {
response = senecHomeApi.getStatistics();
logger.trace("received {}", response);
BigDecimal pvLimitation = new BigDecimal(100).subtract(getSenecValue(response.limitation.powerLimitation))
BigDecimal pvLimitation = new BigDecimal(100).subtract(getSenecValue(response.power.powerLimitation))
.setScale(0, RoundingMode.HALF_UP);
updateState(CHANNEL_SENEC_POWER_LIMITATION, new QuantityType<>(pvLimitation, Units.PERCENT));
updateState(SenecHomeBindingConstants.CHANNEL_SENEC_POWER_LIMITATION,
new QuantityType<Dimensionless>(pvLimitation, Units.PERCENT));
Channel channelLimitationState = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_POWER_LIMITATION_STATE);
Channel channelLimitationState = getThing().getChannel(CHANNEL_SENEC_POWER_LIMITATION_STATE);
if (channelLimitationState != null) {
updatePowerLimitationStatus(channelLimitationState,
(100 - pvLimitation.intValue()) <= config.limitationTresholdValue, config.limitationDuration);
}
Channel channelConsumption = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_POWER_CONSUMPTION);
if (channelConsumption != null) {
updateState(channelConsumption.getUID(),
new QuantityType<Power>(
getSenecValue(response.energy.homePowerConsumption).setScale(2, RoundingMode.HALF_UP),
Units.WATT));
if (response.power.currentPerMpp != null) {
updateQtyState(CHANNEL_SENEC_CURRENT_MPP1, response.power.currentPerMpp[0], 2, Units.AMPERE);
updateQtyState(CHANNEL_SENEC_CURRENT_MPP2, response.power.currentPerMpp[1], 2, Units.AMPERE);
if (response.power.currentPerMpp.length > 2) {
// only Home V3 duo
updateQtyState(CHANNEL_SENEC_CURRENT_MPP3, response.power.currentPerMpp[2], 2, Units.AMPERE);
}
}
if (response.power.powerPerMpp != null) {
updateQtyState(CHANNEL_SENEC_POWER_MPP1, response.power.powerPerMpp[0], 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_POWER_MPP2, response.power.powerPerMpp[1], 2, Units.WATT);
if (response.power.powerPerMpp.length > 2) {
updateQtyState(CHANNEL_SENEC_POWER_MPP3, response.power.powerPerMpp[2], 2, Units.WATT);
}
}
if (response.power.voltagePerMpp != null) {
updateQtyState(CHANNEL_SENEC_VOLTAGE_MPP1, response.power.voltagePerMpp[0], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_VOLTAGE_MPP2, response.power.voltagePerMpp[1], 2, Units.VOLT);
if (response.power.voltagePerMpp.length > 2) {
updateQtyState(CHANNEL_SENEC_VOLTAGE_MPP3, response.power.voltagePerMpp[2], 2, Units.VOLT);
}
}
Channel channelEnergyProduction = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_ENERGY_PRODUCTION);
if (channelEnergyProduction != null) {
updateState(channelEnergyProduction.getUID(), new QuantityType<Power>(
getSenecValue(response.energy.inverterPowerGeneration).setScale(0, RoundingMode.HALF_UP),
Units.WATT));
}
Channel channelBatteryPower = getThing().getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_BATTERY_POWER);
if (channelBatteryPower != null) {
updateState(channelBatteryPower.getUID(), new QuantityType<Power>(
getSenecValue(response.energy.batteryPower).setScale(2, RoundingMode.HALF_UP), Units.WATT));
}
Channel channelBatteryFuelCharge = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_BATTERY_FUEL_CHARGE);
if (channelBatteryFuelCharge != null) {
updateState(channelBatteryFuelCharge.getUID(),
new QuantityType<Dimensionless>(
getSenecValue(response.energy.batteryFuelCharge).setScale(0, RoundingMode.HALF_UP),
Units.PERCENT));
}
Channel channelGridCurrentPhase1 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_CURRENT_PH1);
updateState(channelGridCurrentPhase1.getUID(), new QuantityType<ElectricCurrent>(
getSenecValue(response.grid.currentGridCurrentPerPhase[0]).setScale(2, RoundingMode.HALF_UP),
Units.AMPERE));
Channel channelGridCurrentPhase2 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_CURRENT_PH2);
updateState(channelGridCurrentPhase2.getUID(), new QuantityType<ElectricCurrent>(
getSenecValue(response.grid.currentGridCurrentPerPhase[1]).setScale(2, RoundingMode.HALF_UP),
Units.AMPERE));
Channel channelGridCurrentPhase3 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_CURRENT_PH3);
updateState(channelGridCurrentPhase3.getUID(), new QuantityType<ElectricCurrent>(
getSenecValue(response.grid.currentGridCurrentPerPhase[2]).setScale(2, RoundingMode.HALF_UP),
Units.AMPERE));
Channel channelGridPowerPhase1 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER_PH1);
updateState(channelGridPowerPhase1.getUID(),
new QuantityType<Power>(
getSenecValue(response.grid.currentGridPowerPerPhase[0]).setScale(2, RoundingMode.HALF_UP),
Units.WATT));
Channel channelGridPowerPhase2 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER_PH2);
updateState(channelGridPowerPhase2.getUID(),
new QuantityType<Power>(
getSenecValue(response.grid.currentGridPowerPerPhase[1]).setScale(2, RoundingMode.HALF_UP),
Units.WATT));
Channel channelGridPowerPhase3 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER_PH3);
updateState(channelGridPowerPhase3.getUID(),
new QuantityType<Power>(
getSenecValue(response.grid.currentGridPowerPerPhase[2]).setScale(2, RoundingMode.HALF_UP),
Units.WATT));
Channel channelGridVoltagePhase1 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_VOLTAGE_PH1);
updateState(channelGridVoltagePhase1.getUID(), new QuantityType<ElectricPotential>(
getSenecValue(response.grid.currentGridVoltagePerPhase[0]).setScale(2, RoundingMode.HALF_UP),
Units.VOLT));
Channel channelGridVoltagePhase2 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_VOLTAGE_PH2);
updateState(channelGridVoltagePhase2.getUID(), new QuantityType<ElectricPotential>(
getSenecValue(response.grid.currentGridVoltagePerPhase[1]).setScale(2, RoundingMode.HALF_UP),
Units.VOLT));
Channel channelGridVoltagePhase3 = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_VOLTAGE_PH3);
updateState(channelGridVoltagePhase3.getUID(), new QuantityType<ElectricPotential>(
getSenecValue(response.grid.currentGridVoltagePerPhase[2]).setScale(2, RoundingMode.HALF_UP),
Units.VOLT));
Channel channelGridFrequency = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_FREQUENCY);
updateState(channelGridFrequency.getUID(), new QuantityType<Frequency>(
getSenecValue(response.grid.currentGridFrequency).setScale(2, RoundingMode.HALF_UP), Units.HERTZ));
Channel channelBatteryStateValue = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_BATTERY_STATE_VALUE);
updateState(channelBatteryStateValue.getUID(),
new DecimalType(getSenecValue(response.energy.batteryState).intValue()));
Channel channelLiveBatCharge = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_LIVE_BAT_CHARGE);
updateState(channelLiveBatCharge.getUID(),
new QuantityType<Energy>(
getSenecValue(response.statistics.liveBatCharge).setScale(2, RoundingMode.HALF_UP),
Units.WATT_HOUR));
Channel channelLiveBatDischarge = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_LIVE_BAT_DISCHARGE);
updateState(channelLiveBatDischarge.getUID(),
new QuantityType<Energy>(
getSenecValue(response.statistics.liveBatDischarge).setScale(2, RoundingMode.HALF_UP),
Units.WATT_HOUR));
Channel channelLiveGridImport = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_LIVE_GRID_IMPORT);
updateState(channelLiveGridImport.getUID(),
new QuantityType<Energy>(
getSenecValue(response.statistics.liveGridImport).setScale(2, RoundingMode.HALF_UP),
Units.WATT_HOUR));
Channel channelLiveGridExport = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_LIVE_GRID_EXPORT);
updateState(channelLiveGridExport.getUID(),
new QuantityType<Energy>(
getSenecValue(response.statistics.liveGridExport).setScale(2, RoundingMode.HALF_UP),
Units.WATT_HOUR));
Channel channelBatteryVoltage = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_BATTERY_VOLTAGE);
updateState(channelBatteryVoltage.getUID(), new QuantityType<ElectricPotential>(
getSenecValue(response.energy.batteryVoltage).setScale(2, RoundingMode.HALF_UP), Units.VOLT));
Channel channelBatteryState = getThing().getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_BATTERY_STATE);
if (channelBatteryState != null) {
updateBatteryState(channelBatteryState, getSenecValue(response.energy.batteryState).intValue());
}
updateQtyState(CHANNEL_SENEC_POWER_CONSUMPTION, response.energy.housePowerConsumption, 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_ENERGY_PRODUCTION, response.energy.inverterPowerGeneration, 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_BATTERY_POWER, response.energy.batteryPower, 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_BATTERY_CURRENT, response.energy.batteryCurrent, 2, Units.AMPERE);
updateQtyState(CHANNEL_SENEC_BATTERY_VOLTAGE, response.energy.batteryVoltage, 2, Units.VOLT);
updateStringStateFromInt(CHANNEL_SENEC_SYSTEM_STATE, response.energy.systemState,
SenecSystemStatus::descriptionFromCode);
updateDecimalState(CHANNEL_SENEC_SYSTEM_STATE_VALUE, response.energy.systemState);
updateQtyState(CHANNEL_SENEC_BATTERY_FUEL_CHARGE, response.energy.batteryFuelCharge, 0, Units.PERCENT);
updateGridPowerValues(getSenecValue(response.grid.currentGridValue));
updateQtyState(CHANNEL_SENEC_GRID_CURRENT_PH1, response.grid.currentGridCurrentPerPhase[0], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_GRID_CURRENT_PH2, response.grid.currentGridCurrentPerPhase[1], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_GRID_CURRENT_PH3, response.grid.currentGridCurrentPerPhase[2], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_GRID_POWER_PH1, response.grid.currentGridPowerPerPhase[0], 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_GRID_POWER_PH2, response.grid.currentGridPowerPerPhase[1], 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_GRID_POWER_PH3, response.grid.currentGridPowerPerPhase[2], 2, Units.WATT);
updateQtyState(CHANNEL_SENEC_GRID_VOLTAGE_PH1, response.grid.currentGridVoltagePerPhase[0], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_GRID_VOLTAGE_PH2, response.grid.currentGridVoltagePerPhase[1], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_GRID_VOLTAGE_PH3, response.grid.currentGridVoltagePerPhase[2], 2, Units.VOLT);
updateQtyState(CHANNEL_SENEC_GRID_FREQUENCY, response.grid.currentGridFrequency, 2, Units.HERTZ);
updateQtyState(CHANNEL_SENEC_LIVE_BAT_CHARGE, response.statistics.liveBatCharge, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_BAT_DISCHARGE, response.statistics.liveBatDischarge, 2,
Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_GRID_IMPORT, response.statistics.liveGridImport, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_GRID_EXPORT, response.statistics.liveGridExport, 2, Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_HOUSE_CONSUMPTION, response.statistics.liveHouseConsumption, 2,
Units.KILOWATT_HOUR);
updateQtyState(CHANNEL_SENEC_LIVE_POWER_GENERATOR, response.statistics.livePowerGenerator, 2,
Units.KILOWATT_HOUR);
if (response.statistics.liveWallboxEnergy != null) {
updateQtyState(CHANNEL_SENEC_LIVE_ENERGY_WALLBOX1, response.statistics.liveWallboxEnergy[0], 2,
Units.KILOWATT_HOUR, DIVISOR_ISO_TO_KILO);
}
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);
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);
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]);
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);
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);
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);
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);
if (response.temperature != null) {
updateQtyState(CHANNEL_SENEC_BATTERY_TEMPERATURE, response.temperature.batteryTemperature, 0,
SIUnits.CELSIUS);
updateQtyState(CHANNEL_SENEC_CASE_TEMPERATURE, response.temperature.caseTemperature, 0,
SIUnits.CELSIUS);
updateQtyState(CHANNEL_SENEC_MCU_TEMPERATURE, response.temperature.mcuTemperature, 0, SIUnits.CELSIUS);
}
if (response.wallbox != null && response.wallbox.state != null) {
updateStringStateFromInt(CHANNEL_SENEC_WALLBOX1_STATE, response.wallbox.state[0],
SenecWallboxStatus::descriptionFromCode);
updateDecimalState(CHANNEL_SENEC_WALLBOX1_STATE_VALUE, response.wallbox.state[0]);
updateQtyState(CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH1, response.wallbox.l1ChargingCurrent[0], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH2, response.wallbox.l2ChargingCurrent[0], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_WALLBOX1_CHARGING_CURRENT_PH3, response.wallbox.l3ChargingCurrent[0], 2,
Units.AMPERE);
updateQtyState(CHANNEL_SENEC_WALLBOX1_CHARGING_POWER, response.wallbox.chargingPower[0], 2, Units.WATT);
}
updateStatus(ThingStatus.ONLINE);
} catch (JsonSyntaxException | IOException | InterruptedException | TimeoutException | ExecutionException e) {
} catch (JsonParseException | IOException | InterruptedException | TimeoutException | ExecutionException e) {
if (response == null) {
logger.trace("Faulty response: is null");
} else {
@ -293,19 +292,73 @@ public class SenecHomeHandler extends BaseThingHandler {
return Boolean.TRUE;
}
protected void updateStringStateFromInt(String channelName, String senecValue,
Function<Integer, String> converter) {
Channel channel = getThing().getChannel(channelName);
if (channel != null) {
Integer value = getSenecValue(senecValue).intValue();
updateState(channel.getUID(), new StringType(converter.apply(value)));
}
}
protected void updateDecimalState(String channelName, String senecValue) {
Channel channel = getThing().getChannel(channelName);
if (channel != null) {
BigDecimal value = getSenecValue(senecValue);
updateState(channel.getUID(), new DecimalType(value.intValue()));
}
}
protected <Q extends Quantity<Q>> void updateQtyState(String channelName, String senecValue, int scale,
Unit<Q> unit) {
updateQtyState(channelName, senecValue, scale, unit, null);
}
protected <Q extends Quantity<Q>> void updateQtyState(String channelName, String senecValue, int scale,
Unit<Q> unit, @Nullable BigDecimal divisor) {
Channel channel = getThing().getChannel(channelName);
if (channel == null) {
return;
}
BigDecimal value = getSenecValue(senecValue);
if (divisor != null) {
value = value.divide(divisor, scale, RoundingMode.HALF_UP);
} else {
value = value.setScale(scale, RoundingMode.HALF_UP);
}
updateState(channel.getUID(), new QuantityType<Q>(value, unit));
}
protected BigDecimal getSenecValue(String value) {
String[] type = value.split("_");
if (VALUE_TYPE_INT.equalsIgnoreCase(type[0])) {
return new BigDecimal(Integer.valueOf(type[1], 16));
} else if (VALUE_TYPE_UNSIGNED_INT.equalsIgnoreCase(type[0])) {
return new BigDecimal(Integer.valueOf(type[1], 16));
} else if (VALUE_TYPE_FLOAT.equalsIgnoreCase(type[0])) {
return parseFloatValue(type[1]);
} else {
logger.warn("Unknown value type [{}]", type[0]);
if (type[0] != null) {
if (type[0].startsWith(VALUE_TYPE_DECIMAL)) {
return new BigDecimal(Long.valueOf(type[1], 16));
} else if (type[0].startsWith(VALUE_TYPE_INT1)) {
Integer val = Integer.valueOf(type[1], 16);
if ((val & 0x8000) > 0) {
val = val - 0x10000;
}
return new BigDecimal(val);
} else if (type[0].startsWith(VALUE_TYPE_INT3)) {
Long val = Long.valueOf(type[1], 16);
if ((Math.abs(val & 0x80000000)) > 0) {
val = val - 0x100000000L;
}
return new BigDecimal(val);
} else if (type[0].startsWith(VALUE_TYPE_INT8)) {
Long val = Long.valueOf(type[1], 16);
if ((val & 0x80) > 0) {
val = val - 0x100;
}
return new BigDecimal(val);
} else if (VALUE_TYPE_FLOAT.equalsIgnoreCase(type[0])) {
return parseFloatValue(type[1]);
}
}
logger.warn("Unknown value type [{}]", type[0]);
return BigDecimal.ZERO;
}
@ -349,29 +402,25 @@ public class SenecHomeHandler extends BaseThingHandler {
updateState(channel.getUID(), status ? OnOffType.ON : OnOffType.OFF);
}
protected void updateBatteryState(Channel channel, int code) {
updateState(channel.getUID(), new StringType(SenecBatteryStatus.descriptionFromCode(code)));
}
protected void updateGridPowerValues(BigDecimal gridTotalValue) {
BigDecimal gridTotal = gridTotalValue.setScale(2, RoundingMode.HALF_UP);
Channel channelGridPower = getThing().getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER);
if (channelGridPower != null) {
updateState(channelGridPower.getUID(), new QuantityType<Power>(gridTotal, Units.WATT));
updateState(channelGridPower.getUID(), new QuantityType<>(gridTotal, Units.WATT));
}
Channel channelGridPowerSupply = getThing()
.getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER_SUPPLY);
if (channelGridPowerSupply != null) {
BigDecimal gridSupply = gridTotal.compareTo(BigDecimal.ZERO) < 0 ? gridTotal.abs() : BigDecimal.ZERO;
updateState(channelGridPowerSupply.getUID(), new QuantityType<Power>(gridSupply, Units.WATT));
updateState(channelGridPowerSupply.getUID(), new QuantityType<>(gridSupply, Units.WATT));
}
Channel channelGridPowerDraw = getThing().getChannel(SenecHomeBindingConstants.CHANNEL_SENEC_GRID_POWER_DRAW);
if (channelGridPowerDraw != null) {
BigDecimal gridDraw = gridTotal.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : gridTotal.abs();
updateState(channelGridPowerDraw.getUID(), new QuantityType<Power>(gridDraw, Units.WATT));
updateState(channelGridPowerDraw.getUID(), new QuantityType<>(gridDraw, Units.WATT));
}
}
}

View File

@ -13,13 +13,13 @@
package org.openhab.binding.senechome.internal;
/**
* The {@link SenecBatteryStatus} class defines available Senec specific
* battery states.
* The {@link SenecSystemStatus} class defines available Senec specific
* system states.
*
* @author Steven Schwarznau - Initial contribution
*
*/
public enum SenecBatteryStatus {
public enum SenecSystemStatus {
INITIALSTATE(0, "INITIAL STATE"),
ERROR_INVERTER_COMMUNICATION(1, "ERROR INVERTER COMMUNICATION"),
@ -118,7 +118,7 @@ public enum SenecBatteryStatus {
private int code;
private String description;
SenecBatteryStatus(int index, String description) {
SenecSystemStatus(int index, String description) {
this.code = index;
this.description = description;
}
@ -131,21 +131,21 @@ public enum SenecBatteryStatus {
return description;
}
public static SenecBatteryStatus fromCode(int code) {
for (SenecBatteryStatus state : SenecBatteryStatus.values()) {
public static SenecSystemStatus fromCode(int code) {
for (SenecSystemStatus state : SenecSystemStatus.values()) {
if (state.code == code) {
return state;
}
}
return SenecBatteryStatus.UNKNOWN;
return SenecSystemStatus.UNKNOWN;
}
public static String descriptionFromCode(int code) {
for (SenecBatteryStatus state : SenecBatteryStatus.values()) {
for (SenecSystemStatus state : SenecSystemStatus.values()) {
if (state.code == code) {
return state.description;
}
}
return SenecBatteryStatus.UNKNOWN.description;
return SenecSystemStatus.UNKNOWN.description;
}
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal;
/**
* Enum with available Senec specific wallbox states.
*
* @author Erwin Guib - Initial Contribution
*/
public enum SenecWallboxStatus {
WAIT_FOR_EV(0xA1, "Waiting for EV"),
EV_ASKING_CHARGE(0xB1, "EV asking for charge"),
EV_CHARGE_PERMISSION(0xB2, "EV has charge permission"),
EV_CHARGING(0xC2, "Charging"),
EV_CHARGING_REDUCED_CURRENT_ERROR(0xC3, "Charging reduced current (error F16, F17)"),
EV_CHARGING_REDUCED_CURRENT_IMBALANCE(0xC4, "Charging reduced current (imbalance F15)"),
DISABLED(0xE0, "Wallbox disabled"),
TEST_PRODUCTION(0xE1, "production test"),
EVCC_PROGRAM(0xE2, "EVCC program mode"),
BUS_IDLE(0xE3, "Bus idle"),
UNEXPECTED_CLOSED_CONTACT(0xF1, "unexpected closed contact (welded)"),
INTERNAL_ERROR(0xF2, "Internal error"),
DC_RESIDUAL_CURRENT(0xF3, "DC residual current detected"),
UPSTREAM_COM_TIMEOUT(0xF4, "Upstream communication timeout"),
LOCK_SOCKET_FAILED(0xF5, "Lock of socket failed"),
CS_OUT_OF_RANGE(0xF6, "CS out of range"),
EV_HIGH_TEMP(0xF7, "State D requested by EV"),
CP_OUT_OF_RANGE(0xF8, "CP out of range"),
OVERCURRENT(0xF9, "Overcurrent detected"),
TEMP_OUT_OF_LIMITS(0xFA, "Temperature outside limits"),
UNEXPECTED_OPEN_CONTACT(0xFB, "unexpected opened contact"),
RESERVED_1(0xFC, "Reserved State"),
RESERVED_2(0xFD, "Reserved State"),
UNKNOWN(-1, "UNKNOWN");
private final int code;
private final String description;
SenecWallboxStatus(int index, String description) {
this.code = index;
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
public static SenecWallboxStatus fromCode(int code) {
for (SenecWallboxStatus state : SenecWallboxStatus.values()) {
if (state.code == code) {
return state;
}
}
return SenecWallboxStatus.UNKNOWN;
}
public static String descriptionFromCode(int code) {
for (SenecWallboxStatus state : SenecWallboxStatus.values()) {
if (state.code == code) {
return state.description;
}
}
return SenecWallboxStatus.UNKNOWN.description;
}
}

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import java.util.Arrays;
import com.google.gson.annotations.SerializedName;
/**
* Battery related data from section "BMS".
*
* @author Erwin Guib - Initial Contribution
*/
public class SenecHomeBattery implements Serializable {
public static final long serialVersionUID = -2850415059107677832L;
/**
* Total charged energy per battery pack (mWh).
*/
public @SerializedName("CHARGED_ENERGY") String[] chargedEnergy;
/**
* Total discharged energy per battery pack (mWh).
*/
public @SerializedName("DISCHARGED_ENERGY") String[] dischargedEnergy;
/**
* Number of load cycles per battery pack.
*/
public @SerializedName("CYCLES") String[] cycles;
/**
* Current per battery pack (A).
*/
public @SerializedName("CURRENT") String[] current;
/**
* Voltage per battery pack (V).
*/
public @SerializedName("VOLTAGE") String[] voltage;
/**
* Maximum cell voltage per battery pack (mV).
*/
public @SerializedName("MAX_CELL_VOLTAGE") String[] maxCellVoltage;
/**
* Minimum cell voltage per battery pack (mV).
*/
public @SerializedName("MIN_CELL_VOLTAGE") String[] minCellVoltage;
@Override
public String toString() {
return "SenecHomeBattery{" + "chargedEnergy=" + Arrays.toString(chargedEnergy) + ", dischargedEnergy="
+ Arrays.toString(dischargedEnergy) + ", cycles=" + Arrays.toString(cycles) + ", current="
+ Arrays.toString(current) + ", voltage=" + Arrays.toString(voltage) + ", maxCellVoltage="
+ Arrays.toString(maxCellVoltage) + ", minCellVoltage=" + Arrays.toString(minCellVoltage) + '}';
}
}

View File

@ -20,23 +20,55 @@ import com.google.gson.annotations.SerializedName;
* Json model of senec home devices: This sub model contains values of current workload, i. e. current consumption and
* battery charge.
*
* Section is "ENERGY"
*
* @author Steven Schwarznau - Initial Contribution
*/
public class SenecHomeEnergy implements Serializable {
private static final long serialVersionUID = -6171687327416551070L;
private static final long serialVersionUID = -5491226594672777034L;
public @SerializedName("GUI_HOUSE_POW") String homePowerConsumption;
/**
* House power consumption (W).
*/
public @SerializedName("GUI_HOUSE_POW") String housePowerConsumption;
/**
* Total inverter power (W).
* Named "energyProduction" on channel/thing-type side.
*/
public @SerializedName("GUI_INVERTER_POWER") String inverterPowerGeneration;
/**
* Battery power in W (+values loading, -values unloading)
*/
public @SerializedName("GUI_BAT_DATA_POWER") String batteryPower;
public @SerializedName("GUI_BAT_DATA_FUEL_CHARGE") String batteryFuelCharge;
public @SerializedName("STAT_STATE") String batteryState;
/**
* Battery current (A).
*/
public @SerializedName("GUI_BAT_DATA_CURRENT") String batteryCurrent;
/**
* Battery voltage (V).
*/
public @SerializedName("GUI_BAT_DATA_VOLTAGE") String batteryVoltage;
/**
* Battery charge rate (%).
*/
public @SerializedName("GUI_BAT_DATA_FUEL_CHARGE") String batteryFuelCharge;
/**
* Encoded system state.
*/
public @SerializedName("STAT_STATE") String systemState;
@Override
public String toString() {
return "SenecHomeEnergy [homePowerConsumption=" + homePowerConsumption + ", inverterPowerGeneration="
+ inverterPowerGeneration + ", batteryPower=" + batteryPower + ", batteryFuelCharge="
+ batteryFuelCharge + ", batteryState=" + batteryState + ", batteryVoltage" + batteryVoltage + "]";
return "SenecHomeEnergy [housePowerConsumption=" + housePowerConsumption + ", inverterPowerGeneration="
+ inverterPowerGeneration + ", batteryPower=" + batteryPower + ", batteryVoltage=" + batteryVoltage
+ ", batteryCurrent=" + batteryCurrent + ", batteryFuelCharge=" + batteryFuelCharge + ", systemState="
+ systemState + "]";
}
}

View File

@ -17,7 +17,9 @@ import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
/**
* Json model of senec home devices: This sub model provides the current power statistics by the inverter.
* Json model of senec home devices: This sub model contains grid related power values.
*
* Section "PM1OBJ1" (Enfluri Netz Werte)
*
* @author Steven Schwarznau - Initial Contribution
*/

View File

@ -1,34 +0,0 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
/**
* Json model of senec home devices: This sub model contains grid related power values.
*
* @author Steven Schwarznau - Initial Contribution
*/
public class SenecHomeLimitation implements Serializable {
private static final long serialVersionUID = -8990871346958824085L;
public @SerializedName("POWER_RATIO") String powerLimitation;
@Override
public String toString() {
return "SenecHomePower [powerLimitation=" + powerLimitation + "]";
}
}

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import java.util.Arrays;
import com.google.gson.annotations.SerializedName;
/**
* Json model of senec home devices: This sub model provides the current power statistics by the inverter.
*
* Section "PV1" in Senec JSON.
*
* @author Steven Schwarznau - Initial Contribution
*/
public class SenecHomePower implements Serializable {
private static final long serialVersionUID = -7092741166288342343L;
/**
* Power limitation (%).
*/
public @SerializedName("POWER_RATIO") String powerLimitation;
/**
* Current DC current per MPP (A).
*/
public @SerializedName("MPP_CUR") String[] currentPerMpp;
/**
* Current DC power per MPP (W)
*/
public @SerializedName("MPP_POWER") String[] powerPerMpp;
/**
* Current DC tension per MPP (V).
*/
public @SerializedName("MPP_VOL") String[] voltagePerMpp;
@Override
public String toString() {
return "SenecHomePower [powerLimitation=" + powerLimitation + ", mppCur=" + Arrays.toString(currentPerMpp)
+ ", mppPower=" + Arrays.toString(powerPerMpp) + ", mppVol=" + Arrays.toString(voltagePerMpp) + "]";
}
}

View File

@ -23,16 +23,19 @@ import com.google.gson.annotations.SerializedName;
*/
public class SenecHomeResponse implements Serializable {
private static final long serialVersionUID = 5302080655053778494L;
private static final long serialVersionUID = -2672622188872750438L;
public @SerializedName("PV1") SenecHomeLimitation limitation = new SenecHomeLimitation();
public @SerializedName("PV1") SenecHomePower power = new SenecHomePower();
public @SerializedName("ENERGY") SenecHomeEnergy energy = new SenecHomeEnergy();
public @SerializedName("PM1OBJ1") SenecHomeGrid grid = new SenecHomeGrid();
public @SerializedName("STATISTIC") SenecHomeStatistics statistics = new SenecHomeStatistics();
public @SerializedName("BMS") SenecHomeBattery battery = new SenecHomeBattery();
public @SerializedName("TEMPMEASURE") SenecHomeTemperature temperature = new SenecHomeTemperature();
public @SerializedName("WALLBOX") SenecHomeWallbox wallbox = new SenecHomeWallbox();
@Override
public String toString() {
return "SenecHomeResponse [limitation=" + limitation + ", energy=" + energy + ", grid=" + grid + ", statistics="
+ statistics + "]";
return "SenecHomeResponse [power=" + power + ", energy=" + energy + ", grid=" + grid + ", statistics="
+ statistics + "battery" + battery + "temperature" + temperature + "wallbox" + wallbox + "]";
}
}

View File

@ -13,41 +13,61 @@
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import java.util.Arrays;
import com.google.gson.annotations.SerializedName;
/**
* Json model of senec home devices: This sub model provides the current statistics by the inverter.
*
* Section "STATISTIC" in Senec JSON.
*
* @author Korbinian Probst - Initial Contribution
*/
public class SenecHomeStatistics implements Serializable {
private static final long serialVersionUID = -7479338432170375451L;
private static final long serialVersionUID = -1102310892637495823L;
/**
* total Wh charged to the battery
* total Wh charged to the battery (kWh)
*/
public @SerializedName("LIVE_BAT_CHARGE") String liveBatCharge;
/**
* total Wh discharged from the battery
* total Wh discharged from the battery (kWh)
*/
public @SerializedName("LIVE_BAT_DISCHARGE") String liveBatDischarge;
/**
* total Wh imported from grid
* total Wh imported from grid (kWh)
*/
public @SerializedName("LIVE_GRID_IMPORT") String liveGridImport;
/**
* total Wh supplied to the grid
* total Wh supplied to the grid (kWh)
*/
public @SerializedName("LIVE_GRID_EXPORT") String liveGridExport;
/**
* Total house consumption (kWh)
*/
public @SerializedName("LIVE_HOUSE_CONS") String liveHouseConsumption;
/**
* Total Wh produced (kWh)
*/
public @SerializedName("LIVE_PV_GEN") String livePowerGenerator;
/**
* Total Wh provided to Wallbox (Wh)
*/
public @SerializedName("LIVE_WB_ENERGY") String[] liveWallboxEnergy;
@Override
public String toString() {
return "SenecHomeStatistics [liveBatCharge=" + liveBatCharge + ", liveBatDischarge= " + liveBatDischarge
+ ", liveGridImport= " + liveGridImport + ", liveGridExport= " + liveGridExport + "]";
return "SenecHomeStatistics [liveBatCharge=" + liveBatCharge + ", liveBatDischarge=" + liveBatDischarge
+ ", liveGridImport=" + liveGridImport + ", liveGridExport=" + liveGridExport
+ ", liveHouseConsumption=" + liveHouseConsumption + ", livePowerGen=" + livePowerGenerator
+ ", liveWallboxEnergy=" + Arrays.toString(liveWallboxEnergy) + "]";
}
}

View File

@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
/**
* Senec Temperature information from "TEMPMEASURE" section.
*
* @author Erwin Guib - Initial Contribution
*/
public class SenecHomeTemperature implements Serializable {
private static final long serialVersionUID = 5300207918289980752L;
/**
* Battery temperature (°C).
*/
public @SerializedName("BATTERY_TEMP") String batteryTemperature;
/**
* Case temperature (°C).
*/
public @SerializedName("CASE_TEMP") String caseTemperature;
/**
* MCU Temperature (°C).
*/
public @SerializedName("MCU_TEMP") String mcuTemperature;
@Override
public String toString() {
return "SenecHomeTemperature{" + "batteryTemperature='" + batteryTemperature + '\'' + ", caseTemperature='"
+ caseTemperature + '\'' + ", mcuTemperature='" + mcuTemperature + '\'' + '}';
}
}

View File

@ -0,0 +1,60 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal.json;
import java.io.Serializable;
import java.util.Arrays;
import com.google.gson.annotations.SerializedName;
/**
* Senec wallbox specific data from "WALLBOX" section.
*
* @author Erwin Guib - Initial Contribution
*/
public class SenecHomeWallbox implements Serializable {
private static final long serialVersionUID = -664163242812451235L;
/**
* Encoded wallbox state.
*/
public @SerializedName("STATE") String[] state;
/**
* L1 Charging current per wallbox (A).
*/
public @SerializedName("L1_CHARGING_CURRENT") String[] l1ChargingCurrent;
/**
* L2 Charging current per wallbox (A).
*/
public @SerializedName("L2_CHARGING_CURRENT") String[] l2ChargingCurrent;
/**
* L3 Charging current per wallbox (A).
*/
public @SerializedName("L3_CHARGING_CURRENT") String[] l3ChargingCurrent;
/**
* Charging power per wallbox (W).
*/
public @SerializedName("APPARENT_CHARGING_POWER") String[] chargingPower;
@Override
public String toString() {
return "SenecWallbox{" + "l1ChargingCurrent=" + Arrays.toString(l1ChargingCurrent) + ", l2ChargingCurrent="
+ Arrays.toString(l2ChargingCurrent) + ", l3ChargingCurrent=" + Arrays.toString(l3ChargingCurrent)
+ '}';
}
}

View File

@ -10,14 +10,30 @@
<description>Senec Home</description>
<channels>
<!-- SenecHomePower -->
<channel id="powerLimitation" typeId="powerLimitation"/>
<channel id="powerLimitationState" typeId="powerLimitationState"/>
<channel id="currentMpp1" typeId="currentMpp1"/>
<channel id="currentMpp2" typeId="currentMpp2"/>
<channel id="currentMpp3" typeId="currentMpp3"/>
<channel id="powerMpp1" typeId="powerMpp1"/>
<channel id="powerMpp2" typeId="powerMpp2"/>
<channel id="powerMpp3" typeId="powerMpp3"/>
<channel id="voltageMpp1" typeId="voltageMpp1"/>
<channel id="voltageMpp2" typeId="voltageMpp2"/>
<channel id="voltageMpp3" typeId="voltageMpp3"/>
<!-- SenecHomeEnergy -->
<channel id="houseConsumption" typeId="houseConsumption"/>
<channel id="energyProduction" typeId="energyProduction"/>
<channel id="batteryPower" typeId="batteryPower"/>
<channel id="batteryCurrent" typeId="batteryCurrent"/>
<channel id="batteryVoltage" typeId="batteryVoltage"/>
<channel id="batteryFuelCharge" typeId="batteryFuelCharge"/>
<channel id="batteryState" typeId="batteryState"/>
<channel id="batteryStateValue" typeId="batteryStateValue"/>
<channel id="systemState" typeId="systemState"/>
<channel id="systemStateValue" typeId="systemStateValue"/>
<!-- SenecHomeGrid -->
<channel id="gridPower" typeId="gridPower"/>
<channel id="gridPowerSupply" typeId="gridPowerSupply"/>
<channel id="gridPowerDraw" typeId="gridPowerDraw"/>
@ -31,11 +47,58 @@
<channel id="gridVoltagePhase2" typeId="gridVoltagePhase2"/>
<channel id="gridVoltagePhase3" typeId="gridVoltagePhase3"/>
<channel id="gridFrequency" typeId="gridFrequency"/>
<channel id="batteryVoltage" typeId="batteryVoltage"/>
<!-- SenecHomeStatistics -->
<channel id="liveBatCharge" typeId="liveBatCharge"/>
<channel id="liveBatDischarge" typeId="liveBatDischarge"/>
<channel id="liveGridImport" typeId="liveGridImport"/>
<channel id="liveGridExport" typeId="liveGridExport"/>
<channel id="liveHouseConsumption" typeId="liveHouseConsumption"/>
<channel id="livePowerGenerator" typeId="livePowerGenerator"/>
<channel id="liveEnergyWallbox1" typeId="liveEnergyWallbox1"/>
<!-- SenecHomeBattery -->
<channel id="chargedEnergyPack1" typeId="chargedEnergyPack1"/>
<channel id="chargedEnergyPack2" typeId="chargedEnergyPack2"/>
<channel id="chargedEnergyPack3" typeId="chargedEnergyPack3"/>
<channel id="chargedEnergyPack4" typeId="chargedEnergyPack4"/>
<channel id="dischargedEnergyPack1" typeId="dischargedEnergyPack1"/>
<channel id="dischargedEnergyPack2" typeId="dischargedEnergyPack2"/>
<channel id="dischargedEnergyPack3" typeId="dischargedEnergyPack3"/>
<channel id="dischargedEnergyPack4" typeId="dischargedEnergyPack4"/>
<channel id="cyclesPack1" typeId="cyclesPack1"/>
<channel id="cyclesPack2" typeId="cyclesPack2"/>
<channel id="cyclesPack3" typeId="cyclesPack3"/>
<channel id="cyclesPack4" typeId="cyclesPack4"/>
<channel id="currentPack1" typeId="currentPack1"/>
<channel id="currentPack2" typeId="currentPack2"/>
<channel id="currentPack3" typeId="currentPack3"/>
<channel id="currentPack4" typeId="currentPack4"/>
<channel id="voltagePack1" typeId="voltagePack1"/>
<channel id="voltagePack2" typeId="voltagePack2"/>
<channel id="voltagePack3" typeId="voltagePack3"/>
<channel id="voltagePack4" typeId="voltagePack4"/>
<channel id="maxCellVoltagePack1" typeId="maxCellVoltagePack1"/>
<channel id="maxCellVoltagePack2" typeId="maxCellVoltagePack2"/>
<channel id="maxCellVoltagePack3" typeId="maxCellVoltagePack3"/>
<channel id="maxCellVoltagePack4" typeId="maxCellVoltagePack4"/>
<channel id="minCellVoltagePack1" typeId="minCellVoltagePack1"/>
<channel id="minCellVoltagePack2" typeId="minCellVoltagePack2"/>
<channel id="minCellVoltagePack3" typeId="minCellVoltagePack3"/>
<channel id="minCellVoltagePack4" typeId="minCellVoltagePack4"/>
<!-- SenecHomeTemperature -->
<channel id="batteryTemperature" typeId="batteryTemperature"/>
<channel id="caseTemperature" typeId="caseTemperature"/>
<channel id="mcuTemperature" typeId="mcuTemperature"/>
<!-- SenecHomeWallbox -->
<channel id="wallbox1State" typeId="wallbox1State"/>
<channel id="wallbox1StateValue" typeId="wallbox1StateValue"/>
<channel id="wallbox1ChargingCurrentPhase1" typeId="wallbox1ChargingCurrentPhase1"/>
<channel id="wallbox1ChargingCurrentPhase2" typeId="wallbox1ChargingCurrentPhase2"/>
<channel id="wallbox1ChargingCurrentPhase3" typeId="wallbox1ChargingCurrentPhase3"/>
<channel id="wallbox1ChargingPower" typeId="wallbox1ChargingPower"/>
</channels>
<config-description>
@ -66,58 +129,120 @@
<channel-type id="powerLimitation">
<item-type>Number:Dimensionless</item-type>
<label>Power Limitation</label>
<category>Energy</category>
<category>Number</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="powerLimitationState">
<item-type>Switch</item-type>
<label>Limitation State</label>
<category>Energy</category>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="houseConsumption">
<channel-type id="currentMpp1">
<item-type>Number:ElectricCurrent</item-type>
<label>Current MPP1</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="currentMpp2">
<item-type>Number:ElectricCurrent</item-type>
<label>Current MPP2</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="currentMpp3">
<item-type>Number:ElectricCurrent</item-type>
<label>Current MPP3</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="powerMpp1">
<item-type>Number:Power</item-type>
<label>Home Power Consumption</label>
<label>Power MPP1</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="powerMpp2">
<item-type>Number:Power</item-type>
<label>Power MPP2</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="powerMpp3">
<item-type>Number:Power</item-type>
<label>Power MPP3</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltageMpp1">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage MPP1</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltageMpp2">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage MPP2</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltageMpp3">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage MPP3</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="houseConsumption">
<item-type>Number:Power</item-type>
<label>House Power Consumption</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="energyProduction">
<item-type>Number:Power</item-type>
<label>Solar Production</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="batteryPower">
<item-type>Number:Power</item-type>
<label>Battery Power</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="batteryCurrent">
<item-type>Number:ElectricCurrent</item-type>
<label>Battery Current</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="batteryVoltage">
<item-type>Number:ElectricPotential</item-type>
<label>Battery Voltage</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="batteryFuelCharge">
<item-type>Number:Dimensionless</item-type>
<label>Battery Fuel</label>
<category>Battery</category>
<category>BatteryLevel</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="batteryState">
<channel-type id="systemState">
<item-type>String</item-type>
<label>Battery State</label>
<category>Battery</category>
<label>System State</label>
<category>Text</category>
<state readOnly="true" pattern="%s"/>
</channel-type>
<channel-type id="batteryStateValue">
<channel-type id="systemStateValue">
<item-type>Number</item-type>
<label>Battery State Value</label>
<category>Battery</category>
<label>System State Value</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="energyProduction">
<item-type>Number:Power</item-type>
<label>Solar Production</label>
<category>Energy</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="gridPower">
<item-type>Number:Power</item-type>
@ -125,84 +250,72 @@
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridPowerSupply">
<item-type>Number:Power</item-type>
<label>Grid Supply</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridPowerDraw">
<item-type>Number:Power</item-type>
<label>Grid Draw</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridPowerPhase1">
<item-type>Number:Power</item-type>
<label>Grid Power Phase 1</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridPowerPhase2">
<item-type>Number:Power</item-type>
<label>Grid Power Phase 2</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridPowerPhase3">
<item-type>Number:Power</item-type>
<label>Grid Power Phase 3</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridCurrentPhase1">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Current Phase 1</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridCurrentPhase2">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Current Phase 2</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridCurrentPhase3">
<item-type>Number:ElectricCurrent</item-type>
<label>Grid Current Phase 3</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridVoltagePhase1">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage Phase 1</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridVoltagePhase2">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage Phase 2</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridVoltagePhase3">
<item-type>Number:ElectricPotential</item-type>
<label>Grid Voltage Phase 3</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="gridFrequency">
<item-type>Number:Frequency</item-type>
<label>Grid Frequency</label>
@ -210,38 +323,275 @@
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveBatCharge">
<item-type>Number:Energy</item-type>
<label>Live Bat Charge</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveBatDischarge">
<item-type>Number:Energy</item-type>
<label>Live Bat Discharge</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveGridImport">
<item-type>Number:Energy</item-type>
<label>Live Grid Import</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveGridExport">
<item-type>Number:Energy</item-type>
<label>Live Grid Export</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveHouseConsumption">
<item-type>Number:Energy</item-type>
<label>Live House Consumption</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="livePowerGenerator">
<item-type>Number:Energy</item-type>
<label>Live Power Generator</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="liveEnergyWallbox1">
<item-type>Number:Energy</item-type>
<label>Live Wallbox 1 charged Energy</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="batteryVoltage">
<channel-type id="chargedEnergyPack1" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total charged energy battery pack 1</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="chargedEnergyPack2" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total charged energy battery pack 2</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="chargedEnergyPack3" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total charged energy battery pack 3</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="chargedEnergyPack4" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total charged energy battery pack 4</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="dischargedEnergyPack1" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total discharged energy battery pack 1</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="dischargedEnergyPack2" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total discharged energy battery pack 2</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="dischargedEnergyPack3" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total discharged energy battery pack 3</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="dischargedEnergyPack4" advanced="true">
<item-type>Number:Energy</item-type>
<label>Total discharged energy battery pack 4</label>
<category>Energy</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="cyclesPack1" advanced="true">
<item-type>Number</item-type>
<label>Cycles battery pack 1</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="cyclesPack2" advanced="true">
<item-type>Number</item-type>
<label>Cycles battery pack 2</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="cyclesPack3" advanced="true">
<item-type>Number</item-type>
<label>Cycles battery pack 3</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="cyclesPack4" advanced="true">
<item-type>Number</item-type>
<label>Cycles battery pack 4</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="currentPack1" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Current battery pack 1</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="currentPack2" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Current battery pack 2</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="currentPack3" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Current battery pack 3</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="currentPack4" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Current battery pack 4</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltagePack1" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Battery Voltage</label>
<label>Voltage battery pack 1</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltagePack2" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage battery pack 2</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltagePack3" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage battery pack 3</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="voltagePack4" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Voltage battery pack 4</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="maxCellVoltagePack1" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Maximum cell voltage battery pack 1</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="maxCellVoltagePack2" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Maximum cell voltage battery pack 2</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="maxCellVoltagePack3" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Maximum cell voltage battery pack 3</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="maxCellVoltagePack4" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Maximum cell voltage battery pack 4</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="minCellVoltagePack1" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Minimum cell voltage battery pack 1</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="minCellVoltagePack2" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Minimum cell voltage battery pack 2</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="minCellVoltagePack3" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Minimum cell voltage battery pack 3</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="minCellVoltagePack4" advanced="true">
<item-type>Number:ElectricPotential</item-type>
<label>Minimum cell voltage battery pack 4</label>
<category>Voltage</category>
<state readOnly="true" pattern="%.3f %unit%"/>
</channel-type>
<channel-type id="batteryTemperature">
<item-type>Number:Temperature</item-type>
<label>Battery Temperature</label>
<category>Temperature</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="caseTemperature">
<item-type>Number:Temperature</item-type>
<label>Case Temperature</label>
<category>Temperature</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="mcuTemperature">
<item-type>Number:Temperature</item-type>
<label>MCU Temperature</label>
<category>Temperature</category>
<state readOnly="true" pattern="%.0f %unit%"/>
</channel-type>
<channel-type id="wallbox1State">
<item-type>String</item-type>
<label>Wallbox 1 State</label>
<category>Text</category>
<state readOnly="true" pattern="%s"/>
</channel-type>
<channel-type id="wallbox1StateValue">
<item-type>Number</item-type>
<label>Wallbox 1 State Value</label>
<category>Number</category>
<state readOnly="true" pattern="%d"/>
</channel-type>
<channel-type id="wallbox1ChargingCurrentPhase1" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Wallbox 1 charging Current Phase 1</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="wallbox1ChargingCurrentPhase2" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Wallbox 1 charging Current Phase 2</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="wallbox1ChargingCurrentPhase3" advanced="true">
<item-type>Number:ElectricCurrent</item-type>
<label>Wallbox 1 charging Current Phase 3</label>
<category>Current</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
<channel-type id="wallbox1ChargingPower">
<item-type>Number:Energy</item-type>
<label>Wallbox 1 charging Power</label>
<category>Power</category>
<state readOnly="true" pattern="%.2f %unit%"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.senechome.internal;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.eclipse.jetty.client.HttpClient;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.openhab.core.thing.Thing;
/**
* Test for senec value parsing. All test data are from "original" senec (using vars.html).
*
* @author Erwin Guib - Initial Contribution
*/
@RunWith(MockitoJUnitRunner.class)
class SenecHomeHandlerTest {
protected static Object[][] data() {
return new Object[][] {
// unsigned
{ "u1_0002", BigDecimal.valueOf(2) }, //
{ "u1_07DB", BigDecimal.valueOf(2011) }, //
{ "u3_0000194C", BigDecimal.valueOf(6476) }, //
{ "u3_817E00E0", BigDecimal.valueOf(2172518624L) }, //
{ "u6_0000000000000001", BigDecimal.valueOf(1) }, //
{ "u6_00000000000C75D9", BigDecimal.valueOf(816601) }, //
{ "u8_64", BigDecimal.valueOf(100) }, //
// int
{ "i1_00FA", BigDecimal.valueOf(250) }, //
{ "i3_00000078", BigDecimal.valueOf(120) }, //
{ "i3_609F8480", BigDecimal.valueOf(1621066880) }, //
{ "i3_FFFFFFFF", BigDecimal.valueOf(-1) }, //
{ "i8_18", BigDecimal.valueOf(24) }, //
// string (unknown)
{ "st_HMI: 3.15.32 PU: 4.1.89", BigDecimal.valueOf(0) } };
}
protected static Object[][] floatData() {
return new Object[][] {
// float
{ "fl_41C80000", BigDecimal.valueOf(25), 0 }, //
{ "fl_4247632F", BigDecimal.valueOf(49.85), 2 }, //
{ "fl_C5AB6F0B", BigDecimal.valueOf(-5485.88), 2 }, //
{ "fl_4248CCCD", BigDecimal.valueOf(50.2), 1 }, //
};
}
@Mock
Thing mockThing;
@Mock
HttpClient mockHttpClient;
SenecHomeHandler cut = new SenecHomeHandler(mockThing, mockHttpClient);
@ParameterizedTest
@MethodSource("data")
void getSenecValue(String value, Object expectedResult) {
Assertions.assertEquals(expectedResult, cut.getSenecValue(value));
}
@ParameterizedTest
@MethodSource("floatData")
void getSenecValueFloat(String value, Object expectedResult, int scale) {
Assertions.assertEquals(expectedResult, cut.getSenecValue(value).setScale(scale, RoundingMode.HALF_UP));
}
}