2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.onewire.internal.device;
15 import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
17 import java.util.BitSet;
19 import javax.measure.quantity.Dimensionless;
20 import javax.measure.quantity.Frequency;
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;
43 * The {@link BAE0910} class defines a BAE0910 device
45 * @author Jan N. Klug - Initial contribution
48 public class BAE0910 extends AbstractOwDevice {
49 private static final int OUTC_OUTEN = 4;
50 private static final int OUTC_DS = 3;
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;
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;
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;
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");
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);
97 private double resolution1 = 8; // in µs
98 private double resolution2 = 8; // in µs
100 public BAE0910(SensorId sensorId, OwBaseThingHandler callback) {
101 super(sensorId, callback);
105 public void configureChannels() {
108 public void configureChannels(OwserverBridgeHandler bridgeHandler) throws OwException {
109 outcRegister.clear();
110 piocRegister.clear();
111 adccRegister.clear();
112 tpm1cRegister.clear();
113 tpm2cRegister.clear();
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);
125 throw new OwException("trying to configure pwm but frequency channel is missing");
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);
139 throw new OwException("trying to configure pwm but frequency channel is missing");
144 if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
145 outcRegister.set(OUTC_DS);
146 outcRegister.set(OUTC_OUTEN);
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) {
159 piocRegister.set(PIOC_PE);
160 piocRegister.clear(PIOC_PD);
163 piocRegister.set(PIOC_PE);
164 piocRegister.set(PIOC_PD);
169 throw new OwException("trying to configure pin 6 but channel is missing");
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);
182 throw new OwException("trying to configure pin 7 but channel is missing");
186 if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
187 tpm2cRegister.set(TPMC_PWMDIS);
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);
199 throw new OwException("trying to configure pin 8 but channel is missing");
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);
214 public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
216 logger.trace("refresh of sensor {} started", sensorId);
218 if (enabledChannels.contains(CHANNEL_COUNTER)) {
219 State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
220 callback.postUpdate(CHANNEL_COUNTER, counterValue);
224 if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
225 BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
226 callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
228 if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
229 BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
230 callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
232 if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
233 BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
234 callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
236 if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
237 BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
238 callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
242 if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
243 State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
244 callback.postUpdate(CHANNEL_VOLTAGE, new QuantityType<>((DecimalType) analogValue, Units.VOLT));
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));
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));
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));
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));
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));
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));
283 public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
285 BitSet value = new BitSet(8);
287 case CHANNEL_DIGITAL2:
289 if (!outcRegister.get(OUTC_OUTEN)) {
292 value.set(0, ((OnOffType) command).equals(OnOffType.ON));
293 bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
295 case CHANNEL_DIGITAL6:
297 if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
300 value.set(0, ((OnOffType) command).equals(OnOffType.ON));
301 bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
303 case CHANNEL_DIGITAL7:
304 // not pwm, not analog
305 if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
308 tpm2cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
309 bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
311 case CHANNEL_DIGITAL8:
312 // not input, not pwm
313 if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
316 tpm1cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
317 bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
319 case CHANNEL_PWM_FREQ1:
320 if (command instanceof QuantityType<?>) {
321 bridgeHandler.writeDecimalType(sensorId, period1Parameter,
322 convertFrequencyToPeriod(command, resolution1));
325 case CHANNEL_PWM_FREQ2:
326 if (command instanceof QuantityType<?>) {
327 bridgeHandler.writeDecimalType(sensorId, period2Parameter,
328 convertFrequencyToPeriod(command, resolution2));
331 case CHANNEL_PWM_DUTY1:
332 if (command instanceof QuantityType<?>) {
333 bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
334 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
337 case CHANNEL_PWM_DUTY2:
338 if (command instanceof QuantityType<?>) {
339 bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
340 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
343 case CHANNEL_PWM_DUTY3:
344 if (command instanceof QuantityType<?>) {
345 bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
346 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
349 case CHANNEL_PWM_DUTY4:
350 if (command instanceof QuantityType<?>) {
351 bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
352 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
356 throw new OwException("unknown or invalid channel");
362 logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
367 public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
369 OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
371 String subDeviceType = bridgeHandler.readString(sensorId, deviceTypeParameter);
372 switch (subDeviceType) {
374 return OwSensorType.BAE0910;
376 return OwSensorType.BAE0911;
378 return OwSensorType.UNKNOWN;
382 private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
383 @SuppressWarnings("unchecked")
384 QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(Units.HERTZ);
386 throw new OwException("could not convert command to frequency");
388 double f = fHz.doubleValue();
391 period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
393 return new DecimalType(period);
396 private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
397 @SuppressWarnings("unchecked")
398 double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
400 if (dutyCycle > 0 && dutyCycle <= 100) {
401 dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
402 } else if (dutyCycle > 100) {
405 return new DecimalType(dutyValue);