]> git.basschouten.com Git - openhab-addons.git/blob
dad89c31a51383f478ccf4c17b57773123940e36
[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.deconz.internal.handler;
14
15 import static org.openhab.binding.deconz.internal.BindingConstants.*;
16
17 import java.util.Set;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.deconz.internal.Util;
22 import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage;
23 import org.openhab.binding.deconz.internal.dto.GroupAction;
24 import org.openhab.binding.deconz.internal.dto.GroupMessage;
25 import org.openhab.binding.deconz.internal.dto.GroupState;
26 import org.openhab.binding.deconz.internal.netutils.AsyncHttpClient;
27 import org.openhab.binding.deconz.internal.types.ResourceType;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.library.types.HSBType;
30 import org.openhab.core.library.types.OnOffType;
31 import org.openhab.core.library.types.PercentType;
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.ThingTypeUID;
36 import org.openhab.core.types.Command;
37 import org.openhab.core.types.RefreshType;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import com.google.gson.Gson;
42
43 /**
44  * This light thing doesn't establish any connections, that is done by the bridge Thing.
45  *
46  * It waits for the bridge to come online, grab the websocket connection and bridge configuration
47  * and registers to the websocket connection as a listener.
48  *
49  * A REST API call is made to get the initial light/rollershutter state.
50  *
51  * Every light and rollershutter is supported by this Thing, because a unified state is kept
52  * in {@link #groupStateCache}. Every field that got received by the REST API for this specific
53  * sensor is published to the framework.
54  *
55  * @author Jan N. Klug - Initial contribution
56  */
57 @NonNullByDefault
58 public class GroupThingHandler extends DeconzBaseThingHandler<GroupMessage> {
59     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(THING_TYPE_LIGHTGROUP);
60     private final Logger logger = LoggerFactory.getLogger(GroupThingHandler.class);
61
62     /**
63      * The group state.
64      */
65     private GroupState groupStateCache = new GroupState();
66
67     public GroupThingHandler(Thing thing, Gson gson) {
68         super(thing, gson, ResourceType.GROUPS);
69     }
70
71     @Override
72     public void handleCommand(ChannelUID channelUID, Command command) {
73         String channelId = channelUID.getId();
74
75         GroupAction newGroupAction = new GroupAction();
76         switch (channelId) {
77             case CHANNEL_ALL_ON:
78             case CHANNEL_ANY_ON:
79                 if (command instanceof RefreshType) {
80                     valueUpdated(channelUID.getId(), groupStateCache);
81                     return;
82                 }
83                 break;
84             case CHANNEL_ALERT:
85                 if (command instanceof OnOffType) {
86                     newGroupAction.alert = command == OnOffType.ON ? "alert" : "none";
87                 } else {
88                     return;
89                 }
90                 break;
91             case CHANNEL_COLOR:
92                 if (command instanceof HSBType) {
93                     HSBType hsbCommand = (HSBType) command;
94                     Integer bri = Util.fromPercentType(hsbCommand.getBrightness());
95                     newGroupAction.bri = bri;
96                     if (bri > 0) {
97                         newGroupAction.hue = (int) (hsbCommand.getHue().doubleValue() * HUE_FACTOR);
98                         newGroupAction.sat = Util.fromPercentType(hsbCommand.getSaturation());
99                     }
100                 } else if (command instanceof PercentType) {
101                     newGroupAction.bri = Util.fromPercentType((PercentType) command);
102                 } else if (command instanceof DecimalType) {
103                     newGroupAction.bri = ((DecimalType) command).intValue();
104                 } else if (command instanceof OnOffType) {
105                     newGroupAction.on = OnOffType.ON.equals(command);
106                 } else {
107                     return;
108                 }
109                 break;
110             case CHANNEL_COLOR_TEMPERATURE:
111                 if (command instanceof DecimalType) {
112                     int miredValue = Util.kelvinToMired(((DecimalType) command).intValue());
113                     newGroupAction.ct = Util.constrainToRange(miredValue, ZCL_CT_MIN, ZCL_CT_MAX);
114                 } else {
115                     return;
116                 }
117                 break;
118             default:
119                 return;
120         }
121
122         Integer bri = newGroupAction.bri;
123         if (bri != null && bri > 0) {
124             newGroupAction.on = true;
125         }
126
127         sendCommand(newGroupAction, command, channelUID, null);
128     }
129
130     @Override
131     protected @Nullable GroupMessage parseStateResponse(AsyncHttpClient.Result r) {
132         if (r.getResponseCode() == 403) {
133             return null;
134         } else if (r.getResponseCode() == 200) {
135             return gson.fromJson(r.getBody(), GroupMessage.class);
136         } else {
137             throw new IllegalStateException("Unknown status code " + r.getResponseCode() + " for full state request");
138         }
139     }
140
141     @Override
142     protected void processStateResponse(@Nullable GroupMessage stateResponse) {
143         if (stateResponse == null) {
144             return;
145         }
146         messageReceived(config.id, stateResponse);
147     }
148
149     private void valueUpdated(String channelId, GroupState newState) {
150         switch (channelId) {
151             case CHANNEL_ALL_ON:
152                 updateState(channelId, OnOffType.from(newState.all_on));
153                 break;
154             case CHANNEL_ANY_ON:
155                 updateState(channelId, OnOffType.from(newState.any_on));
156                 break;
157             default:
158         }
159     }
160
161     @Override
162     public void messageReceived(String sensorID, DeconzBaseMessage message) {
163         if (message instanceof GroupMessage) {
164             GroupMessage groupMessage = (GroupMessage) message;
165             logger.trace("{} received {}", thing.getUID(), groupMessage);
166             GroupState groupState = groupMessage.state;
167             if (groupState != null) {
168                 updateStatus(ThingStatus.ONLINE);
169                 thing.getChannels().stream().map(c -> c.getUID().getId()).forEach(c -> valueUpdated(c, groupState));
170                 groupStateCache = groupState;
171             }
172         }
173     }
174 }