]> git.basschouten.com Git - openhab-addons.git/blob
8f5d502514bf0db795bd3a346805433b6cce52e9
[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.enocean.internal.eep.D2_01;
14
15 import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.*;
16
17 import java.util.function.Function;
18
19 import org.openhab.binding.enocean.internal.config.EnOceanChannelDimmerConfig;
20 import org.openhab.binding.enocean.internal.eep.Base._VLDMessage;
21 import org.openhab.binding.enocean.internal.eep.EEPHelper;
22 import org.openhab.binding.enocean.internal.messages.ERP1Message;
23 import org.openhab.core.config.core.Configuration;
24 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
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.library.types.QuantityType;
29 import org.openhab.core.library.unit.Units;
30 import org.openhab.core.types.Command;
31 import org.openhab.core.types.RefreshType;
32 import org.openhab.core.types.State;
33 import org.openhab.core.types.UnDefType;
34 import org.openhab.core.util.HexUtils;
35
36 /**
37  *
38  * @author Daniel Weber - Initial contribution
39  */
40 public abstract class D2_01 extends _VLDMessage {
41
42     protected final byte cmdMask = 0x0f;
43     protected final byte outputValueMask = 0x7f;
44     protected final byte outputChannelMask = 0x1f;
45
46     protected final byte CMD_ACTUATOR_SET_STATUS = 0x01;
47     protected final byte CMD_ACTUATOR_STATUS_QUERY = 0x03;
48     protected final byte CMD_ACTUATOR_STATUS_RESPONE = 0x04;
49     protected final byte CMD_ACTUATOR_MEASUREMENT_QUERY = 0x06;
50     protected final byte CMD_ACTUATOR_MEASUREMENT_RESPONE = 0x07;
51
52     protected final byte AllChannels_Mask = 0x1e;
53     protected final byte ChannelA_Mask = 0x00;
54     protected final byte ChannelB_Mask = 0x01;
55
56     protected final byte STATUS_SWITCHING_ON = 0x01;
57     protected final byte STATUS_SWITCHING_OFF = 0x00;
58     protected final byte STATUS_DIMMING_100 = 0x64;
59
60     public D2_01() {
61         super();
62     }
63
64     public D2_01(ERP1Message packet) {
65         super(packet);
66     }
67
68     protected byte getCMD() {
69         return (byte) (bytes[0] & cmdMask);
70     }
71
72     protected void setSwitchingData(OnOffType command, byte outputChannel) {
73         if (command == OnOffType.ON) {
74             setData(CMD_ACTUATOR_SET_STATUS, outputChannel, STATUS_SWITCHING_ON);
75         } else {
76             setData(CMD_ACTUATOR_SET_STATUS, outputChannel, STATUS_SWITCHING_OFF);
77         }
78     }
79
80     protected void setSwitchingQueryData(byte outputChannel) {
81         setData(CMD_ACTUATOR_STATUS_QUERY, outputChannel);
82     }
83
84     protected State getSwitchingData() {
85         if (getCMD() == CMD_ACTUATOR_STATUS_RESPONE) {
86             return (bytes[bytes.length - 1] & outputValueMask) == STATUS_SWITCHING_OFF ? OnOffType.OFF : OnOffType.ON;
87         }
88
89         return UnDefType.UNDEF;
90     }
91
92     protected byte getChannel() {
93         return (byte) (bytes[1] & outputChannelMask);
94     }
95
96     protected State getSwitchingData(byte channel) {
97         if (getCMD() == CMD_ACTUATOR_STATUS_RESPONE && (getChannel() == channel || getChannel() == AllChannels_Mask)) {
98             return (bytes[bytes.length - 1] & outputValueMask) == STATUS_SWITCHING_OFF ? OnOffType.OFF : OnOffType.ON;
99         }
100
101         return UnDefType.UNDEF;
102     }
103
104     protected void setDimmingData(Command command, byte outputChannel, Configuration config) {
105         byte outputValue;
106
107         if (command instanceof DecimalType) {
108             if (((DecimalType) command).equals(DecimalType.ZERO)) {
109                 outputValue = STATUS_SWITCHING_OFF;
110             } else {
111                 outputValue = ((DecimalType) command).byteValue();
112             }
113         } else if ((OnOffType) command == OnOffType.ON) {
114             outputValue = STATUS_DIMMING_100;
115         } else {
116             outputValue = STATUS_SWITCHING_OFF;
117         }
118
119         EnOceanChannelDimmerConfig c = config.as(EnOceanChannelDimmerConfig.class);
120         byte rampingTime = Integer.valueOf(c.rampingTime).byteValue();
121
122         setData(CMD_ACTUATOR_SET_STATUS, (byte) ((rampingTime << 5) | outputChannel), outputValue);
123     }
124
125     protected State getDimmingData() {
126         if (getCMD() == CMD_ACTUATOR_STATUS_RESPONE) {
127             return new PercentType((bytes[bytes.length - 1] & outputValueMask));
128         }
129
130         return UnDefType.UNDEF;
131     }
132
133     protected void setEnergyMeasurementQueryData(byte outputChannel) {
134         setData(CMD_ACTUATOR_MEASUREMENT_QUERY, outputChannel);
135     }
136
137     protected void setPowerMeasurementQueryData(byte outputChannel) {
138         setData(CMD_ACTUATOR_MEASUREMENT_QUERY, (byte) (0x20 | outputChannel));
139     }
140
141     protected State getEnergyMeasurementData() {
142         if (getCMD() == CMD_ACTUATOR_MEASUREMENT_RESPONE) {
143             float factor = 1;
144
145             switch (bytes[1] >>> 5) {
146                 case 0: // value is given as watt seconds, so divide it by 3600 to get watt hours, and 1000 to get
147                         // kilowatt hours
148                     factor /= (3600 * 1000);
149                     break;
150                 case 1: // value is given as watt hours, so divide it by 1000 to get kilowatt hours
151                     factor /= 1000;
152                     break;
153                 case 2: // value is given as kilowatt hours
154                     factor = 1;
155                     break;
156                 default:
157                     return UnDefType.UNDEF;
158             }
159
160             float energy = Long.parseLong(HexUtils.bytesToHex(new byte[] { bytes[2], bytes[3], bytes[4], bytes[5] }),
161                     16) * factor;
162             return new QuantityType<>(energy, Units.KILOWATT_HOUR);
163         }
164
165         return UnDefType.UNDEF;
166     }
167
168     protected State getPowerMeasurementData() {
169         if (getCMD() == CMD_ACTUATOR_MEASUREMENT_RESPONE) {
170             float factor = 1;
171
172             switch (bytes[1] >>> 5) {
173                 case 3: // value is given as watt
174                     factor = 1;
175                     break;
176                 case 4: // value is given as kilowatt
177                     factor /= 1000;
178                     break;
179                 default:
180                     return UnDefType.UNDEF;
181             }
182
183             float power = Long.parseLong(HexUtils.bytesToHex(new byte[] { bytes[2], bytes[3], bytes[4], bytes[5] }), 16)
184                     * factor;
185
186             return new QuantityType<>(power, Units.WATT);
187         }
188
189         return UnDefType.UNDEF;
190     }
191
192     @Override
193     public void addConfigPropertiesTo(DiscoveryResultBuilder discoveredThingResultBuilder) {
194         discoveredThingResultBuilder.withProperty(PARAMETER_SENDINGEEPID, getEEPType().getId())
195                 .withProperty(PARAMETER_RECEIVINGEEPID, getEEPType().getId());
196     }
197
198     @Override
199     protected void convertFromCommandImpl(String channelId, String channelTypeId, Command command,
200             Function<String, State> getCurrentStateFunc, Configuration config) {
201         if (channelId.equals(CHANNEL_GENERAL_SWITCHING)) {
202             if (command == RefreshType.REFRESH) {
203                 setSwitchingQueryData(AllChannels_Mask);
204             } else {
205                 setSwitchingData((OnOffType) command, AllChannels_Mask);
206             }
207         } else if (channelId.equals(CHANNEL_GENERAL_SWITCHINGA)) {
208             if (command == RefreshType.REFRESH) {
209                 setSwitchingQueryData(ChannelA_Mask);
210             } else {
211                 setSwitchingData((OnOffType) command, ChannelA_Mask);
212             }
213         } else if (channelId.equals(CHANNEL_GENERAL_SWITCHINGB)) {
214             if (command == RefreshType.REFRESH) {
215                 setSwitchingQueryData(ChannelB_Mask);
216             } else {
217                 setSwitchingData((OnOffType) command, ChannelB_Mask);
218             }
219         } else if (channelId.equals(CHANNEL_DIMMER)) {
220             if (command == RefreshType.REFRESH) {
221                 setSwitchingQueryData(AllChannels_Mask);
222             } else {
223                 setDimmingData(command, AllChannels_Mask, config);
224             }
225         } else if (channelId.equals(CHANNEL_INSTANTPOWER) && command == RefreshType.REFRESH) {
226             setPowerMeasurementQueryData(AllChannels_Mask);
227         } else if (channelId.equals(CHANNEL_TOTALUSAGE) && command == RefreshType.REFRESH) {
228             setEnergyMeasurementQueryData(AllChannels_Mask);
229         }
230     }
231
232     @Override
233     protected State convertToStateImpl(String channelId, String channelTypeId,
234             Function<String, State> getCurrentStateFunc, Configuration config) {
235         switch (channelId) {
236             case CHANNEL_GENERAL_SWITCHING:
237                 return getSwitchingData();
238             case CHANNEL_GENERAL_SWITCHINGA:
239                 return getSwitchingData(ChannelA_Mask);
240             case CHANNEL_GENERAL_SWITCHINGB:
241                 return getSwitchingData(ChannelB_Mask);
242             case CHANNEL_DIMMER:
243                 return getDimmingData();
244             case CHANNEL_INSTANTPOWER:
245                 return getPowerMeasurementData();
246             case CHANNEL_TOTALUSAGE:
247                 State value = getEnergyMeasurementData();
248                 State currentState = getCurrentStateFunc.apply(channelId);
249                 return EEPHelper.validateTotalUsage(value, currentState, config);
250         }
251
252         return UnDefType.UNDEF;
253     }
254 }