]> git.basschouten.com Git - openhab-addons.git/blob
cd0e9af631b63dd846ab6f664b32a5ba3049db52
[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.velbus.internal.handler;
14
15 import static org.openhab.binding.velbus.internal.VelbusBindingConstants.SUB_ADDRESS;
16
17 import java.lang.invoke.MethodHandles;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.velbus.internal.VelbusModuleAddress;
25 import org.openhab.binding.velbus.internal.VelbusPacketListener;
26 import org.openhab.binding.velbus.internal.config.VelbusThingConfig;
27 import org.openhab.binding.velbus.internal.packets.VelbusReadMemoryBlockPacket;
28 import org.openhab.binding.velbus.internal.packets.VelbusReadMemoryPacket;
29 import org.openhab.binding.velbus.internal.packets.VelbusStatusRequestPacket;
30 import org.openhab.binding.velbus.internal.packets.VelbusWriteMemoryPacket;
31 import org.openhab.core.config.core.Configuration;
32 import org.openhab.core.thing.Bridge;
33 import org.openhab.core.thing.Channel;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.thing.binding.ThingHandler;
40 import org.openhab.core.thing.binding.builder.ChannelBuilder;
41 import org.openhab.core.thing.binding.builder.ThingBuilder;
42 import org.openhab.core.thing.type.ChannelKind;
43 import org.openhab.core.thing.type.ChannelTypeUID;
44 import org.openhab.core.util.HexUtils;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 /**
49  * Base ThingHandler for all Velbus handlers.
50  *
51  * @author Cedric Boon - Initial contribution
52  */
53 @NonNullByDefault
54 public abstract class VelbusThingHandler extends BaseThingHandler implements VelbusPacketListener {
55     protected final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
56
57     protected @Nullable VelbusThingConfig velbusThingConfig;
58     private @Nullable VelbusBridgeHandler velbusBridgeHandler;
59     private @NonNullByDefault({}) VelbusModuleAddress velbusModuleAddress;
60
61     private int numberOfSubAddresses;
62
63     public VelbusThingHandler(Thing thing, int numberOfSubAddresses) {
64         super(thing);
65
66         this.numberOfSubAddresses = numberOfSubAddresses;
67     }
68
69     @Override
70     public void initialize() {
71         logger.debug("Initializing velbus handler.");
72
73         this.velbusThingConfig = getConfigAs(VelbusThingConfig.class);
74
75         Bridge bridge = getBridge();
76         initializeThing(bridge == null ? ThingStatus.OFFLINE : bridge.getStatus());
77         initializeChannelNames();
78         initializeChannelStates();
79     }
80
81     @Override
82     public void handleRemoval() {
83         VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
84
85         if (velbusBridgeHandler != null && velbusModuleAddress != null) {
86             byte[] activeAddresses = velbusModuleAddress.getActiveAddresses();
87
88             for (int i = 0; i < activeAddresses.length; i++) {
89                 velbusBridgeHandler.unregisterRelayStatusListener(activeAddresses[i]);
90             }
91         }
92
93         super.handleRemoval();
94     }
95
96     protected VelbusModuleAddress getModuleAddress() {
97         return velbusModuleAddress;
98     }
99
100     protected void updateChannelLabel(ChannelUID channelUID, String channelName) {
101         Channel existingChannel = thing.getChannel(channelUID.getId());
102         if (existingChannel != null) {
103             String acceptedItem = existingChannel.getAcceptedItemType();
104             Configuration configuration = existingChannel.getConfiguration();
105             Set<String> defaultTags = existingChannel.getDefaultTags();
106             String description = existingChannel.getDescription();
107             ChannelKind kind = existingChannel.getKind();
108             Map<String, String> properties = existingChannel.getProperties();
109             ChannelTypeUID type = existingChannel.getChannelTypeUID();
110
111             ThingBuilder thingBuilder = editThing();
112             Channel channel = ChannelBuilder.create(channelUID, acceptedItem).withConfiguration(configuration)
113                     .withDefaultTags(defaultTags).withDescription(description != null ? description : "").withKind(kind)
114                     .withLabel(channelName).withProperties(properties).withType(type).build();
115             thingBuilder.withoutChannel(channelUID).withChannel(channel);
116             updateThing(thingBuilder.build());
117         }
118     }
119
120     private void initializeThing(ThingStatus bridgeStatus) {
121         this.velbusModuleAddress = createVelbusModuleAddress(numberOfSubAddresses);
122
123         if (this.velbusModuleAddress != null) {
124             logger.debug("initializeThing thing {} with address {} bridge status {}", getThing().getUID(),
125                     velbusModuleAddress.getAddress(), bridgeStatus);
126
127             // note: this call implicitly registers our handler as a listener on
128             // the bridge
129             if (getVelbusBridgeHandler() != null) {
130                 if (bridgeStatus == ThingStatus.ONLINE) {
131                     updateStatus(ThingStatus.ONLINE);
132                 } else {
133                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
134                 }
135             } else {
136                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
137             }
138         } else {
139             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Address is not known!");
140         }
141     }
142
143     protected @Nullable VelbusModuleAddress createVelbusModuleAddress(int numberOfSubAddresses) {
144         final VelbusThingConfig velbusThingConfig = this.velbusThingConfig;
145         if (velbusThingConfig != null) {
146             byte address = hexToByte(velbusThingConfig.address);
147
148             byte[] subAddresses = new byte[numberOfSubAddresses];
149             for (int i = 0; i < numberOfSubAddresses; i++) {
150                 String propertyKey = SUB_ADDRESS + (i + 1);
151                 String subAddress = getThing().getProperties().get(propertyKey);
152                 if (subAddress != null) {
153                     subAddresses[i] = hexToByte(subAddress);
154                 } else {
155                     subAddresses[i] = (byte) 0xFF;
156                 }
157             }
158
159             return new VelbusModuleAddress(address, subAddresses);
160         }
161
162         return null;
163     }
164
165     private void initializeChannelNames() {
166         List<Channel> channels = this.getThing().getChannels();
167         for (int i = 0; i < channels.size(); i++) {
168             Channel channel = channels.get(i);
169             String channelUID = channel.getUID().getIdWithoutGroup();
170
171             if (getConfig().containsKey(channelUID)) {
172                 String channelName = getConfig().get(channelUID).toString();
173                 if (!channelName.equals(channel.getLabel())) {
174                     updateChannelLabel(channel.getUID(), channelName);
175                 }
176             }
177         }
178     }
179
180     private void initializeChannelStates() {
181         VelbusBridgeHandler velbusBridgeHandler = this.velbusBridgeHandler;
182         if (velbusBridgeHandler != null) {
183             VelbusStatusRequestPacket packet = new VelbusStatusRequestPacket(getModuleAddress().getAddress());
184             byte[] packetBytes = packet.getBytes();
185
186             velbusBridgeHandler.sendPacket(packetBytes);
187         }
188     }
189
190     protected byte hexToByte(String hexString) {
191         if (hexString.length() > 2) {
192             throw new IllegalArgumentException("hexString contains more than one byte: " + hexString);
193         }
194
195         return HexUtils.hexToBytes(hexString)[0];
196     }
197
198     protected void sendReadMemoryBlockPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress) {
199         VelbusReadMemoryBlockPacket packet = new VelbusReadMemoryBlockPacket(getModuleAddress().getAddress(),
200                 memoryAddress);
201         byte[] packetBytes = packet.getBytes();
202         velbusBridgeHandler.sendPacket(packetBytes);
203     }
204
205     protected void sendReadMemoryPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress) {
206         VelbusReadMemoryPacket packet = new VelbusReadMemoryPacket(getModuleAddress().getAddress(), memoryAddress);
207         byte[] packetBytes = packet.getBytes();
208         velbusBridgeHandler.sendPacket(packetBytes);
209     }
210
211     protected void sendWriteMemoryPacket(VelbusBridgeHandler velbusBridgeHandler, int memoryAddress, byte data) {
212         VelbusWriteMemoryPacket packet = new VelbusWriteMemoryPacket(getModuleAddress().getAddress(), memoryAddress,
213                 data);
214         byte[] packetBytes = packet.getBytes();
215         velbusBridgeHandler.sendPacket(packetBytes);
216     }
217
218     protected @Nullable synchronized VelbusBridgeHandler getVelbusBridgeHandler() {
219         if (this.velbusBridgeHandler == null) {
220             Bridge bridge = getBridge();
221             if (bridge == null) {
222                 return null;
223             }
224             ThingHandler bridgeHandler = bridge.getHandler();
225             if (bridgeHandler instanceof VelbusBridgeHandler) {
226                 VelbusBridgeHandler velbusBridgeHandler = (VelbusBridgeHandler) bridgeHandler;
227                 this.velbusBridgeHandler = velbusBridgeHandler;
228
229                 if (velbusModuleAddress != null) {
230                     byte[] activeAddresses = velbusModuleAddress.getActiveAddresses();
231
232                     for (int i = 0; i < activeAddresses.length; i++) {
233                         velbusBridgeHandler.registerPacketListener(activeAddresses[i], this);
234                     }
235                 }
236             }
237         }
238
239         return this.velbusBridgeHandler;
240     }
241 }