2 * Copyright (c) 2010-2021 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;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * This class implements the base Souliss Typical All other Typicals derive from
39 * ...from wiki of Dario De Maio
40 * In Souliss the logics that drive your lights, curtains, LED, and
41 * others are pre-configured into so called Typicals. A Typical is a
42 * logic with a predefined set of inputs and outputs and a know
43 * behavior, are used to standardize the user interface and have a
44 * configuration-less behavior.
46 * @author Tonino Fazio - Initial contribution
47 * @author Luca Calcaterra - Refactor for OH3
51 public abstract class SoulissGenericHandler extends BaseThingHandler implements TypicalCommonMethods {
55 private final Logger logger = LoggerFactory.getLogger(SoulissGenericHandler.class);
57 private final CommonCommands commonCommands = new CommonCommands();
59 // 0 means that Secure Send is disabled
60 boolean bSecureSend = false;
61 // true means that expected value is setpoint (only for T31, T19 and T6x)
62 boolean bExpectedValueSameAsSet = false;
64 protected SoulissGenericHandler(Thing thing) {
71 public int getSlot() {
76 public void initialize() {
78 var cfg = thing.getConfiguration();
79 var props = cfg.getProperties();
81 var pNode = props.get("node");
82 var pSlot = props.get("slot");
84 if ((pNode != null) && (pSlot != null)) {
85 iNode = Integer.parseInt(pNode.toString());
86 iSlot = Integer.parseInt(pSlot.toString());
87 updateProperty(SoulissBindingConstants.PROPERTY_NODE, Integer.toString(iNode));
88 updateProperty(SoulissBindingConstants.PROPERTY_SLOT, Integer.toString(iSlot));
89 updateProperty(SoulissBindingConstants.PROPERTY_UNIQUEID,
90 "N" + Integer.toString(iNode) + "S" + Integer.toString(iSlot));
92 } catch (Exception e) {
93 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
94 "Error getting node/slot from souliss typical (thing config)");
100 * the SoulissNodeID to get
102 public int getNode() {
106 protected synchronized void commandReadNodeTypsStates() {
107 var gwConfig = getGatewayConfig();
108 if (gwConfig != null) {
109 commonCommands.sendTypicalRequestFrame(gwConfig, this.getNode(), 1);
114 * Send a command as hexadecimal, e.g.: SOULISS_T1N_ON_CMD = 0x02; short
115 * SOULISS_T1N_OFF_CMD = 0x04;
119 public void commandSEND(byte command) {
120 var gwConfig = getGatewayConfig();
121 if (gwConfig != null) {
122 commonCommands.sendFORCEFrame(gwConfig, this.getNode(), this.getSlot(), command);
126 public void commandSendRgb(byte command, byte r, byte g, byte b) {
127 var gwConfig = getGatewayConfig();
128 if (gwConfig != null) {
129 commonCommands.sendFORCEFrame(gwConfig, command, r, g, b);
133 public void commandSEND(byte command, byte b1, byte b2) {
134 var gwConfig = getGatewayConfig();
135 if (gwConfig != null) {
136 commonCommands.sendFORCEFrameT31SetPoint(gwConfig, this.getNode(), this.getSlot(), command, b1, b2);
140 public void commandSEND(byte b1, byte b2) {
141 var gwConfig = getGatewayConfig();
142 if (gwConfig != null) {
143 commonCommands.sendFORCEFrameT61SetPoint(gwConfig, this.getNode(), this.getSlot(), b1, b2);
148 * Create a time stamp as "yyyy-MM-dd'T'HH:mm:ssz"
150 * @return String timestamp
152 private static String getTimestamp() {
153 // Pattern : yyyy-MM-dd'T'HH:mm:ssz
154 var sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz");
156 return sdf.format(n.getTime());
160 public void thingUpdated(Thing thing) {
164 public @Nullable GatewayConfig getGatewayConfig() {
165 var bridge = getBridge();
166 if (bridge != null) {
167 SoulissGatewayHandler bridgeHandler = (SoulissGatewayHandler) bridge.getHandler();
168 if (bridgeHandler != null) {
169 return bridgeHandler.getGwConfig();
175 public @Nullable String getLabel() {
176 return getThing().getLabel();
179 public void setHealthy(byte shHealthy) {
180 this.updateState(SoulissBindingConstants.HEALTHY_CHANNEL, new DecimalType(shHealthy & 0xFF));
181 this.updateStatus(ThingStatus.ONLINE);
184 public void setLastStatusStored() {
185 this.updateState(SoulissBindingConstants.LASTSTATUSSTORED_CHANNEL, DateTimeType.valueOf(getTimestamp()));
188 protected @Nullable OnOffType getOhStateOnOffFromSoulissVal(byte sVal) {
189 if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
191 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
192 return OnOffType.OFF;
193 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_FEEDBACK) {
195 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_FEEDBACK) {
196 return OnOffType.OFF;
197 } else if (sVal == SoulissProtocolConstants.SOULISS_T4N_NOT_ARMED) {
198 return OnOffType.OFF;
199 } else if (sVal == SoulissProtocolConstants.SOULISS_T4N_ARMED) {
206 protected @Nullable OpenClosedType getOhStateOpenCloseFromSoulissVal(byte sVal) {
207 if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
208 return OpenClosedType.CLOSED;
209 } else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
210 return OpenClosedType.OPEN;