]> git.basschouten.com Git - openhab-addons.git/blob
992905118c73e209814edccfb17ab08afff07f1e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.omnilink.internal.handler;
14
15 import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
16
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
24 import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.PercentType;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingStatus;
31 import org.openhab.core.thing.ThingStatusDetail;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.digitaldan.jomnilinkII.Message;
38 import com.digitaldan.jomnilinkII.MessageTypes.CommandMessage;
39 import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
40 import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
41 import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties;
42 import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
43 import com.digitaldan.jomnilinkII.MessageTypes.systemevents.SwitchPressEvent;
44 import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
45 import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
46
47 /**
48  * The {@link AbstractOmnilinkHandler} defines some methods that can be used across
49  * the many different Units exposed by the OmniLink protocol
50  *
51  * @author Craig Hamilton - Initial contribution
52  * @author Ethan Dye - openHAB3 rewrite
53  */
54 @NonNullByDefault
55 public class UnitHandler extends AbstractOmnilinkStatusHandler<ExtendedUnitStatus> {
56     private final Logger logger = LoggerFactory.getLogger(UnitHandler.class);
57     private final int thingID = getThingNumber();
58     public @Nullable String number;
59
60     public UnitHandler(Thing thing) {
61         super(thing);
62     }
63
64     @Override
65     public void initialize() {
66         super.initialize();
67         final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
68         if (bridgeHandler != null) {
69             updateUnitProperties(bridgeHandler);
70         } else {
71             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
72                     "Received null bridge while initializing Unit!");
73         }
74     }
75
76     private void updateUnitProperties(OmnilinkBridgeHandler bridgeHandler) {
77         final List<AreaProperties> areas = getAreaProperties();
78         if (areas != null) {
79             for (AreaProperties areaProperties : areas) {
80                 int areaFilter = bitFilterForArea(areaProperties);
81
82                 ObjectPropertyRequest<UnitProperties> objectPropertyRequest = ObjectPropertyRequest
83                         .builder(bridgeHandler, ObjectPropertyRequests.UNIT, thingID, 0).selectNamed()
84                         .areaFilter(areaFilter).selectAnyLoad().build();
85
86                 for (UnitProperties unitProperties : objectPropertyRequest) {
87                     Map<String, String> properties = editProperties();
88                     properties.put(THING_PROPERTIES_NAME, unitProperties.getName());
89                     properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
90                     updateProperties(properties);
91                 }
92             }
93         }
94     }
95
96     @Override
97     public void handleCommand(ChannelUID channelUID, Command command) {
98         logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
99
100         if (command instanceof RefreshType) {
101             retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
102                     ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null status update!"));
103             return;
104         }
105
106         switch (channelUID.getId()) {
107             case CHANNEL_UNIT_LEVEL:
108             case CHANNEL_UNIT_SWITCH:
109                 if (command instanceof OnOffType) {
110                     handleOnOff(channelUID, (OnOffType) command);
111                 } else {
112                     logger.debug("Invalid command: {}, must be OnOffType", command);
113                 }
114                 break;
115             case CHANNEL_UNIT_ON_FOR_SECONDS:
116             case CHANNEL_UNIT_OFF_FOR_SECONDS:
117             case CHANNEL_UNIT_ON_FOR_MINUTES:
118             case CHANNEL_UNIT_OFF_FOR_MINUTES:
119             case CHANNEL_UNIT_ON_FOR_HOURS:
120             case CHANNEL_UNIT_OFF_FOR_HOURS:
121                 if (command instanceof DecimalType) {
122                     handleUnitDuration(channelUID, (DecimalType) command);
123                 } else {
124                     logger.debug("Invalid command: {}, must be DecimalType", command);
125                 }
126                 break;
127             default:
128                 logger.warn("Unknown channel for Unit thing: {}", channelUID);
129         }
130     }
131
132     private void handleUnitDuration(ChannelUID channelUID, DecimalType command) {
133         logger.debug("handleUnitDuration called for channel: {}, command: {}", channelUID, command);
134         final String channelID = channelUID.getId();
135
136         int duration;
137         if (channelID.endsWith("seconds")) {
138             duration = command.intValue();
139         } else if (channelID.endsWith("minutes")) {
140             duration = command.intValue() + 100;
141         } else if (channelID.endsWith("hours")) {
142             duration = command.intValue() + 200;
143         } else {
144             logger.warn("Unknown channel for Unit duration: {}", channelUID);
145             return;
146         }
147
148         sendOmnilinkCommand(channelID.startsWith("on") ? CommandMessage.CMD_UNIT_ON : CommandMessage.CMD_UNIT_OFF,
149                 duration, thingID);
150     }
151
152     protected void handleOnOff(ChannelUID channelUID, OnOffType command) {
153         logger.debug("handleOnOff called for channel: {}, command: {}", channelUID, command);
154         sendOmnilinkCommand(OnOffType.ON.equals(command) ? CommandMessage.CMD_UNIT_ON : CommandMessage.CMD_UNIT_OFF, 0,
155                 thingID);
156     }
157
158     @Override
159     public void updateChannels(ExtendedUnitStatus status) {
160         logger.debug("updateChannels called for Unit status: {}", status);
161         int unitStatus = status.getStatus();
162         int level = 0;
163
164         if (unitStatus == Status.UNIT_OFF) {
165             level = 0;
166         } else if (unitStatus == Status.UNIT_ON) {
167             level = 100;
168         } else if ((unitStatus >= Status.UNIT_SCENE_A) && (unitStatus <= Status.UNIT_SCENE_L)) {
169             level = 100;
170         } else if ((unitStatus >= Status.UNIT_LEVEL_0) && (unitStatus <= Status.UNIT_LEVEL_100)) {
171             level = unitStatus - Status.UNIT_LEVEL_0;
172         }
173
174         updateState(CHANNEL_UNIT_LEVEL, PercentType.valueOf(Integer.toString(level)));
175         updateState(CHANNEL_UNIT_SWITCH, OnOffType.from(level != 0));
176     }
177
178     @Override
179     protected Optional<ExtendedUnitStatus> retrieveStatus() {
180         try {
181             final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
182             if (bridgeHandler != null) {
183                 ObjectStatus objectStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_UNIT, thingID, thingID,
184                         true);
185                 return Optional.of((ExtendedUnitStatus) objectStatus.getStatuses()[0]);
186             } else {
187                 logger.debug("Received null bridge while updating Unit status!");
188                 return Optional.empty();
189             }
190         } catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
191             logger.debug("Received exception while refreshing Unit status: {}", e.getMessage());
192             return Optional.empty();
193         }
194     }
195
196     private static class Status {
197         private static final int UNIT_OFF = 0;
198         private static final int UNIT_ON = 1;
199         private static final int UNIT_SCENE_A = 2;
200         private static final int UNIT_SCENE_L = 13;
201         private static final int UNIT_LEVEL_0 = 100;
202         private static final int UNIT_LEVEL_100 = 200;
203     }
204
205     /**
206      * Handle a switch press event by triggering the appropriate channel.
207      *
208      * @param switchPressEvent
209      */
210     public void handleSwitchPressEvent(SwitchPressEvent switchPressEvent) {
211         ChannelUID activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_SWITCH_PRESS_EVENT);
212         triggerChannel(activateChannel, Integer.toString(switchPressEvent.getSwitchValue()));
213     }
214 }