]> git.basschouten.com Git - openhab-addons.git/blob
18879df878d32e4a917c1d788f1104b94e2cdf59
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.loxone.internal.controls;
14
15 import static org.openhab.binding.loxone.internal.LxBindingConstants.*;
16
17 import java.io.IOException;
18 import java.math.BigDecimal;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import org.openhab.binding.loxone.internal.types.LxState;
23 import org.openhab.binding.loxone.internal.types.LxTags;
24 import org.openhab.binding.loxone.internal.types.LxUuid;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.UpDownType;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.type.ChannelTypeUID;
30 import org.openhab.core.types.Command;
31 import org.openhab.core.types.StateDescriptionFragmentBuilder;
32 import org.openhab.core.types.StateOption;
33
34 /**
35  * A Light Controller type of control on Loxone Miniserver.
36  * <p>
37  * According to Loxone API documentation, a light controller is one of following functional blocks:
38  * <ul>
39  * <li>Lighting Controller
40  * <li>Hotel Lighting Controller
41  * </ul>
42  *
43  * @author Pawel Pieczul - initial contribution
44  *
45  */
46 class LxControlLightController extends LxControl {
47
48     static class Factory extends LxControlInstance {
49         @Override
50         LxControl create(LxUuid uuid) {
51             return new LxControlLightController(uuid);
52         }
53
54         @Override
55         String getType() {
56             return "lightcontroller";
57         }
58     }
59
60     /**
61      * Number of scenes supported by the Miniserver. Indexing starts with 0 to NUM_OF_SCENES-1.
62      */
63     private static final int NUM_OF_SCENES = 10;
64
65     /**
66      * Current active scene number (0-9)
67      */
68     private static final String STATE_ACTIVE_SCENE = "activescene";
69     /**
70      * List of available scenes (public state, so user can monitor scene list updates)
71      */
72     private static final String STATE_SCENE_LIST = "scenelist";
73     /**
74      * Command string used to set control's state to ON
75      */
76     private static final String CMD_ON = "On";
77     /**
78      * Command string used to set control's state to OFF
79      */
80     private static final String CMD_OFF = "Off";
81     /**
82      * Command string used to go to the next scene
83      */
84     private static final String CMD_NEXT_SCENE = "plus";
85     /**
86      * Command string used to go to the previous scene
87      */
88     private static final String CMD_PREVIOUS_SCENE = "minus";
89     private static final int SCENE_ALL_ON = 9;
90
91     private List<StateOption> sceneNames = new ArrayList<>();
92     private ChannelUID channelId;
93
94     private LxControlLightController(LxUuid uuid) {
95         super(uuid);
96     }
97
98     @Override
99     public void initialize(LxControlConfig config) {
100         super.initialize(config);
101         tags.addAll(LxTags.SCENE);
102         // add only channel, state description will be added later when a control state update message is received
103         channelId = addChannel("Number", new ChannelTypeUID(BINDING_ID, MINISERVER_CHANNEL_TYPE_LIGHT_CTRL),
104                 defaultChannelLabel, "Light controller", tags, this::handleCommands, this::getChannelState);
105     }
106
107     private void handleCommands(Command command) throws IOException {
108         if (command instanceof OnOffType onOffCommand) {
109             if (onOffCommand == OnOffType.ON) {
110                 sendAction(CMD_ON);
111             } else {
112                 sendAction(CMD_OFF);
113             }
114         } else if (command instanceof UpDownType upDownCommand) {
115             if (upDownCommand == UpDownType.UP) {
116                 sendAction(CMD_NEXT_SCENE);
117             } else {
118                 sendAction(CMD_PREVIOUS_SCENE);
119             }
120         } else if (command instanceof DecimalType decimalCommand) {
121             int scene = decimalCommand.intValue();
122             if (scene == SCENE_ALL_ON) {
123                 sendAction(CMD_ON);
124             } else if (scene >= 0 && scene < NUM_OF_SCENES) {
125                 sendAction(Long.toString(scene));
126             }
127         }
128     }
129
130     private DecimalType getChannelState() {
131         Double value = getStateDoubleValue(STATE_ACTIVE_SCENE);
132         if (value != null && value >= 0 && value < NUM_OF_SCENES) {
133             return new DecimalType(value);
134         }
135         return null;
136     }
137
138     /**
139      * Get scene names from new state value received from the Miniserver
140      */
141     @Override
142     public void onStateChange(LxState state) {
143         if (STATE_SCENE_LIST.equals(state.getName()) && channelId != null) {
144             Object value = state.getStateValue();
145             if (value instanceof String str) {
146                 sceneNames.clear();
147                 String[] scenes = str.split(",");
148                 for (String line : scenes) {
149                     line = line.replace("\"", "");
150                     String[] params = line.split("=");
151                     if (params.length == 2) {
152                         sceneNames.add(new StateOption(params[0], params[1]));
153                     }
154                 }
155                 addChannelStateDescriptionFragment(channelId,
156                         StateDescriptionFragmentBuilder.create().withMinimum(BigDecimal.ZERO)
157                                 .withMaximum(new BigDecimal(NUM_OF_SCENES - 1)).withStep(BigDecimal.ONE)
158                                 .withReadOnly(false).withOptions(sceneNames).build());
159             }
160         } else {
161             super.onStateChange(state);
162         }
163     }
164 }