]> git.basschouten.com Git - openhab-addons.git/blob
95951b748c7691d34f5daee7f80babede6eaf052
[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.ObjectStatus;
39 import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
40 import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties;
41 import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
42 import com.digitaldan.jomnilinkII.MessageTypes.systemevents.SwitchPressEvent;
43 import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
44 import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
45
46 /**
47  * The {@link AbstractOmnilinkHandler} defines some methods that can be used across
48  * the many different Units exposed by the OmniLink protocol
49  *
50  * @author Craig Hamilton - Initial contribution
51  * @author Ethan Dye - openHAB3 rewrite
52  */
53 @NonNullByDefault
54 public class UnitHandler extends AbstractOmnilinkStatusHandler<ExtendedUnitStatus> {
55     private final Logger logger = LoggerFactory.getLogger(UnitHandler.class);
56     private final int thingID = getThingNumber();
57     public @Nullable String number;
58
59     public UnitHandler(Thing thing) {
60         super(thing);
61     }
62
63     @Override
64     public void initialize() {
65         super.initialize();
66         final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
67         if (bridgeHandler != null) {
68             updateUnitProperties(bridgeHandler);
69         } else {
70             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
71                     "Received null bridge while initializing Unit!");
72         }
73     }
74
75     private void updateUnitProperties(OmnilinkBridgeHandler bridgeHandler) {
76         final List<AreaProperties> areas = getAreaProperties();
77         if (areas != null) {
78             for (AreaProperties areaProperties : areas) {
79                 int areaFilter = bitFilterForArea(areaProperties);
80
81                 ObjectPropertyRequest<UnitProperties> objectPropertyRequest = ObjectPropertyRequest
82                         .builder(bridgeHandler, ObjectPropertyRequests.UNIT, thingID, 0).selectNamed()
83                         .areaFilter(areaFilter).selectAnyLoad().build();
84
85                 for (UnitProperties unitProperties : objectPropertyRequest) {
86                     Map<String, String> properties = editProperties();
87                     properties.put(THING_PROPERTIES_NAME, unitProperties.getName());
88                     properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
89                     updateProperties(properties);
90                 }
91             }
92         }
93     }
94
95     @Override
96     public void handleCommand(ChannelUID channelUID, Command command) {
97         logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
98
99         if (command instanceof RefreshType) {
100             retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
101                     ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null status update!"));
102             return;
103         }
104
105         switch (channelUID.getId()) {
106             case CHANNEL_UNIT_LEVEL:
107             case CHANNEL_UNIT_SWITCH:
108                 if (command instanceof OnOffType) {
109                     handleOnOff(channelUID, (OnOffType) command);
110                 } else {
111                     logger.debug("Invalid command: {}, must be OnOffType", command);
112                 }
113                 break;
114             case CHANNEL_UNIT_ON_FOR_SECONDS:
115             case CHANNEL_UNIT_OFF_FOR_SECONDS:
116             case CHANNEL_UNIT_ON_FOR_MINUTES:
117             case CHANNEL_UNIT_OFF_FOR_MINUTES:
118             case CHANNEL_UNIT_ON_FOR_HOURS:
119             case CHANNEL_UNIT_OFF_FOR_HOURS:
120                 if (command instanceof DecimalType) {
121                     handleUnitDuration(channelUID, (DecimalType) command);
122                 } else {
123                     logger.debug("Invalid command: {}, must be DecimalType", command);
124                 }
125                 break;
126             default:
127                 logger.warn("Unknown channel for Unit thing: {}", channelUID);
128         }
129     }
130
131     private void handleUnitDuration(ChannelUID channelUID, DecimalType command) {
132         logger.debug("handleUnitDuration called for channel: {}, command: {}", channelUID, command);
133         final String channelID = channelUID.getId();
134
135         int duration;
136         if (channelID.endsWith("seconds")) {
137             duration = command.intValue();
138         } else if (channelID.endsWith("minutes")) {
139             duration = command.intValue() + 100;
140         } else if (channelID.endsWith("hours")) {
141             duration = command.intValue() + 200;
142         } else {
143             logger.warn("Unknown channel for Unit duration: {}", channelUID);
144             return;
145         }
146
147         sendOmnilinkCommand(
148                 channelID.startsWith("on") ? OmniLinkCmd.CMD_UNIT_ON.getNumber() : OmniLinkCmd.CMD_UNIT_OFF.getNumber(),
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) ? OmniLinkCmd.CMD_UNIT_ON.getNumber()
155                 : OmniLinkCmd.CMD_UNIT_OFF.getNumber(), 0, 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 }