]> git.basschouten.com Git - openhab-addons.git/blob
3aef4021d32c330de94c1890d111bb9ab92af20d
[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.onewire.internal.device;
14
15 import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
16
17 import java.util.BitSet;
18
19 import javax.measure.quantity.Dimensionless;
20 import javax.measure.quantity.Frequency;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.openhab.binding.onewire.internal.OwException;
24 import org.openhab.binding.onewire.internal.SensorId;
25 import org.openhab.binding.onewire.internal.config.BAE091xAnalogConfiguration;
26 import org.openhab.binding.onewire.internal.config.BAE091xPIOConfiguration;
27 import org.openhab.binding.onewire.internal.config.BAE091xPWMConfiguration;
28 import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
29 import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
30 import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.OnOffType;
33 import org.openhab.core.library.types.QuantityType;
34 import org.openhab.core.library.unit.Units;
35 import org.openhab.core.thing.Channel;
36 import org.openhab.core.thing.type.ChannelTypeUID;
37 import org.openhab.core.types.Command;
38 import org.openhab.core.types.State;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The {@link BAE0910} class defines a BAE0910 device
44  *
45  * @author Jan N. Klug - Initial contribution
46  */
47 @NonNullByDefault
48 public class BAE0910 extends AbstractOwDevice {
49     private static final int OUTC_OUTEN = 4;
50     private static final int OUTC_DS = 3;
51
52     private static final int PIOC_PIOEN = 4;
53     private static final int PIOC_DS = 3;
54     private static final int PIOC_PD = 2;
55     private static final int PIOC_PE = 1;
56     private static final int PIOC_DD = 0;
57
58     private static final int ADCC_ADCEN = 4;
59     private static final int ADCC_10BIT = 3;
60     @SuppressWarnings("unused") // for future use
61     private static final int ADCC_OFS = 2;
62     @SuppressWarnings("unused")
63     private static final int ADCC_GRP = 1;
64     @SuppressWarnings("unused")
65     private static final int ADCC_STP = 0;
66
67     private static final int TPMC_POL = 7;
68     private static final int TPMC_INENA = 5;
69     private static final int TPMC_PWMDIS = 4;
70     private static final int TPMC_PS2 = 2;
71     private static final int TPMC_PS1 = 1;
72     private static final int TPMC_PS0 = 0;
73
74     private final Logger logger = LoggerFactory.getLogger(BAE0910.class);
75     private final OwserverDeviceParameter pin1CounterParameter = new OwserverDeviceParameter("/counter");
76     private final OwserverDeviceParameter pin2OutParameter = new OwserverDeviceParameter("/out");
77     private final OwserverDeviceParameter pin6PIOParameter = new OwserverDeviceParameter("/pio");
78     private final OwserverDeviceParameter pin7AnalogParameter = new OwserverDeviceParameter("/adc");
79     private final OwserverDeviceParameter outcParameter = new OwserverDeviceParameter("/outc");
80     private final OwserverDeviceParameter piocParameter = new OwserverDeviceParameter("/pioc");
81     private final OwserverDeviceParameter adccParameter = new OwserverDeviceParameter("/adcc");
82     private final OwserverDeviceParameter tpm1cParameter = new OwserverDeviceParameter("/tpm1c");
83     private final OwserverDeviceParameter tpm2cParameter = new OwserverDeviceParameter("/tpm2c");
84     private final OwserverDeviceParameter period1Parameter = new OwserverDeviceParameter("/period1");
85     private final OwserverDeviceParameter period2Parameter = new OwserverDeviceParameter("/period2");
86     private final OwserverDeviceParameter duty1Parameter = new OwserverDeviceParameter("/duty1");
87     private final OwserverDeviceParameter duty2Parameter = new OwserverDeviceParameter("/duty2");
88     private final OwserverDeviceParameter duty3Parameter = new OwserverDeviceParameter("/duty3");
89     private final OwserverDeviceParameter duty4Parameter = new OwserverDeviceParameter("/duty4");
90
91     private final BitSet outcRegister = new BitSet(8);
92     private final BitSet piocRegister = new BitSet(8);
93     private final BitSet adccRegister = new BitSet(8);
94     private final BitSet tpm1cRegister = new BitSet(8);
95     private final BitSet tpm2cRegister = new BitSet(8);
96
97     private double resolution1 = 8; // in µs
98     private double resolution2 = 8; // in µs
99
100     public BAE0910(SensorId sensorId, OwBaseThingHandler callback) {
101         super(sensorId, callback);
102     }
103
104     @Override
105     public void configureChannels() {
106     }
107
108     public void configureChannels(OwserverBridgeHandler bridgeHandler) throws OwException {
109         outcRegister.clear();
110         piocRegister.clear();
111         adccRegister.clear();
112         tpm1cRegister.clear();
113         tpm2cRegister.clear();
114
115         if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
116             Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ1);
117             if (channel != null) {
118                 BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
119                 tpm1cRegister.set(TPMC_POL, channelConfig.reversePolarity);
120                 tpm1cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
121                 tpm1cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
122                 tpm1cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
123                 resolution1 = 0.0625 * (1 << channelConfig.prescaler);
124             } else {
125                 throw new OwException("trying to configure pwm but frequency channel is missing");
126             }
127         }
128
129         if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
130             Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ2);
131             if (channel != null) {
132                 BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
133                 tpm2cRegister.set(TPMC_POL, channelConfig.reversePolarity);
134                 tpm2cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
135                 tpm2cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
136                 tpm2cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
137                 resolution2 = 0.0625 * (1 << channelConfig.prescaler);
138             } else {
139                 throw new OwException("trying to configure pwm but frequency channel is missing");
140             }
141         }
142
143         // Pin 2
144         if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
145             outcRegister.set(OUTC_DS);
146             outcRegister.set(OUTC_OUTEN);
147         }
148
149         // Pin 6
150         if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
151             piocRegister.set(PIOC_PIOEN);
152             piocRegister.set(PIOC_DS);
153             Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL6);
154             if (channel != null) {
155                 BAE091xPIOConfiguration channelConfig = channel.getConfiguration().as(BAE091xPIOConfiguration.class);
156                 piocRegister.set(PIOC_DD, "output".equals(channelConfig.mode));
157                 switch (channelConfig.pulldevice) {
158                     case "pullup" -> {
159                         piocRegister.set(PIOC_PE);
160                         piocRegister.clear(PIOC_PD);
161                     }
162                     case "pulldown" -> {
163                         piocRegister.set(PIOC_PE);
164                         piocRegister.set(PIOC_PD);
165                     }
166                     default -> {
167                     }
168                 }
169             } else {
170                 throw new OwException("trying to configure pin 6 but channel is missing");
171             }
172         }
173
174         // Pin 7
175         if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
176             adccRegister.set(ADCC_ADCEN);
177             Channel channel = callback.getThing().getChannel(CHANNEL_VOLTAGE);
178             if (channel != null) {
179                 BAE091xAnalogConfiguration channelConfig = channel.getConfiguration()
180                         .as(BAE091xAnalogConfiguration.class);
181                 adccRegister.set(ADCC_10BIT, channelConfig.hires);
182             } else {
183                 throw new OwException("trying to configure pin 7 but channel is missing");
184             }
185         }
186
187         if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
188             tpm2cRegister.set(TPMC_PWMDIS);
189         }
190
191         // Pin 8
192         if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
193             tpm1cRegister.set(TPMC_PWMDIS);
194             Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL8);
195             if (channel != null) {
196                 if ((new ChannelTypeUID(BINDING_ID, "bae-in")).equals(channel.getChannelTypeUID())) {
197                     tpm1cRegister.set(TPMC_INENA);
198                 }
199             } else {
200                 throw new OwException("trying to configure pin 8 but channel is missing");
201             }
202         }
203
204         // write configuration
205         bridgeHandler.writeBitSet(sensorId, outcParameter, outcRegister);
206         bridgeHandler.writeBitSet(sensorId, piocParameter, piocRegister);
207         bridgeHandler.writeBitSet(sensorId, adccParameter, adccRegister);
208         bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
209         bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
210
211         isConfigured = true;
212     }
213
214     @Override
215     public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
216         if (isConfigured) {
217             logger.trace("refresh of sensor {} started", sensorId);
218             // Counter
219             if (enabledChannels.contains(CHANNEL_COUNTER)) {
220                 State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
221                 callback.postUpdate(CHANNEL_COUNTER, counterValue);
222             }
223
224             // Digital Pins
225             if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
226                 BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
227                 callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
228             }
229             if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
230                 BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
231                 callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
232             }
233             if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
234                 BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
235                 callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
236             }
237             if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
238                 BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
239                 callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
240             }
241
242             // Analog
243             if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
244                 State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
245                 callback.postUpdate(CHANNEL_VOLTAGE, new QuantityType<>((DecimalType) analogValue, Units.VOLT));
246             }
247
248             // PWM
249             int period1 = 0;
250             int period2 = 0;
251             if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
252                 period1 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)).intValue();
253                 double frequency = (period1 > 0) ? 1 / (period1 * resolution1 * 1e-6) : 0;
254                 callback.postUpdate(CHANNEL_PWM_FREQ1, new QuantityType<>(frequency, Units.HERTZ));
255             }
256             if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
257                 period2 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)).intValue();
258                 double frequency = (period2 > 0) ? 1 / (period2 * resolution2 * 1e-6) : 0;
259                 callback.postUpdate(CHANNEL_PWM_FREQ2, new QuantityType<>(frequency, Units.HERTZ));
260             }
261             if (enabledChannels.contains(CHANNEL_PWM_DUTY1)) {
262                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty1Parameter)).intValue();
263                 double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
264                 callback.postUpdate(CHANNEL_PWM_DUTY1, new QuantityType<>(duty, Units.PERCENT));
265             }
266             if (enabledChannels.contains(CHANNEL_PWM_DUTY2)) {
267                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty2Parameter)).intValue();
268                 double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
269                 callback.postUpdate(CHANNEL_PWM_DUTY2, new QuantityType<>(duty, Units.PERCENT));
270             }
271             if (enabledChannels.contains(CHANNEL_PWM_DUTY3)) {
272                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty3Parameter)).intValue();
273                 double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
274                 callback.postUpdate(CHANNEL_PWM_DUTY3, new QuantityType<>(duty, Units.PERCENT));
275             }
276             if (enabledChannels.contains(CHANNEL_PWM_DUTY4)) {
277                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty4Parameter)).intValue();
278                 double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
279                 callback.postUpdate(CHANNEL_PWM_DUTY4, new QuantityType<>(duty, Units.PERCENT));
280             }
281         }
282     }
283
284     public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
285         try {
286             BitSet value = new BitSet(8);
287             switch (channelId) {
288                 case CHANNEL_DIGITAL2 -> {
289                     // output
290                     if (!outcRegister.get(OUTC_OUTEN)) {
291                         return false;
292                     }
293                     value.set(0, command.equals(OnOffType.ON));
294                     bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
295                 }
296                 case CHANNEL_DIGITAL6 -> {
297                     // not input, pio
298                     if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
299                         return false;
300                     }
301                     value.set(0, command.equals(OnOffType.ON));
302                     bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
303                 }
304                 case CHANNEL_DIGITAL7 -> {
305                     // not pwm, not analog
306                     if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
307                         return false;
308                     }
309                     tpm2cRegister.set(TPMC_POL, command.equals(OnOffType.ON));
310                     bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
311                 }
312                 case CHANNEL_DIGITAL8 -> {
313                     // not input, not pwm
314                     if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
315                         return false;
316                     }
317                     tpm1cRegister.set(TPMC_POL, command.equals(OnOffType.ON));
318                     bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
319                 }
320                 case CHANNEL_PWM_FREQ1 -> {
321                     if (command instanceof QuantityType<?>) {
322                         bridgeHandler.writeDecimalType(sensorId, period1Parameter,
323                                 convertFrequencyToPeriod(command, resolution1));
324                     }
325                 }
326                 case CHANNEL_PWM_FREQ2 -> {
327                     if (command instanceof QuantityType<?>) {
328                         bridgeHandler.writeDecimalType(sensorId, period2Parameter,
329                                 convertFrequencyToPeriod(command, resolution2));
330                     }
331                 }
332                 case CHANNEL_PWM_DUTY1 -> {
333                     if (command instanceof QuantityType<?>) {
334                         bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
335                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
336                     }
337                 }
338                 case CHANNEL_PWM_DUTY2 -> {
339                     if (command instanceof QuantityType<?>) {
340                         bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
341                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
342                     }
343                 }
344                 case CHANNEL_PWM_DUTY3 -> {
345                     if (command instanceof QuantityType<?>) {
346                         bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
347                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
348                     }
349                 }
350                 case CHANNEL_PWM_DUTY4 -> {
351                     if (command instanceof QuantityType<?>) {
352                         bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
353                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
354                     }
355                 }
356                 default -> throw new OwException("unknown or invalid channel");
357             }
358             return true;
359         } catch (OwException e) {
360             logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
361             return false;
362         }
363     }
364
365     public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
366             throws OwException {
367         OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
368
369         String subDeviceType = bridgeHandler.readString(sensorId, deviceTypeParameter);
370         return switch (subDeviceType) {
371             case "2" -> OwSensorType.BAE0910;
372             case "3" -> OwSensorType.BAE0911;
373             default -> OwSensorType.UNKNOWN;
374         };
375     }
376
377     private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
378         @SuppressWarnings("unchecked")
379         QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(Units.HERTZ);
380         if (fHz == null) {
381             throw new OwException("could not convert command to frequency");
382         }
383         double f = fHz.doubleValue();
384         int period = 0;
385         if (f > 0) {
386             period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
387         }
388         return new DecimalType(period);
389     }
390
391     private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
392         @SuppressWarnings("unchecked")
393         double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
394         int dutyValue = 0;
395         if (dutyCycle > 0 && dutyCycle <= 100) {
396             dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
397         } else if (dutyCycle > 100) {
398             dutyValue = 65535;
399         }
400         return new DecimalType(dutyValue);
401     }
402 }