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