]> git.basschouten.com Git - openhab-addons.git/blob
1fca433692c76e4b848a1d65a6f27024ff8d79d6
[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 BitSet outcRegister = new BitSet(8);
92     private BitSet piocRegister = new BitSet(8);
93     private BitSet adccRegister = new BitSet(8);
94     private BitSet tpm1cRegister = new BitSet(8);
95     private 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, channelConfig.mode.equals("output"));
157                 switch (channelConfig.pulldevice) {
158                     case "pullup":
159                         piocRegister.set(PIOC_PE);
160                         piocRegister.clear(PIOC_PD);
161                         break;
162                     case "pulldown":
163                         piocRegister.set(PIOC_PE);
164                         piocRegister.set(PIOC_PD);
165                         break;
166                     default:
167                 }
168             } else {
169                 throw new OwException("trying to configure pin 6 but channel is missing");
170             }
171         }
172
173         // Pin 7
174         if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
175             adccRegister.set(ADCC_ADCEN);
176             Channel channel = callback.getThing().getChannel(CHANNEL_VOLTAGE);
177             if (channel != null) {
178                 BAE091xAnalogConfiguration channelConfig = channel.getConfiguration()
179                         .as(BAE091xAnalogConfiguration.class);
180                 adccRegister.set(ADCC_10BIT, channelConfig.hires);
181             } else {
182                 throw new OwException("trying to configure pin 7 but channel is missing");
183             }
184         }
185
186         if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
187             tpm2cRegister.set(TPMC_PWMDIS);
188         }
189
190         // Pin 8
191         if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
192             tpm1cRegister.set(TPMC_PWMDIS);
193             Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL8);
194             if (channel != null) {
195                 if ((new ChannelTypeUID(BINDING_ID, "bae-in")).equals(channel.getChannelTypeUID())) {
196                     tpm1cRegister.set(TPMC_INENA);
197                 }
198             } else {
199                 throw new OwException("trying to configure pin 8 but channel is missing");
200             }
201         }
202
203         // write configuration
204         bridgeHandler.writeBitSet(sensorId, outcParameter, outcRegister);
205         bridgeHandler.writeBitSet(sensorId, piocParameter, piocRegister);
206         bridgeHandler.writeBitSet(sensorId, adccParameter, adccRegister);
207         bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
208         bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
209
210         isConfigured = true;
211     }
212
213     @Override
214     public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
215         if (isConfigured) {
216             logger.trace("refresh of sensor {} started", sensorId);
217             // Counter
218             if (enabledChannels.contains(CHANNEL_COUNTER)) {
219                 State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
220                 callback.postUpdate(CHANNEL_COUNTER, counterValue);
221             }
222
223             // Digital Pins
224             if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
225                 BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
226                 callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
227             }
228             if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
229                 BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
230                 callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
231             }
232             if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
233                 BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
234                 callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
235             }
236             if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
237                 BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
238                 callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
239             }
240
241             // Analog
242             if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
243                 State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
244                 callback.postUpdate(CHANNEL_VOLTAGE, new QuantityType<>((DecimalType) analogValue, Units.VOLT));
245             }
246
247             // PWM
248             int period1 = 0;
249             int period2 = 0;
250             if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
251                 period1 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)).intValue();
252                 double frequency = (period1 > 0) ? 1 / (period1 * resolution1 * 1e-6) : 0;
253                 callback.postUpdate(CHANNEL_PWM_FREQ1, new QuantityType<>(frequency, Units.HERTZ));
254             }
255             if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
256                 period2 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)).intValue();
257                 double frequency = (period2 > 0) ? 1 / (period2 * resolution2 * 1e-6) : 0;
258                 callback.postUpdate(CHANNEL_PWM_FREQ2, new QuantityType<>(frequency, Units.HERTZ));
259             }
260             if (enabledChannels.contains(CHANNEL_PWM_DUTY1)) {
261                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty1Parameter)).intValue();
262                 double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
263                 callback.postUpdate(CHANNEL_PWM_DUTY1, new QuantityType<>(duty, Units.PERCENT));
264             }
265             if (enabledChannels.contains(CHANNEL_PWM_DUTY2)) {
266                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty2Parameter)).intValue();
267                 double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
268                 callback.postUpdate(CHANNEL_PWM_DUTY2, new QuantityType<>(duty, Units.PERCENT));
269             }
270             if (enabledChannels.contains(CHANNEL_PWM_DUTY3)) {
271                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty3Parameter)).intValue();
272                 double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
273                 callback.postUpdate(CHANNEL_PWM_DUTY3, new QuantityType<>(duty, Units.PERCENT));
274             }
275             if (enabledChannels.contains(CHANNEL_PWM_DUTY4)) {
276                 int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty4Parameter)).intValue();
277                 double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
278                 callback.postUpdate(CHANNEL_PWM_DUTY4, new QuantityType<>(duty, Units.PERCENT));
279             }
280         }
281     }
282
283     public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
284         try {
285             BitSet value = new BitSet(8);
286             switch (channelId) {
287                 case CHANNEL_DIGITAL2:
288                     // output
289                     if (!outcRegister.get(OUTC_OUTEN)) {
290                         return false;
291                     }
292                     value.set(0, ((OnOffType) command).equals(OnOffType.ON));
293                     bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
294                     break;
295                 case CHANNEL_DIGITAL6:
296                     // not input, pio
297                     if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
298                         return false;
299                     }
300                     value.set(0, ((OnOffType) command).equals(OnOffType.ON));
301                     bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
302                     break;
303                 case CHANNEL_DIGITAL7:
304                     // not pwm, not analog
305                     if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
306                         return false;
307                     }
308                     tpm2cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
309                     bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
310                     break;
311                 case CHANNEL_DIGITAL8:
312                     // not input, not pwm
313                     if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
314                         return false;
315                     }
316                     tpm1cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
317                     bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
318                     break;
319                 case CHANNEL_PWM_FREQ1:
320                     if (command instanceof QuantityType<?>) {
321                         bridgeHandler.writeDecimalType(sensorId, period1Parameter,
322                                 convertFrequencyToPeriod(command, resolution1));
323                     }
324                     break;
325                 case CHANNEL_PWM_FREQ2:
326                     if (command instanceof QuantityType<?>) {
327                         bridgeHandler.writeDecimalType(sensorId, period2Parameter,
328                                 convertFrequencyToPeriod(command, resolution2));
329                     }
330                     break;
331                 case CHANNEL_PWM_DUTY1:
332                     if (command instanceof QuantityType<?>) {
333                         bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
334                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
335                     }
336                     break;
337                 case CHANNEL_PWM_DUTY2:
338                     if (command instanceof QuantityType<?>) {
339                         bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
340                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
341                     }
342                     break;
343                 case CHANNEL_PWM_DUTY3:
344                     if (command instanceof QuantityType<?>) {
345                         bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
346                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
347                     }
348                     break;
349                 case CHANNEL_PWM_DUTY4:
350                     if (command instanceof QuantityType<?>) {
351                         bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
352                                 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
353                     }
354                     break;
355                 default:
356                     throw new OwException("unknown or invalid channel");
357             }
358             return true;
359         } catch (
360
361         OwException e) {
362             logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
363             return false;
364         }
365     }
366
367     public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
368             throws OwException {
369         OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
370
371         String subDeviceType = bridgeHandler.readString(sensorId, deviceTypeParameter);
372         switch (subDeviceType) {
373             case "2":
374                 return OwSensorType.BAE0910;
375             case "3":
376                 return OwSensorType.BAE0911;
377             default:
378                 return OwSensorType.UNKNOWN;
379         }
380     }
381
382     private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
383         @SuppressWarnings("unchecked")
384         QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(Units.HERTZ);
385         if (fHz == null) {
386             throw new OwException("could not convert command to frequency");
387         }
388         double f = fHz.doubleValue();
389         int period = 0;
390         if (f > 0) {
391             period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
392         }
393         return new DecimalType(period);
394     }
395
396     private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
397         @SuppressWarnings("unchecked")
398         double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
399         int dutyValue = 0;
400         if (dutyCycle > 0 && dutyCycle <= 100) {
401             dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
402         } else if (dutyCycle > 100) {
403             dutyValue = 65535;
404         }
405         return new DecimalType(dutyValue);
406     }
407 }