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 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);
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);
170 throw new OwException("trying to configure pin 6 but channel is missing");
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);
183 throw new OwException("trying to configure pin 7 but channel is missing");
187 if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
188 tpm2cRegister.set(TPMC_PWMDIS);
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);
200 throw new OwException("trying to configure pin 8 but channel is missing");
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);
215 public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
217 logger.trace("refresh of sensor {} started", sensorId);
219 if (enabledChannels.contains(CHANNEL_COUNTER)) {
220 State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
221 callback.postUpdate(CHANNEL_COUNTER, counterValue);
225 if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
226 BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
227 callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
229 if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
230 BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
231 callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
233 if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
234 BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
235 callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
237 if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
238 BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
239 callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
243 if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
244 State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
245 callback.postUpdate(CHANNEL_VOLTAGE, new QuantityType<>((DecimalType) analogValue, Units.VOLT));
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));
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));
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));
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));
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));
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));
284 public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
286 BitSet value = new BitSet(8);
288 case CHANNEL_DIGITAL2 -> {
290 if (!outcRegister.get(OUTC_OUTEN)) {
293 value.set(0, command.equals(OnOffType.ON));
294 bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
296 case CHANNEL_DIGITAL6 -> {
298 if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
301 value.set(0, command.equals(OnOffType.ON));
302 bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
304 case CHANNEL_DIGITAL7 -> {
305 // not pwm, not analog
306 if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
309 tpm2cRegister.set(TPMC_POL, command.equals(OnOffType.ON));
310 bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
312 case CHANNEL_DIGITAL8 -> {
313 // not input, not pwm
314 if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
317 tpm1cRegister.set(TPMC_POL, command.equals(OnOffType.ON));
318 bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
320 case CHANNEL_PWM_FREQ1 -> {
321 if (command instanceof QuantityType<?>) {
322 bridgeHandler.writeDecimalType(sensorId, period1Parameter,
323 convertFrequencyToPeriod(command, resolution1));
326 case CHANNEL_PWM_FREQ2 -> {
327 if (command instanceof QuantityType<?>) {
328 bridgeHandler.writeDecimalType(sensorId, period2Parameter,
329 convertFrequencyToPeriod(command, resolution2));
332 case CHANNEL_PWM_DUTY1 -> {
333 if (command instanceof QuantityType<?>) {
334 bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
335 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
338 case CHANNEL_PWM_DUTY2 -> {
339 if (command instanceof QuantityType<?>) {
340 bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
341 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
344 case CHANNEL_PWM_DUTY3 -> {
345 if (command instanceof QuantityType<?>) {
346 bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
347 (DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
350 case CHANNEL_PWM_DUTY4 -> {
351 if (command instanceof QuantityType<?>) {
352 bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
353 (DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
356 default -> throw new OwException("unknown or invalid channel");
359 } catch (OwException e) {
360 logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
365 public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
367 OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
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;
377 private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
378 @SuppressWarnings("unchecked")
379 QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(Units.HERTZ);
381 throw new OwException("could not convert command to frequency");
383 double f = fHz.doubleValue();
386 period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
388 return new DecimalType(period);
391 private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
392 @SuppressWarnings("unchecked")
393 double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
395 if (dutyCycle > 0 && dutyCycle <= 100) {
396 dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
397 } else if (dutyCycle > 100) {
400 return new DecimalType(dutyValue);