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.souliss.internal.handler;
15 import java.text.SimpleDateFormat;
16 import java.util.Date;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.souliss.internal.SoulissBindingConstants;
21 import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
22 import org.openhab.binding.souliss.internal.config.GatewayConfig;
23 import org.openhab.binding.souliss.internal.protocol.CommonCommands;
24 import org.openhab.core.library.types.DateTimeType;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.OpenClosedType;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseThingHandler;
34 * This class implements the base Souliss Typical All other Typicals derive from
37 * ...from wiki of Dario De Maio
38 * In Souliss the logics that drive your lights, curtains, LED, and
39 * others are pre-configured into so called Typicals. A Typical is a
40 * logic with a predefined set of inputs and outputs and a know
41 * behavior, are used to standardize the user interface and have a
42 * configuration-less behavior.
44 * @author Tonino Fazio - Initial contribution
45 * @author Luca Calcaterra - Refactor for OH3
49 public abstract class SoulissGenericHandler extends BaseThingHandler implements TypicalCommonMethods {
54 private final CommonCommands commonCommands = new CommonCommands();
56 // 0 means that Secure Send is disabled
57 boolean bSecureSend = false;
58 // true means that expected value is setpoint (only for T31, T19 and T6x)
59 boolean bExpectedValueSameAsSet = false;
61 protected SoulissGenericHandler(Thing thing) {
68 public int getSlot() {
73 public void initialize() {
75 var cfg = thing.getConfiguration();
76 var props = cfg.getProperties();
78 var pNode = props.get("node");
79 var pSlot = props.get("slot");
81 if ((pNode != null) && (pSlot != null)) {
82 iNode = Integer.parseInt(pNode.toString());
83 iSlot = Integer.parseInt(pSlot.toString());
84 updateProperty(SoulissBindingConstants.PROPERTY_NODE, Integer.toString(iNode));
85 updateProperty(SoulissBindingConstants.PROPERTY_SLOT, Integer.toString(iSlot));
86 updateProperty(SoulissBindingConstants.PROPERTY_UNIQUEID,
87 "N" + Integer.toString(iNode) + "S" + Integer.toString(iSlot));
89 } catch (Exception e) {
90 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
91 "Error getting node/slot from souliss typical (thing config)");
97 * the SoulissNodeID to get
99 public int getNode() {
103 protected synchronized void commandReadNodeTypsStates() {
104 var gwConfig = getGatewayConfig();
105 if (gwConfig != null) {
106 commonCommands.sendTypicalRequestFrame(gwConfig, this.getNode(), 1);
111 * Send a command as hexadecimal, e.g.: SOULISS_T1N_ON_CMD = 0x02; short
112 * SOULISS_T1N_OFF_CMD = 0x04;
116 public void commandSEND(byte command) {
117 var gwConfig = getGatewayConfig();
118 if (gwConfig != null) {
119 commonCommands.sendFORCEFrame(gwConfig, this.getNode(), this.getSlot(), command);
123 public void commandSendRgb(byte command, byte r, byte g, byte b) {
124 var gwConfig = getGatewayConfig();
125 if (gwConfig != null) {
126 commonCommands.sendFORCEFrame(gwConfig, command, r, g, b);
130 public void commandSEND(byte command, byte b1, byte b2) {
131 var gwConfig = getGatewayConfig();
132 if (gwConfig != null) {
133 commonCommands.sendFORCEFrameT31SetPoint(gwConfig, this.getNode(), this.getSlot(), command, b1, b2);
137 public void commandSEND(byte b1, byte b2) {
138 var gwConfig = getGatewayConfig();
139 if (gwConfig != null) {
140 commonCommands.sendFORCEFrameT61SetPoint(gwConfig, this.getNode(), this.getSlot(), b1, b2);
145 * Create a time stamp as "yyyy-MM-dd'T'HH:mm:ssz"
147 * @return String timestamp
149 private static String getTimestamp() {
150 // Pattern : yyyy-MM-dd'T'HH:mm:ssz
151 var sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz");
153 return sdf.format(n.getTime());
157 public void thingUpdated(Thing thing) {
161 public @Nullable GatewayConfig getGatewayConfig() {
162 var bridge = getBridge();
163 if (bridge != null) {
164 SoulissGatewayHandler bridgeHandler = (SoulissGatewayHandler) bridge.getHandler();
165 if (bridgeHandler != null) {
166 return bridgeHandler.getGwConfig();
172 public @Nullable String getLabel() {
173 return getThing().getLabel();
176 public void setHealthy(byte shHealthy) {
177 this.updateState(SoulissBindingConstants.HEALTHY_CHANNEL, new DecimalType(shHealthy & 0xFF));
178 this.updateStatus(ThingStatus.ONLINE);
181 public void setLastStatusStored() {
182 this.updateState(SoulissBindingConstants.LASTSTATUSSTORED_CHANNEL, DateTimeType.valueOf(getTimestamp()));
185 protected @Nullable OnOffType getOhStateOnOffFromSoulissVal(byte sVal) {
186 if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
188 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
189 return OnOffType.OFF;
190 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_FEEDBACK) {
192 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_FEEDBACK) {
193 return OnOffType.OFF;
194 } else if (sVal == SoulissProtocolConstants.SOULISS_T4N_NOT_ARMED) {
195 return OnOffType.OFF;
196 } else if (sVal == SoulissProtocolConstants.SOULISS_T4N_ARMED) {
203 protected @Nullable OpenClosedType getOhStateOpenCloseFromSoulissVal(byte sVal) {
204 if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
205 return OpenClosedType.CLOSED;
206 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
207 return OpenClosedType.OPEN;