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.pilight.internal.handler;
15 import static org.openhab.binding.pilight.internal.PilightBindingConstants.CHANNEL_DIMLEVEL;
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.pilight.internal.dto.Action;
23 import org.openhab.binding.pilight.internal.dto.Code;
24 import org.openhab.binding.pilight.internal.dto.Device;
25 import org.openhab.binding.pilight.internal.dto.Status;
26 import org.openhab.binding.pilight.internal.dto.Values;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.Thing;
31 import org.openhab.core.types.Command;
32 import org.openhab.core.types.State;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * The {@link PilightDimmerHandler} is responsible for handling commands, which are
38 * sent to one of the channels.
40 * @author Stefan Röllin - Initial contribution
41 * @author Niklas Dörfler - Port pilight binding to openHAB 3 + add device discovery
44 public class PilightDimmerHandler extends PilightBaseHandler {
46 private static final int MAX_DIM_LEVEL_DEFAULT = 15;
47 private static final BigDecimal BIG_DECIMAL_100 = new BigDecimal(100);
49 private final Logger logger = LoggerFactory.getLogger(PilightDimmerHandler.class);
51 private int maxDimLevel = MAX_DIM_LEVEL_DEFAULT;
53 public PilightDimmerHandler(Thing thing) {
58 protected void updateFromStatus(Status status) {
59 BigDecimal dimLevel = BigDecimal.ZERO;
60 String dimLevelAsString = status.getValues().get("dimlevel");
62 if (dimLevelAsString != null) {
63 dimLevel = getPercentageFromDimLevel(dimLevelAsString);
65 // Dimmer items can can also be switched on or off in pilight.
66 // When this happens, the dimmer value is not reported. At least we know it's on or off.
67 String stateAsString = status.getValues().get("state");
68 if (stateAsString != null) {
69 State state = OnOffType.valueOf(stateAsString.toUpperCase());
70 dimLevel = state.equals(OnOffType.ON) ? BIG_DECIMAL_100 : BigDecimal.ZERO;
74 State state = new PercentType(dimLevel);
75 updateState(CHANNEL_DIMLEVEL, state);
79 protected void updateFromConfigDevice(Device device) {
80 Integer max = device.getDimlevelMaximum();
88 protected @Nullable Action createUpdateCommand(ChannelUID unused, Command command) {
89 Code code = new Code();
90 code.setDevice(getName());
92 if (command instanceof OnOffType) {
93 code.setState(command.equals(OnOffType.ON) ? Code.STATE_ON : Code.STATE_OFF);
94 } else if (command instanceof PercentType percentCommand) {
95 setDimmerValue(percentCommand, code);
97 logger.warn("Only OnOffType and PercentType are supported by a dimmer.");
101 Action action = new Action(Action.ACTION_CONTROL);
102 action.setCode(code);
106 private BigDecimal getPercentageFromDimLevel(String string) {
107 return new BigDecimal(string).setScale(2).divide(new BigDecimal(maxDimLevel), RoundingMode.HALF_UP)
108 .multiply(BIG_DECIMAL_100);
111 private void setDimmerValue(PercentType percent, Code code) {
112 if (PercentType.ZERO.equals(percent)) {
113 // pilight is not responding to commands that set both the dimlevel to 0 and state to off.
114 // So, we're only updating the state for now
115 code.setState(Code.STATE_OFF);
117 BigDecimal dimlevel = percent.toBigDecimal().setScale(2).divide(BIG_DECIMAL_100, RoundingMode.HALF_UP)
118 .multiply(BigDecimal.valueOf(maxDimLevel)).setScale(0, RoundingMode.HALF_UP);
120 Values values = new Values();
121 values.setDimlevel(dimlevel.intValue());
122 code.setValues(values);
123 code.setState(dimlevel.compareTo(BigDecimal.ZERO) == 1 ? Code.STATE_ON : Code.STATE_OFF);