2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.modbus.sunspec.internal.handler;
15 import static org.openhab.binding.modbus.sunspec.internal.SunSpecConstants.*;
16 import static org.openhab.core.library.unit.SIUnits.CELSIUS;
17 import static org.openhab.core.library.unit.Units.*;
19 import java.util.Optional;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.modbus.sunspec.internal.InverterStatus;
23 import org.openhab.binding.modbus.sunspec.internal.dto.InverterModelBlock;
24 import org.openhab.binding.modbus.sunspec.internal.parser.InverterModelParser;
25 import org.openhab.core.io.transport.modbus.ModbusRegisterArray;
26 import org.openhab.core.library.types.StringType;
27 import org.openhab.core.thing.Thing;
28 import org.openhab.core.types.UnDefType;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
33 * The {@link InverterHandler} is responsible for handling commands, which are
34 * sent to an inverter and publishing the received values to OpenHAB.
36 * @author Nagy Attila Gabor - Initial contribution
39 public class InverterHandler extends AbstractSunSpecHandler {
42 * Parser used to convert incoming raw messages into model blocks
44 private final InverterModelParser parser = new InverterModelParser();
49 private final Logger logger = LoggerFactory.getLogger(InverterHandler.class);
51 public InverterHandler(Thing thing) {
56 * This method is called each time new data has been polled from the modbus slave
57 * The register array is first parsed, then each of the channels are updated
60 * @param registers byte array read from the modbus slave
63 protected void handlePolledData(ModbusRegisterArray registers) {
64 logger.trace("Model block received, size: {}", registers.size());
66 InverterModelBlock block = parser.parse(registers);
68 // Device information group
69 updateState(channelUID(GROUP_DEVICE_INFO, CHANNEL_CABINET_TEMPERATURE),
70 getScaled(block.temperatureCabinet, block.temperatureSF, CELSIUS));
72 updateState(channelUID(GROUP_DEVICE_INFO, CHANNEL_HEATSINK_TEMPERATURE),
73 getScaled(block.temperatureHeatsink, Optional.of(block.temperatureSF), CELSIUS));
75 updateState(channelUID(GROUP_DEVICE_INFO, CHANNEL_TRANSFORMER_TEMPERATURE),
76 getScaled(block.temperatureTransformer, Optional.of(block.temperatureSF), CELSIUS));
78 updateState(channelUID(GROUP_DEVICE_INFO, CHANNEL_OTHER_TEMPERATURE),
79 getScaled(block.temperatureOther, Optional.of(block.temperatureSF), CELSIUS));
81 InverterStatus status = InverterStatus.getByCode(block.status);
82 updateState(channelUID(GROUP_DEVICE_INFO, CHANNEL_STATUS),
83 status == null ? UnDefType.UNDEF : new StringType(status.name()));
86 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_TOTAL_CURRENT),
87 getScaled(block.acCurrentTotal, block.acCurrentSF, AMPERE));
89 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_POWER), getScaled(block.acPower, block.acPowerSF, WATT));
91 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_FREQUENCY),
92 getScaled(block.acFrequency, block.acFrequencySF, HERTZ));
94 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_APPARENT_POWER),
95 getScaled(block.acApparentPower, block.acApparentPowerSF, WATT)); // TODO: VA currently not supported,
97 // https://github.com/openhab/openhab-core/pull/1347
99 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_REACTIVE_POWER),
100 getScaled(block.acReactivePower, block.acReactivePowerSF, WATT)); // TODO: var currently not supported,
102 // https://github.com/openhab/openhab-core/pull/1347
104 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_POWER_FACTOR),
105 getScaled(block.acPowerFactor, block.acPowerFactorSF, PERCENT));
107 updateState(channelUID(GROUP_AC_GENERAL, CHANNEL_AC_LIFETIME_ENERGY),
108 getScaled(block.acEnergyLifetime, block.acEnergyLifetimeSF, WATT_HOUR));
111 updateState(channelUID(GROUP_DC_GENERAL, CHANNEL_DC_CURRENT),
112 getScaled(block.dcCurrent, block.dcCurrentSF, AMPERE));
113 updateState(channelUID(GROUP_DC_GENERAL, CHANNEL_DC_VOLTAGE),
114 getScaled(block.dcVoltage, block.dcVoltageSF, VOLT));
115 updateState(channelUID(GROUP_DC_GENERAL, CHANNEL_DC_POWER), getScaled(block.dcPower, block.dcPowerSF, WATT));
117 // AC Phase specific groups
118 // All types of inverters
119 updateState(channelUID(GROUP_AC_PHASE_A, CHANNEL_AC_PHASE_CURRENT),
120 getScaled(block.acCurrentPhaseA, block.acCurrentSF, AMPERE));
121 updateState(channelUID(GROUP_AC_PHASE_A, CHANNEL_AC_VOLTAGE_TO_NEXT),
122 getScaled(block.acVoltageAB, block.acVoltageSF, VOLT));
123 updateState(channelUID(GROUP_AC_PHASE_A, CHANNEL_AC_VOLTAGE_TO_N),
124 getScaled(block.acVoltageAtoN, block.acVoltageSF, VOLT));
126 // Split phase and three phase
127 if ((thing.getThingTypeUID().equals(THING_TYPE_INVERTER_SPLIT_PHASE)
128 || thing.getThingTypeUID().equals(THING_TYPE_INVERTER_THREE_PHASE))
129 && block.phaseConfiguration >= INVERTER_SPLIT_PHASE) {
130 updateState(channelUID(GROUP_AC_PHASE_B, CHANNEL_AC_PHASE_CURRENT),
131 getScaled(block.acCurrentPhaseB, block.acCurrentSF, AMPERE));
132 updateState(channelUID(GROUP_AC_PHASE_B, CHANNEL_AC_VOLTAGE_TO_NEXT),
133 getScaled(block.acVoltageBC, block.acVoltageSF, VOLT));
134 updateState(channelUID(GROUP_AC_PHASE_B, CHANNEL_AC_VOLTAGE_TO_N),
135 getScaled(block.acVoltageBtoN, block.acVoltageSF, VOLT));
139 if (thing.getThingTypeUID().equals(THING_TYPE_INVERTER_THREE_PHASE)
140 && block.phaseConfiguration >= INVERTER_THREE_PHASE) {
141 updateState(channelUID(GROUP_AC_PHASE_C, CHANNEL_AC_PHASE_CURRENT),
142 getScaled(block.acCurrentPhaseC, block.acCurrentSF, AMPERE));
143 updateState(channelUID(GROUP_AC_PHASE_C, CHANNEL_AC_VOLTAGE_TO_NEXT),
144 getScaled(block.acVoltageCA, block.acVoltageSF, VOLT));
145 updateState(channelUID(GROUP_AC_PHASE_C, CHANNEL_AC_VOLTAGE_TO_N),
146 getScaled(block.acVoltageCtoN, block.acVoltageSF, VOLT));
149 resetCommunicationError();