]> git.basschouten.com Git - openhab-addons.git/blob
03fb862059e101df173ca4eac1f651c55833b1b5
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.rfxcom.internal.handler;
14
15 import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
16
17 import java.util.Map;
18 import java.util.concurrent.ConcurrentHashMap;
19
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.openhab.binding.rfxcom.internal.DeviceMessageListener;
22 import org.openhab.binding.rfxcom.internal.config.RFXComDeviceConfiguration;
23 import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
24 import org.openhab.binding.rfxcom.internal.exceptions.RFXComMessageNotImplementedException;
25 import org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType;
26 import org.openhab.binding.rfxcom.internal.messages.RFXComDeviceMessage;
27 import org.openhab.binding.rfxcom.internal.messages.RFXComMessage;
28 import org.openhab.binding.rfxcom.internal.messages.RFXComMessageFactory;
29 import org.openhab.core.library.types.DecimalType;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.thing.Channel;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingStatusInfo;
37 import org.openhab.core.thing.ThingUID;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.thing.binding.ThingHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.openhab.core.types.State;
43 import org.openhab.core.types.Type;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link RFXComHandler} is responsible for handling commands, which are
49  * sent to one of the channels.
50  *
51  * @author Pauli Anttila - Initial contribution
52  */
53 public class RFXComHandler extends BaseThingHandler implements DeviceMessageListener, DeviceState {
54     private static final int LOW_BATTERY_LEVEL = 1;
55
56     private final Logger logger = LoggerFactory.getLogger(RFXComHandler.class);
57
58     private final Map<String, Type> stateMap = new ConcurrentHashMap<>();
59
60     private RFXComBridgeHandler bridgeHandler;
61     private RFXComDeviceConfiguration config;
62
63     public RFXComHandler(@NonNull Thing thing) {
64         super(thing);
65     }
66
67     @Override
68     public void handleCommand(ChannelUID channelUID, Command command) {
69         logger.debug("Received channel: {}, command: {}", channelUID, command);
70
71         if (bridgeHandler != null) {
72             if (command instanceof RefreshType) {
73                 logger.trace("Received unsupported Refresh command");
74             } else {
75                 try {
76                     PacketType packetType = RFXComMessageFactory
77                             .convertPacketType(getThing().getThingTypeUID().getId().toUpperCase());
78
79                     RFXComMessage msg = RFXComMessageFactory.createMessage(packetType);
80
81                     msg.setConfig(config);
82                     msg.convertFromState(channelUID.getId(), command);
83
84                     bridgeHandler.sendMessage(msg);
85                 } catch (RFXComMessageNotImplementedException e) {
86                     logger.error("Message not supported", e);
87                 } catch (RFXComException e) {
88                     logger.error("Transmitting error", e);
89                 }
90             }
91         }
92     }
93
94     @Override
95     public void initialize() {
96         logger.debug("Initializing thing {}", getThing().getUID());
97         initializeBridge((getBridge() == null) ? null : getBridge().getHandler(),
98                 (getBridge() == null) ? null : getBridge().getStatus());
99
100         stateMap.clear();
101     }
102
103     @Override
104     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
105         logger.debug("bridgeStatusChanged {} for thing {}", bridgeStatusInfo, getThing().getUID());
106         initializeBridge((getBridge() == null) ? null : getBridge().getHandler(), bridgeStatusInfo.getStatus());
107     }
108
109     private void initializeBridge(ThingHandler thingHandler, ThingStatus bridgeStatus) {
110         logger.debug("initializeBridge {} for thing {}", bridgeStatus, getThing().getUID());
111
112         config = getConfigAs(RFXComDeviceConfiguration.class);
113         if (config.deviceId == null || config.subType == null) {
114             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
115                     "RFXCOM device missing deviceId or subType");
116         } else if (thingHandler != null && bridgeStatus != null) {
117             bridgeHandler = (RFXComBridgeHandler) thingHandler;
118             bridgeHandler.registerDeviceStatusListener(this);
119
120             if (bridgeStatus == ThingStatus.ONLINE) {
121                 updateStatus(ThingStatus.ONLINE);
122             } else {
123                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
124             }
125         } else {
126             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
127         }
128     }
129
130     @Override
131     public void dispose() {
132         logger.debug("Thing {} disposed.", getThing().getUID());
133         if (bridgeHandler != null) {
134             bridgeHandler.unregisterDeviceStatusListener(this);
135         }
136         bridgeHandler = null;
137         super.dispose();
138     }
139
140     @Override
141     public void onDeviceMessageReceived(ThingUID bridge, RFXComDeviceMessage message) {
142         try {
143             String id = message.getDeviceId();
144             if (config.deviceId.equals(id)) {
145                 String receivedId = PACKET_TYPE_THING_TYPE_UID_MAP.get(message.getPacketType()).getId();
146                 logger.debug("Received message from bridge: {} message: {}", bridge, message);
147
148                 if (receivedId.equals(getThing().getThingTypeUID().getId())) {
149                     updateStatus(ThingStatus.ONLINE);
150
151                     for (Channel channel : getThing().getChannels()) {
152                         ChannelUID uid = channel.getUID();
153                         String channelId = uid.getId();
154
155                         try {
156                             switch (channelId) {
157                                 case CHANNEL_COMMAND:
158                                 case CHANNEL_CHIME_SOUND:
159                                 case CHANNEL_MOOD:
160                                     postNullableCommand(uid, message.convertToCommand(channelId, this));
161                                     break;
162
163                                 case CHANNEL_LOW_BATTERY:
164                                     updateNullableState(uid,
165                                             isLowBattery(message.convertToState(CHANNEL_BATTERY_LEVEL, this)));
166                                     break;
167
168                                 default:
169                                     updateNullableState(uid, message.convertToState(channelId, this));
170                                     break;
171                             }
172                         } catch (RFXComException e) {
173                             logger.trace("{} does not handle {}", channelId, message);
174                         }
175                     }
176                 }
177             }
178         } catch (Exception e) {
179             logger.error("Error occurred during message receiving", e);
180         }
181     }
182
183     private void updateNullableState(ChannelUID uid, State state) {
184         if (state == null) {
185             return;
186         }
187
188         stateMap.put(uid.getId(), state);
189         updateState(uid, state);
190     }
191
192     private void postNullableCommand(ChannelUID uid, Command command) {
193         if (command == null) {
194             return;
195         }
196
197         stateMap.put(uid.getId(), command);
198         postCommand(uid, command);
199     }
200
201     @Override
202     public Type getLastState(String channelId) {
203         return stateMap.get(channelId);
204     }
205
206     /**
207      * Check if battery level is below low battery threshold level.
208      *
209      * @param batteryLevel Internal battery level
210      * @return OnOffType
211      */
212     private State isLowBattery(State batteryLevel) {
213         int level = ((DecimalType) batteryLevel).intValue();
214         if (level <= LOW_BATTERY_LEVEL) {
215             return OnOffType.ON;
216         } else {
217             return OnOffType.OFF;
218         }
219     }
220 }