]> git.basschouten.com Git - openhab-addons.git/blob
c36155b30dc08932c822ea70f610b90ad72e0bc9
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.modbus.e3dc.internal.handler;
14
15 import static org.openhab.binding.modbus.e3dc.internal.E3DCBindingConstants.*;
16 import static org.openhab.binding.modbus.e3dc.internal.modbus.E3DCModbusConstans.*;
17
18 import java.util.BitSet;
19 import java.util.Optional;
20 import java.util.OptionalInt;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.modbus.e3dc.internal.E3DCWallboxConfiguration;
25 import org.openhab.binding.modbus.e3dc.internal.dto.DataConverter;
26 import org.openhab.binding.modbus.e3dc.internal.dto.WallboxArray;
27 import org.openhab.binding.modbus.e3dc.internal.dto.WallboxBlock;
28 import org.openhab.binding.modbus.e3dc.internal.modbus.Data;
29 import org.openhab.binding.modbus.e3dc.internal.modbus.Data.DataType;
30 import org.openhab.binding.modbus.e3dc.internal.modbus.Parser;
31 import org.openhab.core.io.transport.modbus.AsyncModbusFailure;
32 import org.openhab.core.io.transport.modbus.AsyncModbusReadResult;
33 import org.openhab.core.io.transport.modbus.ModbusCommunicationInterface;
34 import org.openhab.core.io.transport.modbus.ModbusReadRequestBlueprint;
35 import org.openhab.core.io.transport.modbus.ModbusRegisterArray;
36 import org.openhab.core.io.transport.modbus.ModbusWriteRegisterRequestBlueprint;
37 import org.openhab.core.library.types.OnOffType;
38 import org.openhab.core.thing.Bridge;
39 import org.openhab.core.thing.ChannelUID;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.binding.BaseThingHandler;
44 import org.openhab.core.thing.binding.ThingHandler;
45 import org.openhab.core.types.Command;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * The {@link E3DCWallboxThingHandler} Basic modbus connection towards the E3DC device
51  *
52  * @author Bernd Weymann - Initial contribution
53  */
54 @NonNullByDefault
55 public class E3DCWallboxThingHandler extends BaseThingHandler {
56     public enum ReadWriteSuccess {
57         NOT_RECEIVED,
58         SUCCESS,
59         FAILED
60     }
61
62     private static final String READ_WRITE_ERROR = "Modbus Data Read/Write Error";
63     private static final String READ_ERROR = "Modbus Read Error";
64     private static final String WRITE_ERROR = "Modbus Write Error";
65
66     ChannelUID wbAvailableChannel;
67     ChannelUID wbSunmodeChannel;
68     ChannelUID wbChargingAbortedChannel;
69     ChannelUID wbChargingChannel;
70     ChannelUID wbJackLockedChannel;
71     ChannelUID wbJackPluggedChannel;
72     ChannelUID wbSchukoOnChannel;
73     ChannelUID wbSchukoPluggedChannel;
74     ChannelUID wbSchukoLockedChannel;
75     ChannelUID wbSchukoRelay16Channel;
76     ChannelUID wbRelay16Channel;
77     ChannelUID wbRelay32Channel;
78     ChannelUID wb1phaseChannel;
79
80     private final Logger logger = LoggerFactory.getLogger(E3DCWallboxThingHandler.class);
81     private final Parser dataParser = new Parser(DataType.DATA);
82     private ReadWriteSuccess dataRead = ReadWriteSuccess.NOT_RECEIVED;
83     private ReadWriteSuccess dataWrite = ReadWriteSuccess.NOT_RECEIVED;
84     private volatile BitSet currentBitSet = new BitSet(16);
85     private @Nullable E3DCWallboxConfiguration config;
86     private @Nullable E3DCThingHandler bridgeHandler;
87
88     public E3DCWallboxThingHandler(Thing thing) {
89         super(thing);
90         wbAvailableChannel = new ChannelUID(thing.getUID(), WB_AVAILABLE_CHANNEL);
91         wbSunmodeChannel = new ChannelUID(thing.getUID(), WB_SUNMODE_CHANNEL);
92         wbChargingAbortedChannel = new ChannelUID(thing.getUID(), WB_CHARGING_ABORTED_CHANNEL);
93         wbChargingChannel = new ChannelUID(thing.getUID(), WB_CHARGING_CHANNEL);
94         wbJackLockedChannel = new ChannelUID(thing.getUID(), WB_JACK_LOCKED_CHANNEL);
95         wbJackPluggedChannel = new ChannelUID(thing.getUID(), WB_JACK_PLUGGED_CHANNEL);
96         wbSchukoOnChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_ON_CHANNEL);
97         wbSchukoPluggedChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_PLUGGED_CHANNEL);
98         wbSchukoLockedChannel = new ChannelUID(thing.getUID(), WB_SCHUKO_LOCKED_CHANNEL);
99         wbSchukoRelay16Channel = new ChannelUID(thing.getUID(), WB_SCHUKO_RELAY_16A_CHANNEL);
100         wbRelay16Channel = new ChannelUID(thing.getUID(), WB_RELAY_16A_CHANNEL);
101         wbRelay32Channel = new ChannelUID(thing.getUID(), WB_RELAY_32A_CHANNEL);
102         wb1phaseChannel = new ChannelUID(thing.getUID(), WB_1PHASE_CHANNEL);
103     }
104
105     @Override
106     public void initialize() {
107         updateStatus(ThingStatus.UNKNOWN);
108         config = getConfigAs(E3DCWallboxConfiguration.class);
109         Bridge bridge = getBridge();
110         if (bridge != null) {
111             ThingHandler handler = bridge.getHandler();
112             if (handler != null) {
113                 bridgeHandler = ((E3DCThingHandler) handler);
114             } else {
115                 logger.warn("Thing Handler null");
116             }
117         } else {
118             logger.warn("Bridge null");
119         }
120     }
121
122     @Override
123     public void handleCommand(ChannelUID channelUID, Command command) {
124         if (command instanceof OnOffType) {
125             int writeValue = 0;
126             synchronized (this) {
127                 if (channelUID.getIdWithoutGroup().equals(WB_SUNMODE_CHANNEL)) {
128                     currentBitSet.set(WB_SUNMODE_BIT, command.equals(OnOffType.ON));
129                 } else if (channelUID.getIdWithoutGroup().equals(WB_CHARGING_ABORTED_CHANNEL)) {
130                     currentBitSet.set(WB_CHARGING_ABORTED_BIT, command.equals(OnOffType.ON));
131                 } else if (channelUID.getIdWithoutGroup().equals(WB_SCHUKO_ON_CHANNEL)) {
132                     currentBitSet.set(WB_SCHUKO_ON_BIT, command.equals(OnOffType.ON));
133                 } else if (channelUID.getIdWithoutGroup().equals(WB_1PHASE_CHANNEL)) {
134                     currentBitSet.set(WB_1PHASE_BIT, command.equals(OnOffType.ON));
135                 }
136                 writeValue = DataConverter.toInt(currentBitSet);
137                 logger.debug("Wallbox write {}", writeValue);
138             }
139             OptionalInt wallboxId = getWallboxId(config);
140             if (wallboxId.isPresent()) {
141                 wallboxSet(wallboxId.getAsInt(), writeValue);
142             }
143         }
144     }
145
146     /**
147      * Wallbox Settings can be changed with one Integer
148      *
149      * @param wallboxId needed to calculate right register
150      * @param writeValue integer to be written
151      */
152     public void wallboxSet(int wallboxId, int writeValue) {
153         E3DCThingHandler localBridgeHandler = bridgeHandler;
154         if (localBridgeHandler != null) {
155             ModbusCommunicationInterface comms = localBridgeHandler.getComms();
156             if (comms != null) {
157                 ModbusRegisterArray regArray = new ModbusRegisterArray(writeValue);
158                 ModbusWriteRegisterRequestBlueprint writeBluePrint = new ModbusWriteRegisterRequestBlueprint(
159                         localBridgeHandler.getSlaveId(), WALLBOX_REG_START + wallboxId, regArray, false, 3);
160                 comms.submitOneTimeWrite(writeBluePrint, result -> {
161                     if (dataWrite != ReadWriteSuccess.SUCCESS) {
162                         dataWrite = ReadWriteSuccess.SUCCESS;
163                         updateStatus();
164                     }
165                     logger.debug("E3DC Modbus write response! {}", result.getResponse().toString());
166                 }, failure -> {
167                     if (dataWrite != ReadWriteSuccess.FAILED) {
168                         dataWrite = ReadWriteSuccess.FAILED;
169                         updateStatus();
170                     }
171                     logger.warn("E3DC Modbus write error! {}", failure.getRequest().toString());
172                 });
173             }
174         }
175     }
176
177     private OptionalInt getWallboxId(@Nullable E3DCWallboxConfiguration c) {
178         if (c != null) {
179             return OptionalInt.of(c.wallboxId);
180         } else {
181             return OptionalInt.empty();
182         }
183     }
184
185     public void handle(AsyncModbusReadResult result) {
186         if (dataRead != ReadWriteSuccess.SUCCESS) {
187             dataRead = ReadWriteSuccess.SUCCESS;
188             updateStatus();
189         }
190         dataParser.handle(result);
191         Optional<Data> wbArrayOpt = dataParser.parse(DataType.WALLBOX);
192         if (wbArrayOpt.isPresent()) {
193             WallboxArray wbArray = (WallboxArray) wbArrayOpt.get();
194             OptionalInt wallboxId = getWallboxId(config);
195             if (wallboxId.isPresent()) {
196                 Optional<WallboxBlock> blockOpt = wbArray.getWallboxBlock(wallboxId.getAsInt());
197                 if (blockOpt.isPresent()) {
198                     WallboxBlock block = blockOpt.get();
199                     synchronized (this) {
200                         currentBitSet = block.getBitSet();
201                     }
202                     updateState(wbAvailableChannel, block.wbAvailable);
203                     updateState(wbSunmodeChannel, block.wbSunmode);
204                     updateState(wbChargingAbortedChannel, block.wbChargingAborted);
205                     updateState(wbChargingChannel, block.wbCharging);
206                     updateState(wbJackLockedChannel, block.wbJackLocked);
207                     updateState(wbJackPluggedChannel, block.wbJackPlugged);
208                     updateState(wbSchukoOnChannel, block.wbSchukoOn);
209                     updateState(wbSchukoPluggedChannel, block.wbSchukoPlugged);
210                     updateState(wbSchukoLockedChannel, block.wbSchukoLocked);
211                     updateState(wbSchukoRelay16Channel, block.wbSchukoRelay16);
212                     updateState(wbRelay16Channel, block.wbRelay16);
213                     updateState(wbRelay32Channel, block.wbRelay32);
214                     updateState(wb1phaseChannel, block.wb1phase);
215                 } else {
216                     logger.debug("Unable to get ID {} from WallboxArray", wallboxId);
217                 }
218             } else {
219                 logger.debug("Wallbox ID {} not valid", wallboxId);
220             }
221         } else {
222             logger.debug("Unable to get {} from Bridge", DataType.WALLBOX);
223         }
224     }
225
226     public void handleError(AsyncModbusFailure<ModbusReadRequestBlueprint> result) {
227         if (dataRead != ReadWriteSuccess.FAILED) {
228             dataRead = ReadWriteSuccess.FAILED;
229             updateStatus();
230         }
231     }
232
233     private void updateStatus() {
234         if (dataWrite == ReadWriteSuccess.NOT_RECEIVED) {
235             // read success / write not happened yet => go online / offline
236             if (dataRead == ReadWriteSuccess.SUCCESS) {
237                 updateStatus(ThingStatus.ONLINE);
238             } else {
239                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_ERROR);
240             }
241         } else {
242             if (dataRead == dataWrite) {
243                 // read and write same status - either go online or offline
244                 if (dataRead == ReadWriteSuccess.SUCCESS) {
245                     updateStatus(ThingStatus.ONLINE);
246                 } else {
247                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_WRITE_ERROR);
248                 }
249             } else {
250                 // either read or write failed - go offline with detailed status
251                 if (dataRead == ReadWriteSuccess.SUCCESS) {
252                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, WRITE_ERROR);
253                 } else {
254                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, READ_ERROR);
255                 }
256             }
257         }
258     }
259 }