[souliss] Souliss Binding initial contribution (#11083)

* Initial Contribution

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update pom.xml

spotless-apply

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Renamed healty in healthy (simple word error)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

onOff to CamelCase
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* camelCase fixed on some types

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed camelCase on thhings parameters

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

fixed label cases
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Revert "Update thing-types.xml"

This reverts commit 5c19fbc69dee53f41d56a847bc82660192e0158c.

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Initial Contribution

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Fix some errors (Nullable issues) and pom.xml format

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update pom.xml

spotless-apply

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT11Handler.java

Default case on switch (handlecommand )

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* added secoresend to t31 skeleton and variable smessage fix declaration

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Initial Contribution

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update pom.xml

spotless-apply

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>
Co-Authored-By: Tonino Fazio <fazioa@gmail.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

Cutted comments and uneccessary log on gw status

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Renamed healty in healthy (simple word error)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed camelCase on thhings parameters

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* cleanup and quality code fixes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissBindingUDPDecoder.java

fixed some npe

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* npe check fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissCommonCommands.java

Remove comments unused code

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissCommonCommands.java

commented out code unused

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissCommonCommands.java

remove unused code commented out
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissBindingUDPServerJob.java

remove unused code comments
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissBindingSendDispatcherJob.java

fixed logger trace and remove unused code comments
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* removed completely unnecessary comments

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed some thing types cases

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

removed unnecessary log line
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

removed unnecessary comment
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* loggers as final !

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayJobHealthy.java

removed unnecessary logs

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayJobPing.java

removed unnecessary logs
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed redundancy on types checks

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

fixed examples parms
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

changed parm var name bridge
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/src/main/java/org/openhab/binding/souliss/handler/SoulissT11Handler.java

remove comments

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/src/main/java/org/openhab/binding/souliss/handler/SoulissT12Handler.java

comments removed

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/src/main/java/org/openhab/binding/souliss/handler/SoulissT13Handler.java

comments removed

Co-authored-by: Matthew Skinner <matt@pcmus.com>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed thing type on README and some case on xml thing types

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

cutted part about manually thing config specs on README . Who use oh already knows it .
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Code cleanup and optimizations based on @Skinah tips

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixes from @Skinah suggestions

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

Fixed typeid's on costants files

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various optimizations follow @Skinah tips (thanks!)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* spotless:apply fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixes constants and channel id types of t31

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Fix various NPE warnings

Fixes many ... Some added suppresswarnings.
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGenericActionMessage.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Refactor handlers into souliss.internal.handler

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* spoless:apply fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* spotless:apply

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fix t19 (securesend parm ,labels and setvalue)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

spotless:apply fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* spotless:apply fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Null checks Warnings removed

(mitigated with local copy of field)  - removed comments

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* syntax sugar fixed of consts and section removed from README

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* moved files to internal package

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissHandlerFactory.java

check types on object and not on strings

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various fixes based on @fwolter

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Gateway ip address regex on config param

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* changed description of gateway ip on param

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* formatted tables in README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* removed comments

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip for npe checks - breaking functionality :-(

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* spotless fix Author: Luca Calcaterra <calcaterra.luca@gmail.com>

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fix contrib header in some files

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* reworked udp - only one bridge allowed and  UDP  listen only to bridge port 230

...passing datagramsocket  with soulissnetworkparameter class

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* quite ok. Where to close socket in case of thread interruption ?

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip2

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip3 udp receive but not on vpn

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Classes names Refactor

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* replaced datagramsocket with nio socket- seems to be ok

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update UDPListenDiscoverRunnable.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Fixed some null checks removed securesend option (only t11 end similar)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* dummy initial value of raw values - removed thread on decoder line

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fix t19 ex catch and broadcast function

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Reworked Config of Gateway as Class (todo check nulls...)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Added representation property on gw - some cleanups

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

cleanup unused vars

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* refactor methods of gw parameters

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP to remove NetworkParameter class

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip refactor DiscoverResult

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip remove networkparameters

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP remove NetworkParameter Class. Things online only on a health message

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP Fix Topics

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP2 Fix topics

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update pom.xml

upgrade  binding version to 3.2 snapshot
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* topics bound to bridge - seems to be ok.

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* remove NetworkParameters class - topics ok but need parse rework

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* code cleanup and bugs check fix

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Add node and slot to property - other fixes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* change default interval subscription -cleanup constants

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP WAN Address gw

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WAN option external network. Fixed Putin on commands - to test well

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* cleanup - safesend check WIP

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed secursend for t11-18

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP Fix null checks

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGenericHandler.java

fixed wrong assignment of prop
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* null checks fixes for code quality

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixed listen port according to gw parm (default 23000)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* nuances

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

changed default values
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* CommonCommands to static - other fixes .

seems quite ok, remain T31 to fix (securesend)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update UDPListenDiscoverRunnable.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

changed executor imp for udp
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* restored commoncommands non static

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SendDispatcherRunnable.java

safesendcheck fix (not really)
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various nuances (sonarlint)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

removed explain how oh works on example
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/README.md

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update bundles/org.openhab.binding.souliss/src/main/feature/feature.xml

Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* @fwolter various fixes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT11Handler.java

wrong header

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT11Handler.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fix headers descriptions before authors on all classes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* all var on begin of classes and @nullable sugar syntax

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* removed @nullable on local vars

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip comments translations and cleanup

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* cleanup comments and translated them (if italian occourred)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* @fwolter suggestions for approval...various fixes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various fixes based on @fwolter suggestions.

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various fixes based on @fwolter suggestions.

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayHandler.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update UDPListenDiscoverRunnable.java

hexutils usage
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT22Handler.java

removed unused method
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT22Handler.java

fix previous commit
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissT11Handler.java

@Nullable on configuration
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* method to put bridge offline (network exception on listener)

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

changed some channels to trigger type
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* WIP broken

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update thing-types.xml

spotless:apply
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* various changes

call super on initialize() of all handlers. Changed to QuantityType where appliable
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGatewayDiscovery.java

added uniqueId (ip of gateway+node+slot) as representationProperty
Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* wip for load discovery component

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* big fixes and code quality improvments

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* fixes

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update SoulissGenericHandler.java

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

* Update README.md

wrong format ..

Signed-off-by: Luca Calcaterra <calcaterra.luca@gmail.com>

Co-authored-by: Tonino Fazio <fazioa@gmail.com>
Co-authored-by: Matthew Skinner <matt@pcmus.com>
Co-authored-by: Fabian Wolter <github@fabian-wolter.de>
This commit is contained in:
Luca Calcaterra
2021-10-17 13:31:36 +02:00
committed by GitHub
parent 31668b3891
commit 649c865c16
62 changed files with 8103 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.souliss-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-souliss" description="Souliss Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.souliss/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,210 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link SoulissBinding} class defines common constants, which are
* used across the whole binding.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public final class SoulissBindingConstants {
public static final String BINDING_ID = "souliss";
public static final long DISCOVERY_RESEND_TIMEOUT_IN_SECONDS = 45;
public static final int DISCOVERY_TIMEOUT_IN_SECONDS = 120;
public static final long SEND_DISPATCHER_MIN_DELAY_CYCLE_IN_MILLIS = 500;
// List of all Thing Type UIDs
public static final ThingTypeUID GATEWAY_THING_TYPE = new ThingTypeUID(BINDING_ID, "gateway");
public static final String T11 = "t11";
public static final String T12 = "t12";
public static final String T13 = "t13";
public static final String T14 = "t14";
public static final String T16 = "t16";
public static final String T18 = "t18";
public static final String T19 = "t19";
public static final String T1A = "t1a";
public static final String T21 = "t21";
public static final String T22 = "t22";
public static final String T31 = "t31";
public static final String T41 = "t41";
public static final String T42 = "t42";
public static final String T51 = "t51";
public static final String T52 = "t52";
public static final String T53 = "t53";
public static final String T54 = "t54";
public static final String T55 = "t55";
public static final String T56 = "t56";
public static final String T57 = "t57";
public static final String T58 = "t58";
public static final String T61 = "t61";
public static final String T62 = "t62";
public static final String T63 = "t63";
public static final String T64 = "t64";
public static final String T65 = "t65";
public static final String T66 = "t66";
public static final String T67 = "t67";
public static final String T68 = "t68";
public static final String TOPICS = "topic";
public static final ThingTypeUID T11_THING_TYPE = new ThingTypeUID(BINDING_ID, T11);
public static final ThingTypeUID T12_THING_TYPE = new ThingTypeUID(BINDING_ID, T12);
public static final ThingTypeUID T13_THING_TYPE = new ThingTypeUID(BINDING_ID, T13);
public static final ThingTypeUID T14_THING_TYPE = new ThingTypeUID(BINDING_ID, T14);
public static final ThingTypeUID T16_THING_TYPE = new ThingTypeUID(BINDING_ID, T16);
public static final ThingTypeUID T18_THING_TYPE = new ThingTypeUID(BINDING_ID, T18);
public static final ThingTypeUID T19_THING_TYPE = new ThingTypeUID(BINDING_ID, T19);
public static final ThingTypeUID T1A_THING_TYPE = new ThingTypeUID(BINDING_ID, T1A);
public static final ThingTypeUID T21_THING_TYPE = new ThingTypeUID(BINDING_ID, T21);
public static final ThingTypeUID T22_THING_TYPE = new ThingTypeUID(BINDING_ID, T22);
public static final ThingTypeUID T31_THING_TYPE = new ThingTypeUID(BINDING_ID, T31);
public static final ThingTypeUID T41_THING_TYPE = new ThingTypeUID(BINDING_ID, T41);
public static final ThingTypeUID T42_THING_TYPE = new ThingTypeUID(BINDING_ID, T42);
public static final ThingTypeUID T51_THING_TYPE = new ThingTypeUID(BINDING_ID, T51);
public static final ThingTypeUID T52_THING_TYPE = new ThingTypeUID(BINDING_ID, T52);
public static final ThingTypeUID T53_THING_TYPE = new ThingTypeUID(BINDING_ID, T53);
public static final ThingTypeUID T54_THING_TYPE = new ThingTypeUID(BINDING_ID, T54);
public static final ThingTypeUID T55_THING_TYPE = new ThingTypeUID(BINDING_ID, T55);
public static final ThingTypeUID T56_THING_TYPE = new ThingTypeUID(BINDING_ID, T56);
public static final ThingTypeUID T57_THING_TYPE = new ThingTypeUID(BINDING_ID, T57);
public static final ThingTypeUID T58_THING_TYPE = new ThingTypeUID(BINDING_ID, T58);
public static final ThingTypeUID T61_THING_TYPE = new ThingTypeUID(BINDING_ID, T61);
public static final ThingTypeUID T62_THING_TYPE = new ThingTypeUID(BINDING_ID, T62);
public static final ThingTypeUID T63_THING_TYPE = new ThingTypeUID(BINDING_ID, T63);
public static final ThingTypeUID T64_THING_TYPE = new ThingTypeUID(BINDING_ID, T64);
public static final ThingTypeUID T65_THING_TYPE = new ThingTypeUID(BINDING_ID, T65);
public static final ThingTypeUID T66_THING_TYPE = new ThingTypeUID(BINDING_ID, T66);
public static final ThingTypeUID T67_THING_TYPE = new ThingTypeUID(BINDING_ID, T67);
public static final ThingTypeUID T68_THING_TYPE = new ThingTypeUID(BINDING_ID, T68);
public static final ThingTypeUID TOPICS_THING_TYPE = new ThingTypeUID(BINDING_ID, TOPICS);
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(GATEWAY_THING_TYPE, T11_THING_TYPE,
T12_THING_TYPE, T13_THING_TYPE, T14_THING_TYPE, T16_THING_TYPE, T18_THING_TYPE, T19_THING_TYPE,
T1A_THING_TYPE, T21_THING_TYPE, T22_THING_TYPE, T31_THING_TYPE, T41_THING_TYPE, T42_THING_TYPE,
T51_THING_TYPE, T52_THING_TYPE, T53_THING_TYPE, T54_THING_TYPE, T55_THING_TYPE, T56_THING_TYPE,
T57_THING_TYPE, T58_THING_TYPE, T61_THING_TYPE, T62_THING_TYPE, T63_THING_TYPE, T64_THING_TYPE,
T65_THING_TYPE, T66_THING_TYPE, T67_THING_TYPE, T68_THING_TYPE, TOPICS_THING_TYPE);
// List of all Channel ids
public static final String ONOFF_CHANNEL = "onOff";
public static final String PULSE_CHANNEL = "pulse";
public static final String SLEEP_CHANNEL = "sleep";
public static final String AUTOMODE_CHANNEL = "autoMode";
public static final String STATEONOFF_CHANNEL = "stateOnOff";
public static final String STATEOPENCLOSE_CHANNEL = "stateOpenClose";
public static final String ROLLERSHUTTER_CHANNEL = "rollerShutter";
public static final String ROLLERSHUTTER_STATE_CHANNEL_CHANNEL = "rollerShutterState";
public static final String ROLLERSHUTTER_MESSAGE_OPENING_CHANNEL = "opening";
public static final String ROLLERSHUTTER_MESSAGE_CLOSING_CHANNEL = "closing";
public static final String ROLLERSHUTTER_MESSAGE_LIMITSWITCH_OPEN_CHANNEL = "limSwitchOpen";
public static final String ROLLERSHUTTER_MESSAGE_LIMITSWITCH_CLOSE_CHANNEL = "limSwitchClose";
public static final String ROLLERSHUTTER_MESSAGE_STATE_OPEN_CHANNEL = "stateOpen";
public static final String ROLLERSHUTTER_MESSAGE_STATE_CLOSE_CHANNEL = "stateClose";
public static final String ROLLERSHUTTER_MESSAGE_NO_LIMITSWITCH_CHANNEL = "NoLimSwitch";
public static final String ROLLERSHUTTER_MESSAGE_STOP_CHANNEL = "stop";
public static final String ROLLERSHUTTER_MESSAGE_TIMER_OFF = "timer off";
public static final String T1A_1_CHANNEL = "one";
public static final String T1A_2_CHANNEL = "two";
public static final String T1A_3_CHANNEL = "three";
public static final String T1A_4_CHANNEL = "four";
public static final String T1A_5_CHANNEL = "five";
public static final String T1A_6_CHANNEL = "six";
public static final String T1A_7_CHANNEL = "seven";
public static final String T1A_8_CHANNEL = "eight";
public static final String T31_MODE_CHANNEL = "mode";
public static final String T31_SYSTEM_CHANNEL = "system";
public static final String T31_FIRE_CHANNEL = "fire";
public static final String T31_FAN_CHANNEL = "fan";
public static final String T31_BUTTON_CHANNEL = "setAsMeasured";
public static final String T31_VALUE_CHANNEL = "measured";
public static final String T31_SETPOINT_CHANNEL = "setPoint";
public static final String T31_COOLINGMODE_MESSAGE_MODE_CHANNEL = "COOLING_MODE";
public static final String T31_HEATINGMODE_MESSAGE_MODE_CHANNEL = "HEATING_MODE";
public static final String T31_OFF_MESSAGE_SYSTEM_CHANNEL = "SYSTEM_OFF";
public static final String T31_ON_MESSAGE_SYSTEM_CHANNEL = "SYSTEM_ON";
public static final String T31_ON_MESSAGE_FIRE_CHANNEL = "FIRE_ON";
public static final String T31_OFF_MESSAGE_FIRE_CHANNEL = "FIRE_OFF";
public static final String T31_FANAUTO_MESSAGE_FAN_CHANNEL = "AUTO";
public static final String T31_FANOFF_MESSAGE_FAN_CHANNEL = "FANOFF";
public static final String T31_FANLOW_MESSAGE_FAN_CHANNEL = "LOW";
public static final String T31_FANMEDIUM_MESSAGE_FAN_CHANNEL = "MEDIUM";
public static final String T31_FANHIGH_MESSAGE_FAN_CHANNEL = "HIGH";
public static final String T4N_ONOFFALARM_CHANNEL = "onOffAlarm";
public static final String T4N_STATUSALARM_CHANNEL = "statusAlarm";
public static final String T4N_REARMALARM_CHANNEL = "rearmAlarm";
public static final String T41_RESETALARM_CHANNEL = "resetAlarm";
public static final String T4N_ALARMON_MESSAGE_CHANNEL = "ALARMON";
public static final String T4N_ALARMOFF_MESSAGE_CHANNEL = "ALARMOFF";
public static final String T4N_REARMOFF_MESSAGE_CHANNEL = "REARMOFF";
public static final String T4N_ARMED_MESSAGE_CHANNEL = "ARMED";
public static final String WHITE_MODE_CHANNEL = "whitemode";
public static final String ROLLER_BRIGHTNESS_CHANNEL = "rollerBrightness";
public static final String DIMMER_BRIGHTNESS_CHANNEL = "dimmerBrightness";
public static final String LED_COLOR_CHANNEL = "ledcolor";
public static final String LASTMESSAGE_CHANNEL = "lastMessage";
public static final String LASTSTATUSSTORED_CHANNEL = "lastStatusStored";
public static final String HEALTHY_CHANNEL = "healthy";
public static final String T5N_VALUE_CHANNEL = "value";
public static final String T6N_VALUE_CHANNEL = "value";
public static final String FLOATING_POINT_CHANNEL = "float";
public static final String HUMIDITY_CHANNEL = "humidity";
public static final String TEMPERATURE_CHANNEL = "temperature";
public static final String AMPERE_CHANNEL = "ampere";
public static final String VOLTAGE_CHANNEL = "voltage";
public static final String POWER_CHANNEL = "power";
public static final String CONFIG_ID = "ID";
public static final String CONFIG_IP_ADDRESS = "gatewayLanAddress";
public static final String UUID_NODE_SLOT_SEPARATOR = "-";
public static final String UUID_ELEMENTS_SEPARATOR = ":";
public static final String CONFIG_SLEEP = "sleep";
public static final String CONFIG_SECURE_SEND = "secureSend";
public static final String CONFIG_TIMEOUT_TO_REQUEUE = "timeoutToRequeue";
public static final String CONFIG_TIMEOUT_TO_REMOVE_PACKET = "timeoutToRemovePacket";
// Properties
public static final String PROPERTY_NODE = "node";
public static final String PROPERTY_SLOT = "slot";
public static final String PROPERTY_UNIQUEID = "uniqueId";
// private constructor
private SoulissBindingConstants() {
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal;
import java.net.DatagramSocket;
import java.net.SocketException;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
/**
* The {@link SoulissDatagramSocketFactory} is responsible for creating datagramSocket object for trasmission e
* receiving.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissDatagramSocketFactory {
public static @Nullable DatagramSocket getSocketDatagram(Logger logger) {
return getSocketDatagram(0, logger);
}
public static @Nullable DatagramSocket getSocketDatagram(int socketPortNumber, Logger logger) {
// return DatagramSocket for packet trasmission
DatagramSocket soulissDatagramSocket = null;
logger.debug("Setup socket");
try {
if (socketPortNumber != 0) {
soulissDatagramSocket = new DatagramSocket(socketPortNumber);
} else {
soulissDatagramSocket = new DatagramSocket();
}
logger.debug("Datagram Socket Created on port {}", soulissDatagramSocket.getLocalPort());
} catch (SocketException e) {
logger.warn("Error on creation of Socket: {}", e.getMessage());
}
return soulissDatagramSocket;
}
}

View File

@@ -0,0 +1,138 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal;
import static org.openhab.binding.souliss.internal.SoulissBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.binding.souliss.internal.handler.SoulissT11Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT12Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT13Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT14Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT16Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT18Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT19Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT1AHandler;
import org.openhab.binding.souliss.internal.handler.SoulissT22Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT31Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT41Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT42Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT51Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT52Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT53Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT54Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT55Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT56Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT57Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT61Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT62Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT63Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT64Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT65Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT66Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT67Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT68Handler;
import org.openhab.binding.souliss.internal.handler.SoulissTopicsHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link SoulissHandlerFactory} is responsible for creating things and thingGeneric
* handlers. It fire when a new thingGeneric is added.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
@Component(configurationPid = "binding.souliss", service = ThingHandlerFactory.class)
public class SoulissHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
var thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(GATEWAY_THING_TYPE)) {
return new SoulissGatewayHandler((Bridge) thing);
} else if (thingTypeUID.equals(T11_THING_TYPE)) {
return new SoulissT11Handler(thing);
} else if (thingTypeUID.equals(T12_THING_TYPE)) {
return new SoulissT12Handler(thing);
} else if (thingTypeUID.equals(T13_THING_TYPE)) {
return new SoulissT13Handler(thing);
} else if (thingTypeUID.equals(T14_THING_TYPE)) {
return new SoulissT14Handler(thing);
} else if (thingTypeUID.equals(T16_THING_TYPE)) {
return new SoulissT16Handler(thing);
} else if (thingTypeUID.equals(T18_THING_TYPE)) {
return new SoulissT18Handler(thing);
} else if (thingTypeUID.equals(T19_THING_TYPE)) {
return new SoulissT19Handler(thing);
} else if (thingTypeUID.equals(T1A_THING_TYPE)) {
return new SoulissT1AHandler(thing);
} else if (thingTypeUID.equals(T21_THING_TYPE) || (thingTypeUID.equals(T22_THING_TYPE))) {
return new SoulissT22Handler(thing);
} else if (thingTypeUID.equals(T31_THING_TYPE)) {
return new SoulissT31Handler(thing);
} else if (thingTypeUID.equals(T41_THING_TYPE)) {
return new SoulissT41Handler(thing);
} else if (thingTypeUID.equals(T42_THING_TYPE)) {
return new SoulissT42Handler(thing);
} else if (thingTypeUID.equals(T51_THING_TYPE)) {
return new SoulissT51Handler(thing);
} else if (thingTypeUID.equals(T52_THING_TYPE)) {
return new SoulissT52Handler(thing);
} else if (thingTypeUID.equals(T53_THING_TYPE)) {
return new SoulissT53Handler(thing);
} else if (thingTypeUID.equals(T54_THING_TYPE)) {
return new SoulissT54Handler(thing);
} else if (thingTypeUID.equals(T55_THING_TYPE)) {
return new SoulissT55Handler(thing);
} else if (thingTypeUID.equals(T56_THING_TYPE)) {
return new SoulissT56Handler(thing);
} else if (thingTypeUID.equals(T57_THING_TYPE)) {
return new SoulissT57Handler(thing);
} else if (thingTypeUID.equals(T61_THING_TYPE)) {
return new SoulissT61Handler(thing);
} else if (thingTypeUID.equals(T62_THING_TYPE)) {
return new SoulissT62Handler(thing);
} else if (thingTypeUID.equals(T63_THING_TYPE)) {
return new SoulissT63Handler(thing);
} else if (thingTypeUID.equals(T64_THING_TYPE)) {
return new SoulissT64Handler(thing);
} else if (thingTypeUID.equals(T65_THING_TYPE)) {
return new SoulissT65Handler(thing);
} else if (thingTypeUID.equals(T66_THING_TYPE)) {
return new SoulissT66Handler(thing);
} else if (thingTypeUID.equals(T67_THING_TYPE)) {
return new SoulissT67Handler(thing);
} else if (thingTypeUID.equals(T68_THING_TYPE)) {
return new SoulissT68Handler(thing);
} else if (thingTypeUID.equals(TOPICS_THING_TYPE)) {
return new SoulissTopicsHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,309 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* the class {@link SoulissProtocolConstants} class contains Souliss constants. Original version is taken from
* SoulissApp. For scope of this binding not all constants are used.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Alessandro Del Pex - soulissapp
* @author Tonino Fazio - @since 1.7.0
* @author Luca Remigio - @since 2.0.0
*
*/
@NonNullByDefault
public final class SoulissProtocolConstants {
public static final String TAG = "SoulissApp:Typicals";
/**
* /** // Defines for Typicals C LIBRARY
*
* #define SOULISS_T31 31 // Temperature control #define Souliss_T41 41 //
* Anti-theft integration (Main) #define Souliss_T42 42 // Anti-theft
* integration (Peer)
*/
public static final byte SOULISS_T_EMPTY = 0;
public static final byte SOULISS_T_RELATED = (byte) 0xFF;
public static final byte SOULISS_TSERVICE_NODE_HEALTHY = (byte) 0x98;
public static final byte SOULISS_TSERVICE_NODE_TIMESTAMP = (byte) 0x99;
public static final int SOULISS_TSERVICE_NODE_HEALTHY_VIRTUAL_SLOT = 998;
public static final int SOULISS_TSERVICE_NODE_TIMESTAMP_VIRTUAL_SLOT = 999;
// Defines for Typicals
public static final byte SOULISS_T11 = 0x11;
public static final byte SOULISS_T12 = 0x12;
public static final byte SOULISS_T13 = 0x13;
public static final byte SOULISS_T14 = 0x14;
// RGB Light
public static final byte SOULISS_T1N_RGB = 0x15;
public static final byte SOULISS_T16 = 0x16;
public static final byte SOULISS_T18 = 0x18;
public static final byte SOULISS_T19 = 0x19;
public static final byte SOULISS_T1A = 0x1A;
// Motorized devices with limit switches
public static final byte SOULISS_T21 = 0x21;
// Motorized devices with limit switches and middle position
public static final byte SOULISS_T22 = 0x22;
public static final byte SOULISS_T31 = 0x31;
public static final byte SOULISS_T32_IRCOM_AIRCON = 0x32;
// Anti-theft group (used with massive commands)
public static final byte SOULISS_T42_ANTITHEFT_GROUP = 0x40;
// Anti-theft integration (Main)
public static final byte SOULISS_T41_ANTITHEFT_MAIN = 0x41;
// Anti-theft integration (Peer)
public static final byte SOULISS_T42_ANTITHEFT_PEER = 0x42;
public static final byte SOULISS_T51 = 0x51;
public static final byte SOULISS_T52_TEMPERATURE_SENSOR = 0x52;
public static final byte SOULISS_T53_HUMIDITY_SENSOR = 0x53;
public static final byte SOULISS_T54_LUX_SENSOR = 0x54;
public static final byte SOULISS_T55_VOLTAGE_SENSOR = 0x55;
public static final byte SOULISS_T56_CURRENT_SENSOR = 0x56;
public static final byte SOULISS_T57_POWER_SENSOR = 0x57;
public static final byte SOULISS_T58_PRESSURE_SENSOR = 0x58;
public static final byte SOULISS_T61 = 0x61;
public static final byte SOULISS_T62_TEMPERATURE_SENSOR = 0x62;
public static final byte SOULISS_T63_HUMIDITY_SENSOR = 0x63;
public static final byte SOULISS_T64_LUX_SENSOR = 0x64;
public static final byte SOULISS_T65_VOLTAGE_SENSOR = 0x65;
public static final byte SOULISS_T66_CURRENT_SENSOR = 0x66;
public static final byte SOULISS_T67_POWER_SENSOR = 0x67;
public static final byte SOULISS_T68_PRESSURE_SENSOR = 0x68;
public static final byte SOULISS_TOPICS = 0x72;
// customized (remote) AirCon commands
public static final int SOULISS_T_IRCOM_AIRCON_POW_ON = 0x8FFE;
public static final int SOULISS_T_IRCOM_AIRCON_POW_AUTO_20 = 0x8FFD;
public static final int SOULISS_T_IRCOM_AIRCON_POW_AUTO_24 = 0x8FFE;
public static final int SOULISS_T_IRCOM_AIRCON_POW_COOL_18 = 0x807B;
public static final int SOULISS_T_IRCOM_AIRCON_POW_COOL_22 = 0x8079;
public static final int SOULISS_T_IRCOM_AIRCON_POW_COOL_26 = 0x807A;
public static final int SOULISS_T_IRCOM_AIRCON_POW_FAN = 0x8733;
public static final int SOULISS_T_IRCOM_AIRCON_POW_DRY = 0x87BE;
public static final int SOULISS_T_IRCOM_AIRCON_POW_OFF = 0x70FE;
// Souliss Aircon Temperature
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_16C = 0xF;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_17C = 0x7;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_18C = 0xB;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_19C = 0x3;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_20C = 0xD;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_21C = 0x5;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_22C = 0x9;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_23C = 0x1;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_24C = 0xE;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_25C = 0x6;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_26C = 0xA;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_27C = 0x2;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_28C = 0xC;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_29C = 0x4;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_30C = 0x8;
// Souliss conditioner Function
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FUN_AAUTO = 0xF;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FUN_DRY = 0xB;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FUN_FAN = 0x3;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FUN_HEAT = 0xD;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FUN_COOL = 0x7;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FAN_AUTO = 0x7;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FAN_HIGH = 0x2;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FAN_MEDIUM = 0x6;
public static final byte SOULISS_T_IRCOM_AIRCON_TEMP_FAN_LOW = 0x5;
// optional switches. May be used to toggle
// custom aircon functions as air deflector, ionizer, turbomode, etc.
public static final byte SOULISS_T_IRCOM_AIRCON_OPT1 = 0x2D;
public static final byte SOULISS_T_IRCOM_AIRCON_OPT2 = 0x77;
public static final byte SOULISS_T_IRCOM_AIRCON_RESET = 0x00;
// General defines for T1n
public static final byte SOULISS_T1N_TOGGLE_CMD = 0x01;
public static final byte SOULISS_T1N_ON_CMD = 0x02;
public static final byte SOULISS_T1N_OFF_CMD = 0x04;
public static final byte SOULISS_T1N_AUTO_CMD = 0x08;
public static final byte SOULISS_T1N_TIMED = 0x30;
public static final byte SOULISS_T1N_RST_CMD = 0x00;
public static final byte SOULISS_T1N_ON_COIL = 0x01;
public static final byte SOULISS_T1N_OFF_COIL = 0x00;
public static final byte SOULISS_T1N_ON_COIL_AUTO = (byte) 0xF1;
public static final byte SOULISS_T1N_OFF_COIL_AUTO = (byte) 0xF0;
// Set a state
public static final byte SOULISS_T1N_SET = 0x22;
// Increase Light
public static final byte SOULISS_T1N_BRIGHT_UP = 0x10;
// Decrease Light
public static final byte SOULISS_T1N_BRIGHT_DOWN = 0x20;
// Flash Light
public static final byte SOULISS_T1N_FLASH = 0x21;
public static final byte SOULISS_T1N_ON_FEEDBACK = 0x23;
public static final byte SOULISS_T1N_OFF_FEEDBACK = 0x24;
public static final String SOULISS_T12_USE_OF_SLOT_AUTO_MODE = "autoMode";
public static final String SOULISS_T12_USE_OF_SLOT_SWITCH = "switch";
// Set a state
public static final long SOULISS_T16_RED = 0x22FF0000;
public static final long SOULISS_T16_GREEN = 0x2200FF00;
public static final long SOULISS_T16_BLUE = 0x220000FF;
public static final long SOULISS_T18_PULSE = 0xA1;
/*
* IR RGB Typical
*/
public static final byte SOULISS_T1N_RGB_ON_CMD = 0x1;
public static final byte SOULISS_T1N_RGB_OFF_CMD = 0x9;
// Souliss RGB main colours
public static final byte SOULISS_T1N_RGB_R = 0x2;
public static final byte SOULISS_T1N_RGB_G = 0x3;
public static final byte SOULISS_T1N_RGB_B = 0x4;
public static final byte SOULISS_T1N_RGB_W = 0x5;
// Souliss RGB Controls
public static final byte SOULISS_T_IRCOM_RGB_BRIGHT_UP = 0x6;
public static final byte SOULISS_T_IRCOM_RGB_BRIGHT_DOWN = 0x7;
// MODES
public static final byte SOULISS_T_IRCOM_RGB_MODE_FLASH = (byte) 0xA1;
public static final byte SOULISS_T_IRCOM_RGB_MODE_STROBE = (byte) 0xA2;
public static final byte SOULISS_T_IRCOM_RGB_MODE_FADE = (byte) 0xA3;
public static final byte SOULISS_T_IRCOM_RGB_MODE_SMOOTH = (byte) 0xA4;
public static final byte SOULISS_T1N_RGB_R2 = (byte) 0xB1;
public static final byte SOULISS_T1N_RGB_R3 = (byte) 0xB2;
public static final byte SOULISS_T1N_RGB_R4 = (byte) 0xB3;
public static final byte SOULISS_T1N_RGB_R5 = (byte) 0xB4;
public static final byte SOULISS_T1N_RGB_G2 = (byte) 0xC1;
public static final byte SOULISS_T1N_RGB_G3 = (byte) 0xC2;
public static final byte SOULISS_T1N_RGB_G4 = (byte) 0xC3;
public static final byte SOULISS_T1N_RGB_G5 = (byte) 0xC4;
public static final byte SOULISS_T1N_RGB_B2 = (byte) 0xD1;
public static final byte SOULISS_T1N_RGB_B3 = (byte) 0xD2;
public static final byte SOULISS_T1N_RGB_B4 = (byte) 0xD3;
public static final byte SOULISS_T1N_RGB_B5 = (byte) 0xD4;
public static final byte SOULISS_T1N_RGB_RST_CMD = 0x00;
// Defines for Typical 2n
public static final byte SOULISS_T2N_CLOSE_CMD = 0x01;
public static final byte SOULISS_T2N_OPEN_CMD = 0x02;
public static final byte SOULISS_T2N_STOP_CMD = 0x04;
// Close Command (only from local pushbutton)
public static final byte SOULISS_T2N_CLOSE_CMD_LOCAL = 0x08;
// Open Command (only from local pushbutton)
public static final byte SOULISS_T2N_OPEN_CMD_LOCAL = 0x10;
public static final byte SOULISS_T2N_TOGGLE_CMD = 0x08;
public static final byte SOULISS_T2N_RST_CMD = 0x00;
// Timer set value
public static final byte SOULISS_T2N_TIMER_VAL = (byte) 0xC0;
// Timer expired value
public static final byte SOULISS_T2N_TIMER_OFF = (byte) 0xA0;
// Timed stop value
public static final byte SOULISS_T2N_TIMEDSTOP_VAL = (byte) 0xC2;
// Timed stop exipred value
public static final byte SOULISS_T2N_TIMEDSTOP_OFF = (byte) 0xC0;
public static final byte SOULISS_T2N_LIMSWITCH_CLOSE = 0x14;
public static final byte SOULISS_T2N_LIMSWITCH_OPEN = 0x16;
// Close Feedback from Limit Switch
public static final byte SOULISS_T2N_STATE_CLOSE = 0x08;
// Open Feedback from Limit Switch
public static final byte SOULISS_T2N_STATE_OPEN = 0x10;
public static final byte SOULISS_T2N_NOLIMSWITCH = 0x20;
public static final byte SOULISS_T2N_COIL_CLOSE = 0x01;
public static final byte SOULISS_T2N_COIL_OPEN = 0x02;
public static final byte SOULISS_T2N_COIL_STOP = 0x03;
public static final byte SOULISS_T2N_COIL_OFF = 0x00;
// General defines for T3n
public static final String SOULISS_T31_USE_OF_SLOT_SETPOINT = "setPoint";
public static final String SOULISS_T31_USE_OF_SLOT_MEASURED = "measured";
public static final String SOULISS_T31_USE_OF_SLOT_SETASMEASURED = "setAsMeasured";
public static final byte SOULISS_T31_USE_OF_SLOT_SETPOINT_COMMAND = 0x0C;
public static final byte SOULISS_T31_USE_OF_SLOT_HEATING = 0x05;
public static final byte SOULISS_T31_USE_OF_SLOT_COOLING = 0x04;
public static final String SOULISS_T31_USE_OF_SLOT_HEATING_COOLING = "heatingCooling";
public static final byte SOULISS_T31_USE_OF_SLOT_FAN_OFF = 0x06;
public static final byte SOULISS_T31_USE_OF_SLOT_FAN_LOW = 0x07;
public static final byte SOULISS_T31_USE_OF_SLOT_FAN_MED = 0x08;
public static final byte SOULISS_T31_USE_OF_SLOT_FAN_HIGH = 0x09;
public static final byte SOULISS_T31_USE_OF_SLOT_FAN_AUTOMODE = 0x0A;
public static final String SOULISS_T31_USE_OF_SLOT_POWER = "power";
public static final byte SOULISS_T3N_IN_SETPOINT = 0x01;
public static final byte SOULISS_T3N_OUT_SETPOINT = 0x02;
public static final byte SOULISS_T3N_AS_MEASURED = 0x03;
public static final byte SOULISS_T3N_COOLING = 0x04;
public static final byte SOULISS_T3N_HEATING = 0x05;
public static final byte SOULISS_T3N_FAN_OFF = 0x06;
public static final byte SOULISS_T3N_FAN_LOW = 0x07;
public static final byte SOULISS_T3N_FAN_MED = 0x08;
public static final byte SOULISS_T3N_FAN_HIGH = 0x09;
public static final byte SOULISS_T3N_FAN_AUTO = 0x0A;
public static final byte SOULISS_T3N_FAN_MANUAL = 0x0B;
public static final byte SOULISS_T3N_SET_TEMP = 0x0C;
public static final byte SOULISS_T3N_SHUTDOWN = 0x0D;
public static final String SOULISS_T3N_HEATING_ON = "0x02";
public static final String SOULISS_T3N_COOLING_ON = "0x03";
public static final String SOULISS_T3N_FAN_ON_1 = "0x08";
public static final String SOULISS_T3N_FAN_ON_2 = "0x10";
public static final String SOULISS_T3N_FAN_ON_3 = "0x20";
// General defines for T4n
// Alarm Condition Detected (Input)
public static final byte SOULISS_T4N_ALARM = 0x01;
public static final byte SOULISS_T4N_RST_CMD = 0x00;
// Silence and Arm Command
public static final byte SOULISS_T4N_REARM = 0x03;
// Anti-theft not Armed Command
public static final byte SOULISS_T4N_NOT_ARMED = 0x04;
// Anti-theft Armed Command
public static final byte SOULISS_T4N_ARMED = 0x05;
// Anti-theft Armed Feedback
public static final byte SOULISS_T4N_ANTITHEFT = 0x01;
// Anti-theft not Armed Feedback
public static final byte SOULISS_T4N_NO_ANTITHEFT = 0x00;
// Anti-theft in Alarm
public static final byte SOULISS_T4N_IN_ALARM = 0x03;
public static final byte SOULISS_RST_CMD = 0x00;
public static final byte SOULISS_NOT_TRIGGED = 0x00;
public static final byte SOULISS_TRIGGED = 0x01;
// Defines for current sensor
public static final byte SOULISS_T_CURRENT_SENSOR = 0x65;
// REMOVE THESE
public static final byte SOULISS_T_TEMPERATURE_SENSOR = 0x67;
public static final byte SOULISS_T_TEMPERATURE_SENSOR_REFRESH = 0x02;
public static final byte SOULISS_T_HUMIDITY_SENSOR = 0x69;
public static final byte SOULISS_T_HUMIDITY_SENSOR_REFRESH = 0x03;
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Network constants. The class {@link SoulissUDPConstants} contains Souliss constants. Original version is
* taken from SoulissApp. For scope of this binding not all constants are used.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Alessandro Del Pex - @since 1.7.0
*/
@NonNullByDefault
public class SoulissUDPConstants {
public static final String TAG = "SoulissApp";
public static final int SOULISS_BINDING_LOCAL_PORT = 0;
public static final int SOULISS_GATEWAY_DEFAULT_PORT = 230;
public static final Integer SOULISS_DEFAULT_NODE_INDEX = 70;
public static final Integer SOULISS_DEFAULT_USER_INDEX = 120;
public static final String BROADCASTADDR = "255.255.255.255";
public static final byte SOULISS_UDP_FUNCTION_FORCE = 0x33;
public static final byte SOULISS_UDP_FUNCTION_FORCE_MASSIVE = 0x34;
public static final byte SOULISS_UDP_FUNCTION_SUBSCRIBE_REQ = 0x21;
public static final byte SOULISS_UDP_FUNCTION_SUBSCRIBE_RESP = 0x31;
public static final byte SOULISS_UDP_FUNCTION_POLL_REQ = 0x27;
public static final byte SOULISS_UDP_FUNCTION_POLL_RESP = 0x37;
public static final byte SOULISS_UDP_FUNCTION_TYP_REQ = 0x22;
public static final byte SOULISS_UDP_FUNCTION_TYP_RESP = 0x32;
public static final byte SOULISS_UDP_FUNCTION_HEALTHY_REQ = 0x25;
public static final byte SOULISS_UDP_FUNCTION_HEALTHY_RESP = 0x35;
public static final byte SOULISS_UDP_FUNCTION_PING_REQ = 0x8;
public static final byte SOULISS_UDP_FUNCTION_PING_RESP = 0x18;
public static final byte SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_REQ = 0x28;
public static final byte SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_RESP = 0x38;
public static final int SOULISS_UDP_FUNCTION_DBSTRUCT_REQ = 0x26;
public static final int SOULISS_UDP_FUNCTION_DBSTRUCT_RESP = 0x36;
public static final int SOULISS_UDP_FUNCTION_ACTION_MESSAGE = 0x72;
protected static final Byte[] PING_PAYLOAD = { SOULISS_UDP_FUNCTION_PING_REQ, 0, 0, 0, 0 };
protected static final Byte[] PING_DISCOVER_BCAST_PAYLOAD = { SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_REQ, 0, 0,
0, 0 };
protected static final Byte[] DBSTRUCT_PAYLOAD = { SOULISS_UDP_FUNCTION_DBSTRUCT_REQ, 0, 0, 0, 0 };
// private constructor
private SoulissUDPConstants() {
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link GatewayConfig} is responsible for holding souliss gateway config
*
* @author Luca Calcaterra - Initial Contribution
*/
@NonNullByDefault
public final class GatewayConfig {
public int pingInterval;
public int subscriptionInterval;
public int healthyInterval;
public int sendInterval;
public int timeoutToRequeue;
public int timeoutToRemovePacket;
public int preferredLocalPortNumber;
public int gatewayPortNumber;
public int userIndex;
public int nodeIndex;
public String gatewayLanAddress = "";
public String gatewayWanAddress = "";
}

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.discovery;
import java.net.InetAddress;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Result callback interface.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public interface DiscoverResult {
static boolean IS_GATEWAY_DETECTED = false;
void gatewayDetected(InetAddress addr, String id);
void thingDetectedTypicals(byte lastByteGatewayIP, byte typical, byte node, byte slot);
void thingDetectedActionMessages(String sTopicNumber, String sTopicVariant);
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.discovery;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.binding.souliss.internal.protocol.CommonCommands;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissDiscoverJob implements Runnable {
private final Logger logger = LoggerFactory.getLogger(SoulissDiscoverJob.class);
private final CommonCommands commonCommands = new CommonCommands();
private int resendCounter = 0;
private @Nullable SoulissGatewayHandler gwHandler;
public SoulissDiscoverJob(@Nullable SoulissGatewayHandler soulissGwHandler) {
this.gwHandler = soulissGwHandler;
}
@Override
public void run() {
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
commonCommands.sendDBStructFrame(localGwHandler.getGwConfig());
logger.debug("Sending request to gateway for souliss network - Counter={}", resendCounter);
} else {
logger.debug("Gateway null - Skipped");
}
resendCounter++;
}
}

View File

@@ -0,0 +1,277 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.discovery;
import java.net.InetAddress;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link soulissHandlerFactory} is responsible for creating things and thingGeneric
* handlers.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissGatewayDiscovery extends AbstractDiscoveryService
implements DiscoverResult, DiscoveryService, ThingHandlerService {
private @Nullable ScheduledFuture<?> discoveryJob = null;
private final Logger logger = LoggerFactory.getLogger(SoulissGatewayDiscovery.class);
private @Nullable SoulissDiscoverJob soulissDiscoverRunnableClass = null;
private @Nullable SoulissGatewayHandler soulissGwHandler;
public SoulissGatewayDiscovery() {
super(SoulissBindingConstants.SUPPORTED_THING_TYPES_UIDS, SoulissBindingConstants.DISCOVERY_TIMEOUT_IN_SECONDS,
false);
}
@Override
public void deactivate() {
super.deactivate();
}
/**
* The {@link gatewayDetected} callback used to create the Gateway
*/
@Override
public void gatewayDetected(InetAddress addr, String id) {
logger.debug("Souliss gateway found: {} ", addr.getHostName());
String label = "Souliss Gateway " + (Byte.parseByte(id) & 0xFF);
Map<String, Object> properties = new TreeMap<>();
properties.put(SoulissBindingConstants.CONFIG_IP_ADDRESS, addr.getHostAddress());
var gatewayUID = new ThingUID(SoulissBindingConstants.GATEWAY_THING_TYPE,
Integer.toString((Byte.parseByte(id) & 0xFF)));
var discoveryResult = DiscoveryResultBuilder.create(gatewayUID).withLabel(label)
.withRepresentationProperty(SoulissBindingConstants.CONFIG_IP_ADDRESS).withProperties(properties)
.build();
thingDiscovered(discoveryResult);
}
@Override
protected void startScan() {
logger.debug("Starting Scan Service");
// create discovery class
if (soulissDiscoverRunnableClass == null) {
soulissDiscoverRunnableClass = new SoulissDiscoverJob(this.soulissGwHandler);
// send command for gw struct (typicals).. must be not soo much quick..
discoveryJob = scheduler.scheduleWithFixedDelay(soulissDiscoverRunnableClass, 2,
SoulissBindingConstants.DISCOVERY_RESEND_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
logger.debug("Start Discovery Job");
}
}
@Override
protected synchronized void stopScan() {
ScheduledFuture<?> localDiscoveryJob = this.discoveryJob;
if (localDiscoveryJob != null) {
localDiscoveryJob.cancel(false);
soulissDiscoverRunnableClass = null;
logger.debug("Discovery Job Stopped");
}
super.stopScan();
}
@Override
public void thingDetectedActionMessages(String topicNumber, String sTopicVariant) {
ThingUID thingUID = null;
var label = "";
DiscoveryResult discoveryResult;
String sNodeID = topicNumber + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + sTopicVariant;
var localGwHandler = this.soulissGwHandler;
if (localGwHandler != null) {
var gatewayUID = localGwHandler.getThing().getUID();
thingUID = new ThingUID(SoulissBindingConstants.TOPICS_THING_TYPE, gatewayUID, sNodeID);
label = "Topic. Number: " + topicNumber + ", Variant: " + sTopicVariant;
discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(label)
.withProperty("number", topicNumber).withProperty("variant", sTopicVariant)
.withRepresentationProperty("number").withBridge(gatewayUID).build();
thingDiscovered(discoveryResult);
}
}
@Override
public void thingDetectedTypicals(byte lastByteGatewayIP, byte typical, byte node, byte slot) {
ThingUID thingUID = null;
var label = "";
DiscoveryResult discoveryResult;
var gwHandler = this.soulissGwHandler;
if ((gwHandler != null) && (lastByteGatewayIP == (byte) Integer
.parseInt(gwHandler.getGwConfig().gatewayLanAddress.split("\\.")[3]))) {
String sNodeId = node + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + slot;
ThingUID gatewayUID = gwHandler.getThing().getUID();
var slotLabel = "slot";
switch (typical) {
case SoulissProtocolConstants.SOULISS_T11:
thingUID = new ThingUID(SoulissBindingConstants.T11_THING_TYPE, gatewayUID, sNodeId);
label = "T11: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T12:
thingUID = new ThingUID(SoulissBindingConstants.T12_THING_TYPE, gatewayUID, sNodeId);
label = "T12: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T13:
thingUID = new ThingUID(SoulissBindingConstants.T13_THING_TYPE, gatewayUID, sNodeId);
label = "T13: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T14:
thingUID = new ThingUID(SoulissBindingConstants.T14_THING_TYPE, gatewayUID, sNodeId);
label = "T14: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T16:
thingUID = new ThingUID(SoulissBindingConstants.T16_THING_TYPE, gatewayUID, sNodeId);
label = "T16: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T18:
thingUID = new ThingUID(SoulissBindingConstants.T18_THING_TYPE, gatewayUID, sNodeId);
label = "T18: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T19:
thingUID = new ThingUID(SoulissBindingConstants.T19_THING_TYPE, gatewayUID, sNodeId);
label = "T19: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T1A:
thingUID = new ThingUID(SoulissBindingConstants.T1A_THING_TYPE, gatewayUID, sNodeId);
label = "T1A: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T21:
thingUID = new ThingUID(SoulissBindingConstants.T21_THING_TYPE, gatewayUID, sNodeId);
label = "T21: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T22:
thingUID = new ThingUID(SoulissBindingConstants.T22_THING_TYPE, gatewayUID, sNodeId);
label = "T22: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T41_ANTITHEFT_MAIN:
thingUID = new ThingUID(SoulissBindingConstants.T41_THING_TYPE, gatewayUID, sNodeId);
label = "T41: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T42_ANTITHEFT_PEER:
thingUID = new ThingUID(SoulissBindingConstants.T42_THING_TYPE, gatewayUID, sNodeId);
label = "T42: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T31:
thingUID = new ThingUID(SoulissBindingConstants.T31_THING_TYPE, gatewayUID, sNodeId);
label = "T31: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T52_TEMPERATURE_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T52_THING_TYPE, gatewayUID, sNodeId);
label = "T52: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T53_HUMIDITY_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T53_THING_TYPE, gatewayUID, sNodeId);
label = "T53: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T54_LUX_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T54_THING_TYPE, gatewayUID, sNodeId);
label = "T54: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T55_VOLTAGE_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T55_THING_TYPE, gatewayUID, sNodeId);
label = "T55: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T56_CURRENT_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T56_THING_TYPE, gatewayUID, sNodeId);
label = "T56: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T57_POWER_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T57_THING_TYPE, gatewayUID, sNodeId);
label = "T57: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T61:
thingUID = new ThingUID(SoulissBindingConstants.T61_THING_TYPE, gatewayUID, sNodeId);
label = "T61: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T62_TEMPERATURE_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T62_THING_TYPE, gatewayUID, sNodeId);
label = "T62: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T63_HUMIDITY_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T63_THING_TYPE, gatewayUID, sNodeId);
label = "T63: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T64_LUX_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T64_THING_TYPE, gatewayUID, sNodeId);
label = "T64: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T65_VOLTAGE_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T65_THING_TYPE, gatewayUID, sNodeId);
label = "T65: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T66_CURRENT_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T66_THING_TYPE, gatewayUID, sNodeId);
label = "T66: node " + node + slotLabel + slot;
break;
case SoulissProtocolConstants.SOULISS_T67_POWER_SENSOR:
thingUID = new ThingUID(SoulissBindingConstants.T67_THING_TYPE, gatewayUID, sNodeId);
label = "T67: node " + node + slotLabel + slot;
break;
default: {
logger.debug("no supported things found ...");
}
}
if (thingUID != null) {
label = "[" + gwHandler.getThing().getUID().getAsString() + "] " + label;
var uniqueId = "N" + Byte.toString(node) + "S" + Byte.toString(slot);
discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(label)
.withProperty(SoulissBindingConstants.PROPERTY_NODE, node)
.withProperty(SoulissBindingConstants.PROPERTY_SLOT, slot)
.withProperty(SoulissBindingConstants.PROPERTY_UNIQUEID, uniqueId)
.withRepresentationProperty(SoulissBindingConstants.PROPERTY_UNIQUEID)
.withBridge(gwHandler.getThing().getUID()).build();
thingDiscovered(discoveryResult);
gwHandler.setThereIsAThingDetection();
}
}
}
@Override
public void setThingHandler(ThingHandler handler) {
if (handler instanceof SoulissGatewayHandler) {
var localGwHandler = this.soulissGwHandler;
localGwHandler = (SoulissGatewayHandler) handler;
localGwHandler.discoverResult = this;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return soulissGwHandler;
}
}

View File

@@ -0,0 +1,248 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.config.GatewayConfig;
import org.openhab.binding.souliss.internal.discovery.DiscoverResult;
import org.openhab.binding.souliss.internal.discovery.SoulissGatewayDiscovery;
import org.openhab.binding.souliss.internal.protocol.CommonCommands;
import org.openhab.binding.souliss.internal.protocol.SendDispatcherRunnable;
import org.openhab.binding.souliss.internal.protocol.UDPListenDiscoverRunnable;
import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SoulissGatewayHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissGatewayHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(SoulissGatewayHandler.class);
private final CommonCommands commonCommands = new CommonCommands();
private @Nullable ExecutorService udpExecutorService;
private @Nullable Future<?> udpListenerJob;
private @Nullable ScheduledFuture<?> pingScheduler;
private @Nullable ScheduledFuture<?> subscriptionScheduler;
private @Nullable ScheduledFuture<?> healthScheduler;
boolean bGatewayDetected = false;
private @Nullable SoulissGatewayDiscovery discoveryService;
public @Nullable DiscoverResult discoverResult = null;
public boolean thereIsAThingDetection = true;
private Bridge bridge;
private int nodes = 0;
private int maxTypicalXnode = 24;
private int countPingKo = 0;
private GatewayConfig gwConfig = new GatewayConfig();
public GatewayConfig getGwConfig() {
return gwConfig;
}
public SoulissGatewayHandler(Bridge br) {
super(br);
bridge = br;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// do nothing
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(SoulissGatewayDiscovery.class);
}
@Override
public void initialize() {
gwConfig = getConfigAs(GatewayConfig.class);
logger.debug("Starting UDP server on Souliss Default Port for Topics (Publish&Subcribe)");
// new runnable udp listener
var udpServerDefaultPortRunnableClass = new UDPListenDiscoverRunnable(this.bridge, this.discoverResult);
// and exec on thread
var localUdpListenerJob = this.udpListenerJob;
if (localUdpListenerJob == null || localUdpListenerJob.isCancelled()) {
var localUdpExecutorService = this.udpExecutorService;
localUdpExecutorService = Executors
.newSingleThreadExecutor(new NamedThreadFactory(getThing().getUID().getAsString()));
localUdpExecutorService.submit(udpServerDefaultPortRunnableClass);
}
// JOB PING
var soulissGatewayJobPingRunnable = new SoulissGatewayJobPing(this.bridge);
pingScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobPingRunnable, 2, this.gwConfig.pingInterval,
TimeUnit.SECONDS);
// JOB SUBSCRIPTION
var soulissGatewayJobSubscriptionRunnable = new SoulissGatewayJobSubscription(bridge);
subscriptionScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobSubscriptionRunnable, 5,
this.gwConfig.subscriptionInterval, TimeUnit.SECONDS);
// JOB HEALTH OF NODES
var soulissGatewayJobHealthyRunnable = new SoulissGatewayJobHealthy(this.bridge);
healthScheduler = scheduler.scheduleWithFixedDelay(soulissGatewayJobHealthyRunnable, 5,
this.gwConfig.healthyInterval, TimeUnit.SECONDS);
var soulissSendDispatcherRunnable = new SendDispatcherRunnable(this.bridge);
scheduler.scheduleWithFixedDelay(soulissSendDispatcherRunnable, 15,
SoulissBindingConstants.SEND_DISPATCHER_MIN_DELAY_CYCLE_IN_MILLIS, TimeUnit.MILLISECONDS);
}
public void dbStructAnswerReceived() {
commonCommands.sendTypicalRequestFrame(this.gwConfig, nodes);
}
public void setNodes(int nodes) {
this.nodes = nodes;
}
public int getNodes() {
var maxNode = 0;
for (Thing thing : getThing().getThings()) {
if (thing.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
continue;
}
var cfg = thing.getConfiguration();
var props = cfg.getProperties();
var pNode = props.get("node");
if (pNode != null) {
var thingNode = Integer.parseInt(pNode.toString());
if (thingNode > maxNode) {
maxNode = thingNode;
}
}
// at the end the length of the list will be equal to the number of present nodes
}
return maxNode + 1;
}
public void setMaxTypicalXnode(int maxTypicalXnode) {
this.maxTypicalXnode = maxTypicalXnode;
}
public int getMaxTypicalXnode() {
return maxTypicalXnode;
}
/**
* The {@link gatewayDetected} is used to notify that UDPServer decoded a Ping Response from gateway
*/
public void gatewayDetected() {
updateStatus(ThingStatus.ONLINE);
// reset counter
countPingKo = 0;
}
public void pingSent() {
if (++countPingKo > 3) {
var bridgeHandler = bridge.getHandler();
if (bridgeHandler != null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Gateway " + bridgeHandler.getThing().getUID() + " do not respond to " + countPingKo + " ping");
}
}
}
public void sendSubscription() {
if (this.gwConfig.gatewayLanAddress.length() > 0) {
int totNodes = getNodes();
commonCommands.sendSUBSCRIPTIONframe(this.gwConfig, totNodes);
}
logger.debug("Sent subscription packet");
}
public void setThereIsAThingDetection() {
thereIsAThingDetection = true;
}
public void resetThereIsAThingDetection() {
thereIsAThingDetection = false;
}
public @Nullable SoulissGatewayDiscovery getDiscoveryService() {
return this.discoveryService;
}
public void setDiscoveryService(SoulissGatewayDiscovery discoveryService) {
this.discoveryService = discoveryService;
}
@Override
public void dispose() {
var localPingScheduler = this.pingScheduler;
if (localPingScheduler != null) {
localPingScheduler.cancel(true);
}
var localSubscriptionScheduler = this.subscriptionScheduler;
if (localSubscriptionScheduler != null) {
localSubscriptionScheduler.cancel(true);
}
var localHealthScheduler = this.healthScheduler;
if (localHealthScheduler != null) {
localHealthScheduler.cancel(true);
}
var localUdpListenerJob = this.udpListenerJob;
if (localUdpListenerJob != null) {
localUdpListenerJob.cancel(true);
}
var localUdpExecutorService = this.udpExecutorService;
if (localUdpExecutorService != null) {
localUdpExecutorService.shutdownNow();
}
super.dispose();
}
public void setBridgeStatus(boolean isOnline) {
logger.debug("setBridgeStatus(): Setting Bridge to {}", isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
updateStatus(isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
}
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.protocol.CommonCommands;
import org.openhab.core.thing.Bridge;
/**
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissGatewayJobHealthy implements Runnable {
private @Nullable SoulissGatewayHandler gwHandler;
private final CommonCommands commonCommands = new CommonCommands();
public SoulissGatewayJobHealthy(Bridge bridge) {
this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
}
@Override
public void run() {
sendHealthyRequest();
}
private void sendHealthyRequest() {
var localGwHandler = this.gwHandler;
// sending healthy packet
if ((localGwHandler != null) && (localGwHandler.getGwConfig().gatewayLanAddress.length() > 0)) {
commonCommands.sendHealthyRequestFrame(localGwHandler.getGwConfig(), localGwHandler.getNodes());
// healthy packet sent
}
}
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.protocol.CommonCommands;
import org.openhab.core.thing.Bridge;
/**
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissGatewayJobPing implements Runnable {
private @Nullable SoulissGatewayHandler gwHandler;
private final CommonCommands commonCommands = new CommonCommands();
public SoulissGatewayJobPing(Bridge bridge) {
var bridgeHandler = bridge.getHandler();
if (bridgeHandler != null) {
gwHandler = (SoulissGatewayHandler) bridgeHandler;
}
}
@Override
public void run() {
SoulissGatewayHandler localGwHandler = this.gwHandler;
if (localGwHandler != null) {
sendPing(localGwHandler);
localGwHandler.pingSent();
}
}
private void sendPing(SoulissGatewayHandler soulissGwHandler) {
// sending ping packet
if (soulissGwHandler.getGwConfig().gatewayLanAddress.length() > 0) {
commonCommands.sendPing(soulissGwHandler.getGwConfig());
// ping packet sent
}
}
}

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.Bridge;
/**
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissGatewayJobSubscription implements Runnable {
private @Nullable SoulissGatewayHandler gwHandler;
public SoulissGatewayJobSubscription(Bridge bridge) {
this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
}
@Override
public void run() {
sendSubscription();
}
private void sendSubscription() {
SoulissGatewayHandler localGwHandler = this.gwHandler;
if (localGwHandler != null) {
localGwHandler.sendSubscription();
}
}
}

View File

@@ -0,0 +1,103 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class implements the base Souliss Action Message. All Action Messages derives from
* this class
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Tonino Fazio - @since 1.7.0
*/
@NonNullByDefault
public abstract class SoulissGenericActionMessage extends BaseThingHandler {
Thing thingGenActMsg;
private String sTopicNumber = "";
private String sTopicVariant = "";
private String timestamp = "";
private final Logger logger = LoggerFactory.getLogger(SoulissGenericActionMessage.class);
protected SoulissGenericActionMessage(Thing pThing) {
super(pThing);
thingGenActMsg = pThing;
try {
var cfg = thingGenActMsg.getConfiguration();
var props = cfg.getProperties();
var pTopicNumber = props.get("number");
var pTopicVariant = props.get("number");
if (pTopicNumber != null) {
sTopicNumber = pTopicNumber.toString();
}
if (pTopicVariant != null) {
sTopicVariant = pTopicVariant.toString();
}
} catch (Exception e) {
logger.debug("Item Definition Error. Use ex:'souliss:t11:thing_id'");
}
}
/**
* @return the Topic Number
*/
public String getTopicNumber() {
return sTopicNumber;
}
/**
* @param the Topic Variant
*/
public String getTopicVariant() {
return sTopicVariant;
}
public DateTimeType getLastUpdateTime() {
return DateTimeType.valueOf(timestamp);
}
public void setUpdateTimeNow() {
timestamp = getTimestamp();
}
/**
* Create a time stamp as "yyyy-MM-dd'T'HH:mm:ssz"
*
* @return String timestamp
*/
private static String getTimestamp() {
// Pattern : yyyy-MM-dd'T'HH:mm:ssz
var sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz");
var n = new Date();
return sdf.format(n.getTime());
}
@Override
public void thingUpdated(Thing thing) {
this.thingGenActMsg = thing;
}
}

View File

@@ -0,0 +1,214 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.binding.souliss.internal.config.GatewayConfig;
import org.openhab.binding.souliss.internal.protocol.CommonCommands;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class implements the base Souliss Typical All other Typicals derive from
* this class
*
* ...from wiki of Dario De Maio
* In Souliss the logics that drive your lights, curtains, LED, and
* others are pre-configured into so called Typicals. A Typical is a
* logic with a predefined set of inputs and outputs and a know
* behavior, are used to standardize the user interface and have a
* configuration-less behavior.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public abstract class SoulissGenericHandler extends BaseThingHandler implements TypicalCommonMethods {
private int iSlot;
private int iNode;
private final Logger logger = LoggerFactory.getLogger(SoulissGenericHandler.class);
private final CommonCommands commonCommands = new CommonCommands();
// 0 means that Secure Send is disabled
boolean bSecureSend = false;
// true means that expected value is setpoint (only for T31, T19 and T6x)
boolean bExpectedValueSameAsSet = false;
protected SoulissGenericHandler(Thing thing) {
super(thing);
}
/**
* @return the iSlot
*/
public int getSlot() {
return iSlot;
}
@Override
public void initialize() {
try {
var cfg = thing.getConfiguration();
var props = cfg.getProperties();
var pNode = props.get("node");
var pSlot = props.get("slot");
if ((pNode != null) && (pSlot != null)) {
iNode = Integer.parseInt(pNode.toString());
iSlot = Integer.parseInt(pSlot.toString());
updateProperty(SoulissBindingConstants.PROPERTY_NODE, Integer.toString(iNode));
updateProperty(SoulissBindingConstants.PROPERTY_SLOT, Integer.toString(iSlot));
updateProperty(SoulissBindingConstants.PROPERTY_UNIQUEID,
"N" + Integer.toString(iNode) + "S" + Integer.toString(iSlot));
}
} catch (Exception e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Error getting node/slot from souliss typical (thing config)");
}
}
/**
* @param SoulissNode
* the SoulissNodeID to get
*/
public int getNode() {
return iNode;
}
protected synchronized void commandReadNodeTypsStates() {
var gwConfig = getGatewayConfig();
if (gwConfig != null) {
commonCommands.sendTypicalRequestFrame(gwConfig, this.getNode(), 1);
}
}
/**
* Send a command as hexadecimal, e.g.: SOULISS_T1N_ON_CMD = 0x02; short
* SOULISS_T1N_OFF_CMD = 0x04;
*
* @param command
*/
public void commandSEND(byte command) {
var gwConfig = getGatewayConfig();
if (gwConfig != null) {
commonCommands.sendFORCEFrame(gwConfig, this.getNode(), this.getSlot(), command);
}
}
public void commandSendRgb(byte command, byte r, byte g, byte b) {
var gwConfig = getGatewayConfig();
if (gwConfig != null) {
commonCommands.sendFORCEFrame(gwConfig, command, r, g, b);
}
}
public void commandSEND(byte command, byte b1, byte b2) {
var gwConfig = getGatewayConfig();
if (gwConfig != null) {
commonCommands.sendFORCEFrameT31SetPoint(gwConfig, this.getNode(), this.getSlot(), command, b1, b2);
}
}
public void commandSEND(byte b1, byte b2) {
var gwConfig = getGatewayConfig();
if (gwConfig != null) {
commonCommands.sendFORCEFrameT61SetPoint(gwConfig, this.getNode(), this.getSlot(), b1, b2);
}
}
/**
* Create a time stamp as "yyyy-MM-dd'T'HH:mm:ssz"
*
* @return String timestamp
*/
private static String getTimestamp() {
// Pattern : yyyy-MM-dd'T'HH:mm:ssz
var sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz");
var n = new Date();
return sdf.format(n.getTime());
}
@Override
public void thingUpdated(Thing thing) {
updateThing(thing);
}
public @Nullable GatewayConfig getGatewayConfig() {
var bridge = getBridge();
if (bridge != null) {
SoulissGatewayHandler bridgeHandler = (SoulissGatewayHandler) bridge.getHandler();
if (bridgeHandler != null) {
return bridgeHandler.getGwConfig();
}
}
return null;
}
public @Nullable String getLabel() {
return getThing().getLabel();
}
public void setHealthy(byte shHealthy) {
this.updateState(SoulissBindingConstants.HEALTHY_CHANNEL, new DecimalType(shHealthy & 0xFF));
this.updateStatus(ThingStatus.ONLINE);
}
public void setLastStatusStored() {
this.updateState(SoulissBindingConstants.LASTSTATUSSTORED_CHANNEL, DateTimeType.valueOf(getTimestamp()));
}
protected @Nullable OnOffType getOhStateOnOffFromSoulissVal(byte sVal) {
if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
return OnOffType.ON;
} else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
return OnOffType.OFF;
} else if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_FEEDBACK) {
return OnOffType.ON;
} else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_FEEDBACK) {
return OnOffType.OFF;
} else if (sVal == SoulissProtocolConstants.SOULISS_T4N_NOT_ARMED) {
return OnOffType.OFF;
} else if (sVal == SoulissProtocolConstants.SOULISS_T4N_ARMED) {
return OnOffType.ON;
}
return null;
}
protected @Nullable OpenClosedType getOhStateOpenCloseFromSoulissVal(byte sVal) {
if (sVal == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
return OpenClosedType.CLOSED;
} else if (sVal == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
return OpenClosedType.OPEN;
}
return null;
}
}

View File

@@ -0,0 +1,139 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SoulissT11Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT11Handler extends SoulissGenericHandler {
private final Logger logger = LoggerFactory.getLogger(SoulissT11Handler.class);
private byte t1nRawState = 0xF; // dummy value for first init
private byte xSleepTime = 0;
public SoulissT11Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
OnOffType val = getOhStateOnOffFromSoulissVal(t1nRawState);
if (val != null) {
updateState(channelUID, val);
}
break;
default:
logger.debug("Unknown channel for T11 thing: {}", channelUID);
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.SLEEP_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND((byte) (SoulissProtocolConstants.SOULISS_T1N_TIMED + xSleepTime));
// set Off
updateState(channelUID, OnOffType.OFF);
}
break;
default:
logger.debug("Unknown channel for T11 thing: {}", channelUID);
}
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL) != null) {
xSleepTime = ((BigDecimal) configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL)).byteValue();
}
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T1N_ON_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T1N_OFF_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_OFF_COIL;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T1N_TIMED) {
// SLEEP
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
}
}
return -1;
}
void setState(@Nullable PrimitiveType state) {
if (state != null) {
this.updateState(SoulissBindingConstants.SLEEP_CHANNEL, OnOffType.OFF);
this.updateState(SoulissBindingConstants.ONOFF_CHANNEL, (OnOffType) state);
}
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
this.setState(getOhStateOnOffFromSoulissVal(rawState));
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return t1nRawState;
}
}

View File

@@ -0,0 +1,176 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT12Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT12Handler extends SoulissGenericHandler {
private byte t1nRawState = 0xF;
private byte xSleepTime = 0;
public SoulissT12Handler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL) != null) {
xSleepTime = ((BigDecimal) configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL)).byteValue();
}
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
switch (t1nRawState) {
case SoulissProtocolConstants.SOULISS_T1N_ON_COIL_AUTO:
case SoulissProtocolConstants.SOULISS_T1N_ON_COIL:
this.setState(OnOffType.ON);
break;
case SoulissProtocolConstants.SOULISS_T1N_OFF_COIL_AUTO:
case SoulissProtocolConstants.SOULISS_T1N_OFF_COIL:
this.setState(OnOffType.OFF);
break;
default:
break;
}
break;
case SoulissBindingConstants.AUTOMODE_CHANNEL:
switch (t1nRawState) {
case SoulissProtocolConstants.SOULISS_T1N_ON_COIL_AUTO:
case SoulissProtocolConstants.SOULISS_T1N_OFF_COIL_AUTO:
this.setStateAutomode(OnOffType.ON);
break;
case SoulissProtocolConstants.SOULISS_T1N_ON_COIL:
case SoulissProtocolConstants.SOULISS_T1N_OFF_COIL:
this.setStateAutomode(OnOffType.OFF);
break;
default:
break;
}
break;
default:
break;
}
} else
{
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.AUTOMODE_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_AUTO_CMD);
}
break;
case SoulissBindingConstants.SLEEP_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND((byte) (SoulissProtocolConstants.SOULISS_T1N_TIMED + xSleepTime));
// set Off
updateState(channelUID, OnOffType.OFF);
}
break;
default:
break;
}
}
}
public void setState(PrimitiveType state) {
this.updateState(SoulissBindingConstants.ONOFF_CHANNEL, (OnOffType) state);
}
public void setStateAutomode(PrimitiveType state) {
this.updateState(SoulissBindingConstants.AUTOMODE_CHANNEL, (OnOffType) state);
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
if (rawState == SoulissProtocolConstants.SOULISS_T1N_ON_COIL_AUTO) {
this.setState(OnOffType.ON);
this.setStateAutomode(OnOffType.ON);
} else if (rawState == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL_AUTO) {
this.setState(OnOffType.OFF);
this.setStateAutomode(OnOffType.ON);
} else if (rawState == SoulissProtocolConstants.SOULISS_T1N_ON_COIL) {
this.setState(OnOffType.ON);
this.setStateAutomode(OnOffType.OFF);
} else if (rawState == SoulissProtocolConstants.SOULISS_T1N_OFF_COIL) {
this.setState(OnOffType.OFF);
this.setStateAutomode(OnOffType.OFF);
}
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return t1nRawState;
}
@Override
public byte getExpectedRawState(byte bCommand) {
if (bSecureSend) {
if (bCommand == SoulissProtocolConstants.SOULISS_T1N_ON_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
} else if (bCommand == SoulissProtocolConstants.SOULISS_T1N_OFF_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_OFF_COIL;
} else if (bCommand >= SoulissProtocolConstants.SOULISS_T1N_TIMED) {
// SLEEP
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
}
}
return -1;
}
}

View File

@@ -0,0 +1,108 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT13Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT13Handler extends SoulissGenericHandler {
private byte t1nRawState = 0xF;
public SoulissT13Handler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
}
public void setState(@Nullable PrimitiveType state) {
super.setLastStatusStored();
if (state != null) {
if (state instanceof OnOffType) {
this.updateState(SoulissBindingConstants.STATEONOFF_CHANNEL, (OnOffType) state);
}
if (state instanceof OpenClosedType) {
this.updateState(SoulissBindingConstants.STATEOPENCLOSE_CHANNEL, (OpenClosedType) state);
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.STATEONOFF_CHANNEL:
OnOffType valonOff = getOhStateOnOffFromSoulissVal(t1nRawState);
if (valonOff != null) {
updateState(channelUID, valonOff);
}
break;
case SoulissBindingConstants.STATEOPENCLOSE_CHANNEL:
OpenClosedType valOpenClose = getOhStateOpenCloseFromSoulissVal(t1nRawState);
if (valOpenClose != null) {
updateState(channelUID, valOpenClose);
}
break;
default:
break;
}
}
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
this.setState(getOhStateOpenCloseFromSoulissVal(rawState));
this.setState(getOhStateOnOffFromSoulissVal(rawState));
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return 0;
}
@Override
public byte getExpectedRawState(byte bCommand) {
// Secure Send is disabled
return -1;
}
}

View File

@@ -0,0 +1,107 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT14Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT14Handler extends SoulissGenericHandler {
private byte t1nRawState = 0xF;
public SoulissT14Handler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.PULSE_CHANNEL:
OnOffType valPulse = getOhStateOnOffFromSoulissVal(t1nRawState);
if (valPulse != null) {
updateState(channelUID, valPulse);
}
break;
default:
break;
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.PULSE_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
default:
break;
}
}
}
public void setState(@Nullable PrimitiveType state) {
super.setLastStatusStored();
if (state != null) {
this.updateState(SoulissBindingConstants.PULSE_CHANNEL, (OnOffType) state);
}
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
this.setState(getOhStateOnOffFromSoulissVal(rawState));
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return t1nRawState;
}
@Override
public byte getExpectedRawState(byte bCommand) {
// Secure Send is disabled for T14
return -1;
}
}

View File

@@ -0,0 +1,233 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SoulissT16Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT16Handler extends SoulissGenericHandler {
private final Logger logger = LoggerFactory.getLogger(SoulissT16Handler.class);
private byte t1nRawStateByte0 = 0xF;
private byte t1nRawStateRedByte1 = 0x00;
private byte t1nRawStateGreenByte2 = 0x00;
private byte t1nRawStateBluByte3 = 0x00;
private HSBType hsbState = HSBType.WHITE;
byte xSleepTime = 0;
public SoulissT16Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
OnOffType valOnOff = getOhStateOnOffFromSoulissVal(t1nRawStateByte0);
if (valOnOff != null) {
updateState(channelUID, valOnOff);
}
break;
case SoulissBindingConstants.LED_COLOR_CHANNEL:
updateState(channelUID, gethsb(t1nRawStateRedByte1, t1nRawStateGreenByte2, t1nRawStateBluByte3));
break;
case SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL:
updateState(channelUID,
PercentType.valueOf(gethsb(t1nRawStateRedByte1, t1nRawStateGreenByte2, t1nRawStateBluByte3)
.getBrightness().toString()));
break;
default:
break;
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.WHITE_MODE_CHANNEL:
if (command instanceof OnOffType) {
hsbState = HSBType.fromRGB(255, 255, 255);
commandSendRgb(SoulissProtocolConstants.SOULISS_T1N_SET, (byte) 255, (byte) 255, (byte) 255);
updateState(SoulissBindingConstants.LED_COLOR_CHANNEL, hsbState);
}
break;
case SoulissBindingConstants.SLEEP_CHANNEL:
if (command instanceof OnOffType) {
commandSEND((byte) (SoulissProtocolConstants.SOULISS_T1N_TIMED + xSleepTime));
// set Off
updateState(channelUID, OnOffType.OFF);
}
break;
case SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL:
if (command instanceof PercentType) {
updateState(SoulissBindingConstants.LED_COLOR_CHANNEL,
gethsb(t1nRawStateRedByte1, t1nRawStateGreenByte2, t1nRawStateBluByte3));
commandSendRgb(SoulissProtocolConstants.SOULISS_T1N_SET,
(byte) (hsbState.getRed().shortValue() * (255.00 / 100)),
(byte) (hsbState.getGreen().shortValue() * (255.00 / 100)),
(byte) (hsbState.getBlue().shortValue() * (255.00 / 100)));
} else if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.ROLLER_BRIGHTNESS_CHANNEL:
if (command.equals(UpDownType.UP)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_BRIGHT_UP);
} else if (command.equals(UpDownType.DOWN)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_BRIGHT_DOWN);
}
break;
case SoulissBindingConstants.LED_COLOR_CHANNEL:
if (command instanceof HSBType) {
HSBType localHsbState = (HSBType) command;
updateState(SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL,
PercentType.valueOf(hsbState.getBrightness().toString()));
commandSendRgb(SoulissProtocolConstants.SOULISS_T1N_SET,
(byte) (localHsbState.getRed().shortValue() * 255.00 / 100),
(byte) (localHsbState.getGreen().shortValue() * 255.00 / 100),
(byte) (localHsbState.getBlue().shortValue() * 255.00 / 100));
}
break;
default:
break;
}
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL) != null) {
xSleepTime = ((BigDecimal) configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL)).byteValue();
}
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
void setState(@Nullable PrimitiveType state) {
super.setLastStatusStored();
updateState(SoulissBindingConstants.SLEEP_CHANNEL, OnOffType.OFF);
if (state != null) {
logger.debug("T16, setting state to {}", state.toFullString());
this.updateState(SoulissBindingConstants.ONOFF_CHANNEL, (OnOffType) state);
}
}
@Override
public void setRawState(byte rawState) {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public void setRawStateCommand(byte rawStateByte0) {
super.setLastStatusStored();
if (rawStateByte0 != t1nRawStateByte0) {
this.setState(getOhStateOnOffFromSoulissVal(rawStateByte0));
}
}
public void setRawStateRgb(byte rawStateRedByte1, byte rawStateGreenByte2, byte rawStateBluByte3) {
super.setLastStatusStored();
if (rawStateRedByte1 != t1nRawStateRedByte1 || rawStateGreenByte2 != t1nRawStateGreenByte2
|| rawStateBluByte3 != t1nRawStateBluByte3) {
HSBType localHsbState = gethsb(rawStateRedByte1, rawStateGreenByte2, rawStateBluByte3);
logger.debug("T16, setting color to {},{},{}", rawStateRedByte1, rawStateGreenByte2, rawStateBluByte3);
updateState(SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL,
PercentType.valueOf(localHsbState.getBrightness().toString()));
updateState(SoulissBindingConstants.LED_COLOR_CHANNEL, localHsbState);
}
t1nRawStateRedByte1 = rawStateRedByte1;
t1nRawStateGreenByte2 = rawStateGreenByte2;
t1nRawStateBluByte3 = rawStateBluByte3;
}
@Override
public byte getRawState() {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public byte getRawStateCommand() {
return t1nRawStateByte0;
}
public byte[] getRawStateValues() {
return new byte[] { t1nRawStateRedByte1, t1nRawStateGreenByte2, t1nRawStateBluByte3 };
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T1N_ON_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T1N_OFF_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_OFF_COIL;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T1N_TIMED) {
// SLEEP
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
}
}
return -1;
}
HSBType gethsb(byte rawStateRedByte1, byte rawStateGreenByte2, byte rawStateBluByte3) {
return HSBType.fromRGB(rawStateRedByte1, rawStateGreenByte2, rawStateBluByte3);
}
}

View File

@@ -0,0 +1,128 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT18Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT18Handler extends SoulissGenericHandler {
byte t1nRawState = 0xF;
byte xSleepTime = 0;
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL) != null) {
xSleepTime = ((BigDecimal) configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL)).byteValue();
}
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
public SoulissT18Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.PULSE_CHANNEL:
OnOffType valPulse = getOhStateOnOffFromSoulissVal(t1nRawState);
if (valPulse != null) {
updateState(channelUID, valPulse);
}
break;
default:
break;
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
default:
break;
}
}
}
void setState(@Nullable PrimitiveType state) {
if (state != null) {
updateState(SoulissBindingConstants.SLEEP_CHANNEL, OnOffType.OFF);
this.updateState(SoulissBindingConstants.ONOFF_CHANNEL, (OnOffType) state);
}
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
this.setState(getOhStateOnOffFromSoulissVal(rawState));
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return t1nRawState;
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T1N_ON_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_ON_FEEDBACK;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T1N_OFF_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_OFF_FEEDBACK;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T1N_TIMED) {
// SLEEP
return SoulissProtocolConstants.SOULISS_T1N_ON_FEEDBACK;
}
}
return -1;
}
}

View File

@@ -0,0 +1,183 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SoulissT19Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT19Handler extends SoulissGenericHandler {
private final Logger logger = LoggerFactory.getLogger(SoulissT19Handler.class);
byte t1nRawStateByte0 = 0xF;
byte t1nRawStateBrigthnessByte1 = 0x00;
byte xSleepTime = 0;
public SoulissT19Handler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
OnOffType valOnOff = getOhStateOnOffFromSoulissVal(t1nRawStateByte0);
if (valOnOff != null) {
updateState(channelUID, valOnOff);
}
break;
case SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL:
updateState(SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL,
PercentType.valueOf(String.valueOf((t1nRawStateBrigthnessByte1 / 255) * 100)));
break;
default:
break;
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL:
if (command instanceof PercentType) {
updateState(SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL, (PercentType) command);
commandSEND(SoulissProtocolConstants.SOULISS_T1N_SET,
(byte) (((PercentType) command).shortValue() * 255.00 / 100.00));
} else if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_ON_CMD);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_OFF_CMD);
}
break;
case SoulissBindingConstants.ROLLER_BRIGHTNESS_CHANNEL:
if (command.equals(UpDownType.UP)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_BRIGHT_UP);
} else if (command.equals(UpDownType.DOWN)) {
commandSEND(SoulissProtocolConstants.SOULISS_T1N_BRIGHT_DOWN);
}
break;
case SoulissBindingConstants.SLEEP_CHANNEL:
if (command instanceof OnOffType) {
commandSEND((byte) (SoulissProtocolConstants.SOULISS_T1N_TIMED + xSleepTime));
}
break;
default:
break;
}
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL) != null) {
xSleepTime = ((BigDecimal) configurationMap.get(SoulissBindingConstants.SLEEP_CHANNEL)).byteValue();
}
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
public void setState(@Nullable PrimitiveType state) {
super.setLastStatusStored();
if (state != null) {
updateState(SoulissBindingConstants.SLEEP_CHANNEL, OnOffType.OFF);
logger.debug("T19, setting state to {}", state.toFullString());
this.updateState(SoulissBindingConstants.ONOFF_CHANNEL, (OnOffType) state);
}
}
public void setRawStateDimmerValue(byte dimmerValue) {
try {
if (dimmerValue != t1nRawStateByte0 && dimmerValue >= 0) {
logger.debug("T19, setting dimmer to {}", dimmerValue);
updateState(SoulissBindingConstants.DIMMER_BRIGHTNESS_CHANNEL,
PercentType.valueOf(String.valueOf(Math.round(((double) dimmerValue / 255) * 100))));
}
} catch (Exception ex) {
logger.warn("UUID: {}, had an update dimmer state error:{}", this.getThing().getUID().getAsString(),
ex.getMessage());
}
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawStateByte0 != rawState) {
this.setState(getOhStateOnOffFromSoulissVal(rawState));
}
t1nRawStateByte0 = rawState;
}
@Override
public byte getRawState() {
return t1nRawStateByte0;
}
public byte getRawStateDimmerValue() {
return t1nRawStateBrigthnessByte1;
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T1N_ON_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T1N_OFF_CMD) {
return SoulissProtocolConstants.SOULISS_T1N_OFF_COIL;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T1N_TIMED) {
// SLEEP
return SoulissProtocolConstants.SOULISS_T1N_ON_COIL;
}
}
return -1;
}
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
/**
* The {@link SoulissT1AHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT1AHandler extends SoulissGenericHandler {
byte t1nRawState = 0xF;
public SoulissT1AHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
throw new UnsupportedOperationException("Unsupported operation. Read Only");
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
}
private OpenClosedType getTypeFromBool(boolean value) {
if (!value) {
return OpenClosedType.CLOSED;
}
return OpenClosedType.OPEN;
}
private boolean getBitState(int value, int bit) {
return ((value & (1L << bit)) != 0);
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t1nRawState != rawState) {
this.updateState(SoulissBindingConstants.T1A_1_CHANNEL, getTypeFromBool(getBitState(rawState, 0)));
this.updateState(SoulissBindingConstants.T1A_2_CHANNEL, getTypeFromBool(getBitState(rawState, 1)));
this.updateState(SoulissBindingConstants.T1A_3_CHANNEL, getTypeFromBool(getBitState(rawState, 2)));
this.updateState(SoulissBindingConstants.T1A_4_CHANNEL, getTypeFromBool(getBitState(rawState, 3)));
this.updateState(SoulissBindingConstants.T1A_5_CHANNEL, getTypeFromBool(getBitState(rawState, 4)));
this.updateState(SoulissBindingConstants.T1A_6_CHANNEL, getTypeFromBool(getBitState(rawState, 5)));
this.updateState(SoulissBindingConstants.T1A_7_CHANNEL, getTypeFromBool(getBitState(rawState, 6)));
this.updateState(SoulissBindingConstants.T1A_8_CHANNEL, getTypeFromBool(getBitState(rawState, 7)));
}
t1nRawState = rawState;
}
@Override
public byte getRawState() {
return t1nRawState;
}
@Override
public byte getExpectedRawState(byte bCommand) {
// Secure Send is disabled
return -1;
}
}

View File

@@ -0,0 +1,202 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT22Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT22Handler extends SoulissGenericHandler {
byte t2nRawState = 0xF;
public SoulissT22Handler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case SoulissBindingConstants.ROLLERSHUTTER_CHANNEL:
break;
default:
break;
}
} else {
switch (channelUID.getId()) {
case SoulissBindingConstants.ROLLERSHUTTER_CHANNEL:
if (command.equals(UpDownType.UP)) {
commandSEND(SoulissProtocolConstants.SOULISS_T2N_OPEN_CMD);
} else if (command.equals(UpDownType.DOWN)) {
commandSEND(SoulissProtocolConstants.SOULISS_T2N_CLOSE_CMD);
} else if (command.equals(StopMoveType.STOP)) {
commandSEND(SoulissProtocolConstants.SOULISS_T2N_STOP_CMD);
}
break;
case SoulissBindingConstants.ONOFF_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T2N_OPEN_CMD_LOCAL);
} else if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T2N_CLOSE_CMD_LOCAL);
}
break;
default:
break;
}
}
}
public void setState(PrimitiveType state) {
if (state instanceof PercentType) {
this.updateState(SoulissBindingConstants.ROLLERSHUTTER_CHANNEL, (PercentType) state);
}
}
public void setStateMessage(String rollershutterMessage) {
this.updateState(SoulissBindingConstants.ROLLERSHUTTER_STATE_CHANNEL_CHANNEL,
StringType.valueOf(rollershutterMessage));
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t2nRawState != rawState) {
var val = getOhStateT22FromSoulissVal(rawState);
this.setState(val);
if (rawState == SoulissProtocolConstants.SOULISS_T2N_OPEN_CMD) {
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_OPENING_CHANNEL);
} else if (rawState == SoulissProtocolConstants.SOULISS_T2N_CLOSE_CMD) {
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_CLOSING_CHANNEL);
}
switch (rawState) {
case SoulissProtocolConstants.SOULISS_T2N_COIL_STOP:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_STOP_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_COIL_OFF:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_OPENING_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_LIMSWITCH_CLOSE:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_LIMITSWITCH_CLOSE_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_LIMSWITCH_OPEN:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_LIMITSWITCH_OPEN_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_NOLIMSWITCH:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_LIMITSWITCH_OPEN_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_TIMER_OFF:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_TIMER_OFF);
break;
case SoulissProtocolConstants.SOULISS_T2N_STATE_OPEN:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_STATE_OPEN_CHANNEL);
break;
case SoulissProtocolConstants.SOULISS_T2N_STATE_CLOSE:
this.setStateMessage(SoulissBindingConstants.ROLLERSHUTTER_MESSAGE_STATE_CLOSE_CHANNEL);
break;
default:
break;
}
t2nRawState = rawState;
}
}
private PercentType getOhStateT22FromSoulissVal(short sVal) {
var iState = 0;
switch (sVal) {
case SoulissProtocolConstants.SOULISS_T2N_COIL_OPEN:
iState = 0;
break;
case SoulissProtocolConstants.SOULISS_T2N_COIL_CLOSE:
iState = 100;
break;
case SoulissProtocolConstants.SOULISS_T2N_COIL_STOP:
iState = 50;
break;
case SoulissProtocolConstants.SOULISS_T2N_LIMSWITCH_CLOSE:
iState = 100;
break;
case SoulissProtocolConstants.SOULISS_T2N_LIMSWITCH_OPEN:
iState = 0;
break;
case SoulissProtocolConstants.SOULISS_T2N_NOLIMSWITCH:
iState = 50;
break;
case SoulissProtocolConstants.SOULISS_T2N_TIMER_OFF:
iState = 50;
break;
case SoulissProtocolConstants.SOULISS_T2N_STATE_OPEN:
iState = 0;
break;
case SoulissProtocolConstants.SOULISS_T2N_STATE_CLOSE:
iState = 100;
break;
default:
break;
}
return PercentType.valueOf(String.valueOf(iState));
}
@Override
public byte getRawState() {
return t2nRawState;
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T2N_OPEN_CMD) {
return SoulissProtocolConstants.SOULISS_T2N_COIL_OPEN;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T2N_CLOSE_CMD) {
return SoulissProtocolConstants.SOULISS_T2N_COIL_CLOSE;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T2N_STOP_CMD) {
return SoulissProtocolConstants.SOULISS_T2N_COIL_STOP;
}
}
return -1;
}
}

View File

@@ -0,0 +1,320 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.binding.souliss.internal.protocol.HalfFloatUtils;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SoulissT31Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT31Handler extends SoulissGenericHandler {
private final Logger logger = LoggerFactory.getLogger(SoulissT31Handler.class);
QuantityType<Temperature> setMeasuredValue = new QuantityType<>("0");
QuantityType<Temperature> setPointValue = new QuantityType<>("0");
StringType fanStateValue = StringType.EMPTY;
StringType powerState = StringType.EMPTY;
StringType fireState = StringType.EMPTY;
StringType lastModeState = StringType.EMPTY;
StringType modeStateValue = StringType.EMPTY;
public SoulissT31Handler(Thing pThing) {
super(pThing);
thing = pThing;
}
// called on every status change or change request
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
switch (channelUID.getId()) {
// FAN
case SoulissBindingConstants.T31_SYSTEM_CHANNEL:
if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_SHUTDOWN);
} else {
if (modeStateValue.toString()
.equals(SoulissBindingConstants.T31_HEATINGMODE_MESSAGE_MODE_CHANNEL)) {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_HEATING);
} else {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_COOLING);
}
}
break;
case SoulissBindingConstants.T31_MODE_CHANNEL:
if (command.toString().equals(SoulissBindingConstants.T31_HEATINGMODE_MESSAGE_MODE_CHANNEL)) {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_HEATING);
} else {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_COOLING);
}
break;
case SoulissBindingConstants.T31_BUTTON_CHANNEL:
if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T3N_AS_MEASURED);
}
break;
case SoulissBindingConstants.T31_FAN_CHANNEL:
switch (command.toString()) {
case SoulissBindingConstants.T31_FANHIGH_MESSAGE_FAN_CHANNEL:
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_MANUAL);
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_HIGH);
fanStateValue = StringType.valueOf(SoulissBindingConstants.T31_FANHIGH_MESSAGE_FAN_CHANNEL);
break;
case SoulissBindingConstants.T31_FANMEDIUM_MESSAGE_FAN_CHANNEL:
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_MANUAL);
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_MED);
fanStateValue = StringType
.valueOf(SoulissBindingConstants.T31_FANMEDIUM_MESSAGE_FAN_CHANNEL);
break;
case SoulissBindingConstants.T31_FANLOW_MESSAGE_FAN_CHANNEL:
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_MANUAL);
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_LOW);
fanStateValue = StringType.valueOf(SoulissBindingConstants.T31_FANLOW_MESSAGE_FAN_CHANNEL);
break;
case SoulissBindingConstants.T31_FANAUTO_MESSAGE_FAN_CHANNEL:
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_AUTO);
fanStateValue = StringType.valueOf(SoulissBindingConstants.T31_FANAUTO_MESSAGE_FAN_CHANNEL);
break;
case SoulissBindingConstants.T31_FANOFF_MESSAGE_FAN_CHANNEL:
commandSEND(SoulissProtocolConstants.SOULISS_T3N_FAN_OFF);
fanStateValue = StringType.valueOf(SoulissBindingConstants.T31_FANOFF_MESSAGE_FAN_CHANNEL);
break;
default:
logger.debug("Fan Channel handle not recognized, skipping..");
break;
}
break;
case SoulissBindingConstants.T31_SETPOINT_CHANNEL:
if (command instanceof QuantityType<?>) {
int uu = HalfFloatUtils.fromFloat(((QuantityType<?>) command).floatValue());
byte b2 = (byte) (uu >> 8);
byte b1 = (byte) uu;
// setpoint command
commandSEND(SoulissProtocolConstants.SOULISS_T31_USE_OF_SLOT_SETPOINT_COMMAND, b1, b2);
}
break;
default:
logger.debug("state not recognized! skipping..");
break;
}
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
public void setState(PrimitiveType state) {
this.updateState(SoulissBindingConstants.T31_BUTTON_CHANNEL, OnOffType.OFF);
super.setLastStatusStored();
if (state instanceof StringType) {
switch (state.toString()) {
case SoulissBindingConstants.T31_FANLOW_MESSAGE_FAN_CHANNEL:
case SoulissBindingConstants.T31_FANMEDIUM_MESSAGE_FAN_CHANNEL:
case SoulissBindingConstants.T31_FANHIGH_MESSAGE_FAN_CHANNEL:
case SoulissBindingConstants.T31_FANAUTO_MESSAGE_FAN_CHANNEL:
case SoulissBindingConstants.T31_FANOFF_MESSAGE_FAN_CHANNEL:
if (!fanStateValue.equals(state)) {
this.updateState(SoulissBindingConstants.T31_FAN_CHANNEL, (StringType) state);
fanStateValue = (StringType) state;
}
break;
case SoulissBindingConstants.T31_HEATINGMODE_MESSAGE_MODE_CHANNEL:
case SoulissBindingConstants.T31_COOLINGMODE_MESSAGE_MODE_CHANNEL:
if (!modeStateValue.equals(state)) {
this.updateState(SoulissBindingConstants.T31_MODE_CHANNEL, (StringType) state);
modeStateValue = (StringType) state;
}
break;
case SoulissBindingConstants.T31_OFF_MESSAGE_SYSTEM_CHANNEL:
if (!powerState.equals(state)) {
this.updateState(SoulissBindingConstants.T31_SYSTEM_CHANNEL, OnOffType.OFF);
powerState = (StringType) state;
}
break;
case SoulissBindingConstants.T31_ON_MESSAGE_SYSTEM_CHANNEL:
if (!powerState.equals(state)) {
this.updateState(SoulissBindingConstants.T31_SYSTEM_CHANNEL, OnOffType.ON);
powerState = (StringType) state;
}
break;
case SoulissBindingConstants.T31_ON_MESSAGE_FIRE_CHANNEL:
if (!fireState.equals(state)) {
this.updateState(SoulissBindingConstants.T31_FIRE_CHANNEL, OnOffType.ON);
powerState = (StringType) state;
}
break;
case SoulissBindingConstants.T31_OFF_MESSAGE_FIRE_CHANNEL:
if (!fireState.equals(state)) {
this.updateState(SoulissBindingConstants.T31_FIRE_CHANNEL, OnOffType.OFF);
powerState = (StringType) state;
}
break;
default:
}
}
}
public void setMeasuredValue(QuantityType<Temperature> valueOf) {
if ((valueOf instanceof QuantityType<?>) && (!setMeasuredValue.equals(valueOf))) {
this.updateState(SoulissBindingConstants.T31_VALUE_CHANNEL, valueOf);
setMeasuredValue = valueOf;
}
}
public void setSetpointValue(QuantityType<Temperature> valueOf) {
if ((valueOf instanceof QuantityType<?>) && (!setPointValue.equals(valueOf))) {
this.updateState(SoulissBindingConstants.T31_SETPOINT_CHANNEL, valueOf);
setPointValue = valueOf;
}
}
public void setRawStateValues(byte rawStateByte0, float valTemp, float valSetPoint) {
var sMessage = "";
switch (getBitState(rawStateByte0, 0)) {
case 0:
sMessage = SoulissBindingConstants.T31_OFF_MESSAGE_SYSTEM_CHANNEL;
break;
case 1:
sMessage = SoulissBindingConstants.T31_ON_MESSAGE_SYSTEM_CHANNEL;
break;
default:
logger.debug("System Channel on/off not recognized, skipping");
break;
}
this.setState(StringType.valueOf(sMessage));
switch (getBitState(rawStateByte0, 7)) {
case 0:
sMessage = SoulissBindingConstants.T31_HEATINGMODE_MESSAGE_MODE_CHANNEL;
break;
case 1:
sMessage = SoulissBindingConstants.T31_COOLINGMODE_MESSAGE_MODE_CHANNEL;
break;
default:
logger.debug("Mode not recognized, skipping");
break;
}
this.setState(StringType.valueOf(sMessage));
// button indicating whether the system is running or not
switch (getBitState(rawStateByte0, 1) + getBitState(rawStateByte0, 2)) {
case 0:
sMessage = SoulissBindingConstants.T31_OFF_MESSAGE_FIRE_CHANNEL;
break;
case 1:
sMessage = SoulissBindingConstants.T31_ON_MESSAGE_FIRE_CHANNEL;
break;
default:
logger.debug("Fire not recognized, skipping");
break;
}
this.setState(StringType.valueOf(sMessage));
// FAN SPEED
switch (getBitState(rawStateByte0, 3) + getBitState(rawStateByte0, 4) + getBitState(rawStateByte0, 5)) {
case 0:
sMessage = SoulissBindingConstants.T31_FANOFF_MESSAGE_FAN_CHANNEL;
break;
case 1:
sMessage = SoulissBindingConstants.T31_FANLOW_MESSAGE_FAN_CHANNEL;
break;
case 2:
sMessage = SoulissBindingConstants.T31_FANMEDIUM_MESSAGE_FAN_CHANNEL;
break;
case 3:
sMessage = SoulissBindingConstants.T31_FANHIGH_MESSAGE_FAN_CHANNEL;
break;
default:
logger.debug("Fan speed not recognized, skipping");
break;
}
this.setState(StringType.valueOf(sMessage));
// SLOT 1-2: Temperature Value
if (!Float.isNaN(valTemp)) {
this.setMeasuredValue(QuantityType.valueOf(valTemp, SIUnits.CELSIUS));
}
// SLOT 3-4: Setpoint Value
if (!Float.isNaN(valSetPoint)) {
this.setSetpointValue(QuantityType.valueOf(valSetPoint, SIUnits.CELSIUS));
}
}
@Override
public byte getRawState() {
return 0;
}
@Override
public byte getExpectedRawState(byte bCommand) {
return 0;
}
public byte getBitState(byte vRaw, int iBit) {
final var maskBit1 = 0x1;
if (((vRaw >>> iBit) & maskBit1) == 0) {
return 0;
} else {
return 1;
}
}
@Override
public void setRawState(byte rawState) {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
}

View File

@@ -0,0 +1,142 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
import org.openhab.core.types.RefreshType;
/**
* The {@link SoulissT41Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT41Handler extends SoulissGenericHandler {
byte t4nRawState = 0xF;
public SoulissT41Handler(Thing thing) {
super(thing);
}
// called on every status change or change request
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
if (channelUID.getId().equals(SoulissBindingConstants.T4N_ONOFFALARM_CHANNEL)) {
if (command instanceof OnOffType) {
if (command.equals(OnOffType.OFF)) {
commandSEND(SoulissProtocolConstants.SOULISS_T4N_NOT_ARMED);
} else if (command.equals(OnOffType.ON)) {
commandSEND(SoulissProtocolConstants.SOULISS_T4N_ARMED);
}
}
} else if ((channelUID.getAsString().split(":")[3].equals(SoulissBindingConstants.T4N_REARMALARM_CHANNEL))
&& (command instanceof OnOffType) && (command.equals(OnOffType.OFF))) {
commandSEND(SoulissProtocolConstants.SOULISS_T4N_REARM);
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_REARMOFF_MESSAGE_CHANNEL));
}
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
public void setState(PrimitiveType state) {
if (state instanceof OnOffType) {
this.updateState(SoulissBindingConstants.T4N_ONOFFALARM_CHANNEL, (OnOffType) state);
} else if (state instanceof StringType) {
switch (String.valueOf(state)) {
case SoulissBindingConstants.T4N_ALARMON_MESSAGE_CHANNEL:
this.updateState(SoulissBindingConstants.T4N_STATUSALARM_CHANNEL, OnOffType.ON);
break;
case SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL:
this.updateState(SoulissBindingConstants.T4N_STATUSALARM_CHANNEL, OnOffType.OFF);
break;
default:
break;
}
}
// // Reset the rearm button. This is because if pressed, it does not turn off by itself
updateState(SoulissBindingConstants.T4N_REARMALARM_CHANNEL, OnOffType.OFF);
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t4nRawState != rawState) {
switch (rawState) {
case SoulissProtocolConstants.SOULISS_T4N_NO_ANTITHEFT:
this.setState(OnOffType.OFF);
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL));
break;
case SoulissProtocolConstants.SOULISS_T4N_ANTITHEFT:
this.setState(OnOffType.ON);
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL));
break;
case SoulissProtocolConstants.SOULISS_T4N_IN_ALARM:
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_ALARMON_MESSAGE_CHANNEL));
break;
case SoulissProtocolConstants.SOULISS_T4N_ARMED:
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_ARMED_MESSAGE_CHANNEL));
break;
default:
break;
}
}
t4nRawState = rawState;
}
@Override
public byte getRawState() {
return t4nRawState;
}
@Override
public byte getExpectedRawState(byte bCmd) {
if (bSecureSend) {
if (bCmd == SoulissProtocolConstants.SOULISS_T4N_ARMED) {
return SoulissProtocolConstants.SOULISS_T4N_ANTITHEFT;
} else if (bCmd == SoulissProtocolConstants.SOULISS_T4N_NOT_ARMED) {
return SoulissProtocolConstants.SOULISS_T4N_NO_ANTITHEFT;
} else if (bCmd >= SoulissProtocolConstants.SOULISS_T4N_REARM) {
return SoulissProtocolConstants.SOULISS_T4N_ANTITHEFT;
}
}
return -1;
}
}

View File

@@ -0,0 +1,109 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
/**
* The {@link SoulissT42Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT42Handler extends SoulissGenericHandler {
byte t4nRawState = 0xF;
public SoulissT42Handler(Thing thing) {
super(thing);
}
// called on every status change or change request
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if ((channelUID.getAsString().split(":")[3].equals(SoulissBindingConstants.T4N_REARMALARM_CHANNEL))
&& (command instanceof OnOffType) && (command.equals(OnOffType.ON))) {
commandSEND(SoulissProtocolConstants.SOULISS_T4N_REARM);
this.setState(StringType.valueOf(SoulissBindingConstants.T4N_REARMOFF_MESSAGE_CHANNEL));
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
var configurationMap = getThing().getConfiguration();
if (configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND) != null) {
bSecureSend = ((Boolean) configurationMap.get(SoulissBindingConstants.CONFIG_SECURE_SEND)).booleanValue();
}
}
public void setState(PrimitiveType state) {
if (state instanceof StringType) {
switch (String.valueOf(state)) {
case SoulissBindingConstants.T4N_ALARMON_MESSAGE_CHANNEL:
this.updateState(SoulissBindingConstants.T4N_STATUSALARM_CHANNEL, OnOffType.ON);
break;
case SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL:
this.updateState(SoulissBindingConstants.T4N_STATUSALARM_CHANNEL, OnOffType.OFF);
break;
default:
break;
}
}
// Reset the rearm button. This is because if pressed, it does not turn off by itself
updateState(SoulissBindingConstants.T4N_REARMALARM_CHANNEL, OnOffType.OFF);
super.setLastStatusStored();
}
@Override
public void setRawState(byte rawState) {
// update Last Status stored time
super.setLastStatusStored();
// update item state only if it is different from previous
if (t4nRawState != rawState) {
OnOffType onOffVal = getOhStateOnOffFromSoulissVal(rawState);
if (onOffVal != null) {
this.setState(onOffVal);
}
}
t4nRawState = rawState;
}
@Override
public byte getRawState() {
return t4nRawState;
}
@Override
public byte getExpectedRawState(byte bCmd) {
if ((bSecureSend) && (bCmd == SoulissProtocolConstants.SOULISS_T4N_REARM)) {
return SoulissProtocolConstants.SOULISS_T4N_ANTITHEFT;
}
return -1;
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT51Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT51Handler extends SoulissT5nHandler {
public SoulissT51Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT52Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT52Handler extends SoulissT5nHandler {
public SoulissT52Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT53Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT53Handler extends SoulissT5nHandler {
public SoulissT53Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT54Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT54Handler extends SoulissT5nHandler {
public SoulissT54Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT55Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT55Handler extends SoulissT5nHandler {
public SoulissT55Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT56Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT56Handler extends SoulissT5nHandler {
public SoulissT56Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT57Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT57Handler extends SoulissT5nHandler {
public SoulissT57Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT58Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT58Handler extends SoulissT5nHandler {
public SoulissT58Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
/**
* The {@link SoulissT5nHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT5nHandler extends SoulissGenericHandler {
private float fVal = 0xF;
public SoulissT5nHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
}
public void setState(QuantityType<?> state) {
this.updateState(SoulissBindingConstants.T5N_VALUE_CHANNEL, state);
}
@Override
public void setRawState(byte rawState) {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public void setFloatValue(float valueOf) {
super.setLastStatusStored();
if (fVal != valueOf) {
this.setState(QuantityType.valueOf(Float.toString(valueOf)));
fVal = valueOf;
}
}
@Override
public byte getRawState() {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public float getFloatState() {
return fVal;
}
@Override
public byte getExpectedRawState(byte bCommand) {
// Secure Send is disabled
return -1;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
throw new UnsupportedOperationException("Unsupported operation. Read Only");
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT61Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT61Handler extends SoulissT6nHandler {
// constructor
public SoulissT61Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT62Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT62Handler extends SoulissT6nHandler {
// constructor
public SoulissT62Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT63Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT63Handler extends SoulissT6nHandler {
// constructor
public SoulissT63Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT64Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT64Handler extends SoulissT6nHandler {
// constructor
public SoulissT64Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT65Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT65Handler extends SoulissT6nHandler {
// constructor
public SoulissT65Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT66Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT66Handler extends SoulissT6nHandler {
// constructor
public SoulissT66Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT67Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT67Handler extends SoulissT6nHandler {
// constructor
public SoulissT67Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
/**
* The {@link SoulissT68Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT68Handler extends SoulissT6nHandler {
// constructor
public SoulissT68Handler(Thing thing) {
super(thing);
}
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.protocol.HalfFloatUtils;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
/**
* The {@link SoulissT6nHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissT6nHandler extends SoulissGenericHandler {
private float fSetPointValue = 0xFFFF;
public SoulissT6nHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof DecimalType) {
int uu = HalfFloatUtils.fromFloat(((DecimalType) command).floatValue());
byte b2 = (byte) (uu >> 8);
byte b1 = (byte) uu;
// setpoint command
commandSEND(b1, b2);
}
}
@Override
public void initialize() {
super.initialize();
updateStatus(ThingStatus.UNKNOWN);
}
public void setState(PrimitiveType state) {
this.updateState(SoulissBindingConstants.T6N_VALUE_CHANNEL, (DecimalType) state);
}
@Override
public void setRawState(byte rawState) {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public void setFloatValue(float valueOf) {
super.setLastStatusStored();
if (fSetPointValue != valueOf) {
this.setState(DecimalType.valueOf(Float.toString(valueOf)));
fSetPointValue = valueOf;
}
}
@Override
public byte getRawState() {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
public float getFloatState() {
return fSetPointValue;
}
@Override
public byte getExpectedRawState(byte bCommand) {
return -1;
}
}

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.PrimitiveType;
/**
* The {@link SoulissTopicsHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Luca Remigio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SoulissTopicsHandler extends SoulissGenericActionMessage implements TypicalCommonMethods {
private float fSetPointValue = 0xFFFF;
public SoulissTopicsHandler(Thing pThing) {
super(pThing);
thingGenActMsg = pThing;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
public void initialize() {
// status online
updateStatus(ThingStatus.ONLINE);
}
public void setState(PrimitiveType state) {
this.updateState(SoulissBindingConstants.T5N_VALUE_CHANNEL, (DecimalType) state);
}
public void setFloatValue(float valueOf) {
this.updateState(SoulissBindingConstants.LASTSTATUSSTORED_CHANNEL, this.getLastUpdateTime());
if (fSetPointValue != valueOf) {
this.setState(DecimalType.valueOf(Float.toString(valueOf)));
fSetPointValue = valueOf;
}
}
public float getFloatState() {
return fSetPointValue;
}
@Override
public void setRawState(byte rawState) {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
@Override
public byte getRawState() {
throw new UnsupportedOperationException("Not Implemented, yet.");
}
@Override
public byte getExpectedRawState(byte bCommand) {
return -1;
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
=======
* Copyright (c) 2014-2019 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.souliss.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Result callback interface.
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public interface TypicalCommonMethods {
void setRawState(byte rawState);
byte getRawState();
byte getExpectedRawState(byte bCommand);
}

View File

@@ -0,0 +1,499 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.channels.DatagramChannel;
import java.util.ArrayList;
import java.util.Enumeration;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissUDPConstants;
import org.openhab.binding.souliss.internal.config.GatewayConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provide to construct MaCaco and UDP frame
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Alessandro Del Pex - Souliss App
*/
@NonNullByDefault
public class CommonCommands {
private final Logger logger = LoggerFactory.getLogger(CommonCommands.class);
private static final String LITERAL_SEND_FRAME = "sendFORCEFrame - {}, soulissNodeIPAddressOnLAN: {}";
public final void sendFORCEFrame(GatewayConfig gwConfig, int idNode, int slot, byte shortCommand) {
sendFORCEFrame(gwConfig, idNode, slot, shortCommand, null, null, null);
}
/*
* used for set dimmer value. It set command at first byte and dimmerVal to
* second byte
*/
public final void sendFORCEFrame(GatewayConfig gwConfig, int idNode, int slot, byte shortCommand, byte lDimmer) {
sendFORCEFrame(gwConfig, idNode, slot, shortCommand, lDimmer, null, null);
}
/*
* send force frame with command and RGB value
*/
public final void sendFORCEFrame(GatewayConfig gwConfig, int idNode, int slot, byte shortCommand,
@Nullable Byte byte1, @Nullable Byte byte2, @Nullable Byte byte3) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x0);
// PUTIN
macacoFrame.add((byte) 0x0);
macacoFrame.add((byte) (idNode));// Start Offset
if (byte1 == null && byte2 == null && byte3 == null) {
// Number Of
macacoFrame.add((byte) ((byte) slot + 1));
} else if (byte2 == null && byte3 == null) {
// Number Of byte of payload= command + set byte
macacoFrame.add((byte) ((byte) slot + 2));
} else {
// Number Of byte of payload= OnOFF + Red + Green + Blu
macacoFrame.add((byte) ((byte) slot + 4));
}
for (var i = 0; i <= slot - 1; i++) {
// I set the bytes preceding the slot to be modified to zero
macacoFrame.add((byte) 00);
}
// PAYLOAD
macacoFrame.add(shortCommand);
if (byte1 != null && byte2 != null && byte3 != null) {
// PAYLOAD RED
macacoFrame.add(byte1);
// PAYLOAD GREEN
macacoFrame.add(byte2);
// PAYLOAD BLUE
macacoFrame.add(byte3);
} else if (byte1 != null) {
// PAYLOAD DIMMER
macacoFrame.add(byte1);
}
logger.debug(LITERAL_SEND_FRAME, macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/*
* T61 send frame to push the setpoint value
*/
public final void sendFORCEFrameT61SetPoint(GatewayConfig gwConfig, int idNode, int slot, Byte byte1, Byte byte2) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
// Start Offset
macacoFrame.add((byte) (idNode));
// Number Of byte of payload= command + set byte
macacoFrame.add((byte) ((byte) slot + 2));
for (var i = 0; i <= slot - 1; i++) {
// I set the bytes preceding the slot to be modified to zero
macacoFrame.add((byte) 00);
}
// PAYLOAD
// first byte Setpoint Value
macacoFrame.add(byte1);
// second byte Setpoint Value
macacoFrame.add(byte2);
logger.debug(LITERAL_SEND_FRAME, macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/*
* T31 send force frame with command and setpoint float
*/
public final void sendFORCEFrameT31SetPoint(GatewayConfig gwConfig, int idNode, int slot, byte shortCommand,
Byte byte1, Byte byte2) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
// Start Offset
macacoFrame.add((byte) (idNode));
// Number Of byte of payload= command + set byte
macacoFrame.add((byte) ((byte) slot + 5));
for (var i = 0; i <= slot - 1; i++) {
// prvious byte to zero
macacoFrame.add((byte) 00);
// slot to be changed
}
// PAYLOAD
macacoFrame.add(shortCommand);
// Empty - Temperature Measured Value
macacoFrame.add((byte) 0x0);
// Empty - Temperature Measured Value
macacoFrame.add((byte) 0x0);
// Temperature Setpoint Value
macacoFrame.add(byte1);
// Temperature Setpoint Value
macacoFrame.add(byte2);
logger.debug(LITERAL_SEND_FRAME, macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
public final void sendDBStructFrame(GatewayConfig gwConfig) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add((byte) SoulissUDPConstants.SOULISS_UDP_FUNCTION_DBSTRUCT_REQ);
// PUTIN
macacoFrame.add((byte) 0x0);
// PUTIN
macacoFrame.add((byte) 0x0);
// Start Offset
macacoFrame.add((byte) 0x0);
// Number Of
macacoFrame.add((byte) 0x0);
logger.debug("sendDBStructFrame - {}, soulissNodeIPAddressOnLAN: {}", macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/*
* Queue command to Dispatcher (for securesend retransmission)
*/
private final void queueToDispatcher(ArrayList<Byte> macacoFrame, GatewayConfig gwConfig) {
ArrayList<Byte> buf = buildVNetFrame(macacoFrame, gwConfig.gatewayLanAddress, (byte) gwConfig.userIndex,
(byte) gwConfig.nodeIndex);
byte[] merd = toByteArray(buf);
InetAddress serverAddr;
try {
serverAddr = gwConfig.gatewayWanAddress.isEmpty() ? InetAddress.getByName(gwConfig.gatewayLanAddress)
: InetAddress.getByName(gwConfig.gatewayWanAddress);
var packet = new DatagramPacket(merd, merd.length, serverAddr,
SoulissUDPConstants.SOULISS_GATEWAY_DEFAULT_PORT);
SendDispatcherRunnable.put(packet, logger);
} catch (IOException e) {
logger.warn("Error: {} ", e.getMessage());
}
}
/*
* send broadcast UDP frame - unused in this version
*/
private final void sendBroadcastNow(ArrayList<Byte> macacoFrame) {
byte iUserIndex = (byte) 120;
byte iNodeIndex = (byte) 70;
// Broadcast the message over all the network interfaces
Enumeration<@Nullable NetworkInterface> interfaces;
DatagramSocket sender = null;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
var networkInterface = interfaces.nextElement();
if (networkInterface != null) {
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue;
}
for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
var broadcast = new InetAddress[3];
broadcast[0] = InetAddress.getByName("224.0.0.1");
broadcast[1] = InetAddress.getByName("255.255.255.255");
broadcast[2] = interfaceAddress.getBroadcast();
for (InetAddress bc : broadcast) {
// Send the broadcast package!
if (bc != null) {
try {
ArrayList<Byte> buf = buildVNetFrame(macacoFrame, "255.255.255.255", iUserIndex,
iNodeIndex);
byte[] merd = toByteArray(buf);
var packet = new DatagramPacket(merd, merd.length, bc,
SoulissUDPConstants.SOULISS_GATEWAY_DEFAULT_PORT);
// Datagramsocket creation
var channel = DatagramChannel.open();
sender = channel.socket();
sender.setReuseAddress(true);
sender.setBroadcast(true);
var sa = new InetSocketAddress(230);
sender.bind(sa);
sender.send(packet);
logger.debug("Request packet sent to: {} Interface: {}", bc.getHostAddress(),
networkInterface.getDisplayName());
} catch (IOException e) {
logger.debug("IO error: {}", e.getMessage());
} catch (Exception e) {
logger.debug("{}", e.getMessage(), e);
} finally {
if ((sender != null) && (!sender.isClosed())) {
sender.close();
}
}
}
}
}
}
}
} catch (SocketException | UnknownHostException e) {
logger.warn("{}", e.getMessage());
}
}
/*
* Build VNet Frame
*/
private final ArrayList<Byte> buildVNetFrame(ArrayList<Byte> macacoFrame2, @Nullable String gatewayLanAddress,
byte iUserIndex, byte iNodeIndex) {
if (gatewayLanAddress != null) {
ArrayList<Byte> frame = new ArrayList<>();
InetAddress ip;
try {
ip = InetAddress.getByName(gatewayLanAddress);
} catch (UnknownHostException e) {
logger.warn("{}", e.getMessage());
return frame;
}
byte[] dude = ip.getAddress();
// Port
frame.add((byte) 23);
// es 192.168.1.XX BOARD
frame.add((byte) (dude[3] & 0xFF));
// n broadcast : communication by Ip
// 255.255.255.255 to associate vNet 0xFFFF address.
frame.add(gatewayLanAddress.compareTo(SoulissUDPConstants.BROADCASTADDR) == 0 ? dude[2] : 0);
// NODE INDEX - source vNet address User Interface
frame.add(iNodeIndex);
// USER INDEX - source vNet address User Interface
frame.add(iUserIndex);
// adds the calculation in the head
// Length
frame.add(0, (byte) (frame.size() + macacoFrame2.size() + 1));
// Length Check 2
frame.add(0, (byte) (frame.size() + macacoFrame2.size() + 1));
frame.addAll(macacoFrame2);
return frame;
} else {
throw new IllegalArgumentException("Cannot build VNet Frame . Null Souliss IP address");
}
}
/**
* Builds old-school byte array
*
* @param buf
* @return
*/
private final byte[] toByteArray(ArrayList<Byte> buf) {
var merd = new byte[buf.size()];
for (var i = 0; i < buf.size(); i++) {
merd[i] = buf.get(i);
}
return merd;
}
/**
* Build MULTICAST FORCE Frame
*/
public final void sendMULTICASTFORCEFrame(GatewayConfig gwConfig, byte typical, byte shortCommand) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE_MASSIVE);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x0);
// PUTIN
macacoFrame.add((byte) 0x0);
// Start Offset
macacoFrame.add(typical);
// Number Of
macacoFrame.add((byte) 1);
// PAYLOAD
macacoFrame.add(shortCommand);
logger.debug("sendMULTICASTFORCEFrame - {}, soulissNodeIPAddressOnLAN: {}", macacoToString(macacoFrame),
gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/**
* Build PING Frame
*/
public final void sendPing(@Nullable GatewayConfig gwConfig) {
if (gwConfig != null) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_PING_REQ);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
// Start Offset
macacoFrame.add((byte) 0x00);
// Number Of
macacoFrame.add((byte) 0x00);
logger.debug("sendPing - {}, IP: {} ", macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
} else {
logger.warn("Cannot send Souliss Ping - Ip null");
}
}
/**
* Build BROADCAST PING Frame
*/
public final void sendBroadcastGatewayDiscover() {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_REQ);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x05);
// PUTIN
macacoFrame.add((byte) 0x00);
// Start Offset
macacoFrame.add((byte) 0x00);
// Number Of
macacoFrame.add((byte) 0x00);
logger.debug("sendBroadcastPing - {} ", macacoToString(macacoFrame));
sendBroadcastNow(macacoFrame);
}
/**
* Build SUBSCRIPTION Frame
*/
public final void sendSUBSCRIPTIONframe(GatewayConfig gwConfig, int iNodes) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_SUBSCRIBE_REQ);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
macacoFrame.add((byte) 0x00);
macacoFrame.add((byte) iNodes);
logger.debug("sendSUBSCRIPTIONframe - {}, IP: {} ", macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/**
* Build HEALTHY REQUEST Frame
*/
public final void sendHealthyRequestFrame(GatewayConfig gwConfig, int iNodes) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_HEALTHY_REQ);
// PUTIN, STARTOFFSET, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
macacoFrame.add((byte) 0x00);
macacoFrame.add((byte) iNodes);
logger.debug("sendHealthyRequestFrame - {}, IP: {} ", macacoToString(macacoFrame), gwConfig);
queueToDispatcher(macacoFrame, gwConfig);
}
/**
* Build TYPICAL REQUEST Frame
*/
public final void sendTypicalRequestFrame(GatewayConfig gwConfig, int nodes) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_TYP_REQ);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
// startOffset
macacoFrame.add((byte) 0x00);
// iNodes
macacoFrame.add((byte) nodes);
logger.debug("sendTypicalRequestFrame - {}, IP: {} ", macacoToString(macacoFrame), gwConfig.gatewayLanAddress);
queueToDispatcher(macacoFrame, gwConfig);
}
/**
* Build TYPICAL REQUEST Frame with start offset
*/
public final void sendTypicalRequestFrame(GatewayConfig gwConfig, int start, int nodes) {
ArrayList<Byte> macacoFrame = new ArrayList<>();
macacoFrame.add(SoulissUDPConstants.SOULISS_UDP_FUNCTION_TYP_REQ);
// PUTIN, STARTOFFEST, NUMBEROF
// PUTIN
macacoFrame.add((byte) 0x00);
// PUTIN
macacoFrame.add((byte) 0x00);
// startOffset
macacoFrame.add((byte) start);
// iNodes
macacoFrame.add((byte) nodes);
logger.debug("sendTypicalRequestFrame - {}, IP: {} ", macacoToString(macacoFrame), gwConfig.gatewayLanAddress);
queueToDispatcher(macacoFrame, gwConfig);
}
boolean flag = true;
private final String macacoToString(ArrayList<Byte> mACACOframe) {
// I copy arrays to avoid concurrent changes
ArrayList<Byte> mACACOframe2 = new ArrayList<>();
mACACOframe2.addAll(mACACOframe);
flag = false;
var sb = new StringBuilder();
sb.append("HEX: [");
for (byte b : mACACOframe2) {
sb.append(String.format("%02X ", b));
}
sb.append("]");
flag = true;
return sb.toString();
}
}

View File

@@ -0,0 +1,115 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Helper class to conver half precision float to int int are used on analogue
* typicals (2 bytes) and should be reversed because of endianess
* http://stackoverflow.com/users/237321/x4u
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public final class HalfFloatUtils {
public static boolean isNaN(float x) {
return x != x;
}
// ignores the higher 16 bits
public static float toFloat(int hbits) {
// 10 bits mantissa
int mant = hbits & 0x03ff;
// 5 bits exponent
int exp = hbits & 0x7c00;
if (exp == 0x7c00) {
// -> NaN/Inf
exp = 0x3fc00;
// normalized value
} else if (exp != 0) {
// exp - 15 + 127
exp += 0x1c000;
if (mant == 0 && exp > 0x1c400) {
return Float.intBitsToFloat((hbits & 0x8000) << 16 | exp << 13 | 0x3ff);
}
// && exp==0 -> subnormal
} else if (mant != 0) {
// make it normal
exp = 0x1c400;
do {
// mantissa * 2
mant <<= 1;
// decrease exp by 1
exp -= 0x400;
// while not normal
} while ((mant & 0x400) == 0);
// discard subnormal bit
mant &= 0x3ff;
// else +/-0 -> +/-0
}
// combine all parts
return Float.intBitsToFloat(
// sign << ( 31 - 15 )
(hbits & 0x8000) << 16
// value << ( 23 - 10 )
| (exp | mant) << 13);
}
// returns all higher 16 bits as 0 for all results
public static int fromFloat(float fval) {
var fbits = Float.floatToIntBits(fval);
// sign only
int sign = fbits >>> 16 & 0x8000;
// rounded value
int val = (fbits & 0x7fffffff) + 0x1000;
// might be or become NaN/Inf
if (val >= 0x47800000)
// avoid Inf due to rounding
{
// is or must become
// NaN/Inf
if ((fbits & 0x7fffffff) >= 0x47800000) {
if (val < 0x7f800000) {
// make it +/-Inf
return sign | 0x7c00;
}
// remains +/-Inf or NaN
return sign | 0x7c00 |
// keep NaN (and Inf) bits
(fbits & 0x007fffff) >>> 13;
}
// unrounded not quite Inf
return sign | 0x7bff;
}
if (val >= 0x38800000) {
// exp - 127 + 15
return sign | val - 0x38000000 >>> 13;
}
if (val < 0x33000000) {
// becomes +/-0
return sign;
}
// tmp exp for subnormal calc
val = (fbits & 0x7fffffff) >>> 23;
// add subnormal bit
return sign | ((fbits & 0x7fffff | 0x800000)
// round depending on cut off
+ (0x800000 >>> val - 102)
// div by 2^(1-(exp-127+15)) and >> 13 | exp=0
>>> 126 - val);
}
}

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import java.net.DatagramPacket;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Data Structure for class SendDispatcherThread
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class PacketStruct {
private DatagramPacket packet;
public DatagramPacket getPacket() {
return packet;
}
private boolean sent = false;
private long time = 0;
public PacketStruct(DatagramPacket packetPar) {
packet = packetPar;
}
public long getTime() {
return time;
}
public boolean getSent() {
return sent;
}
public void setSent(boolean sent) {
this.sent = sent;
}
public void setTime(long time) {
// set the time only if it has not already been set once
if (this.time == 0) {
this.time = time;
}
}
}

View File

@@ -0,0 +1,442 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissUDPConstants;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.binding.souliss.internal.handler.SoulissGenericHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provide to take packet, and send it to regular interval to Souliss
* Network
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
*/
@NonNullByDefault
public class SendDispatcherRunnable implements Runnable {
private final Logger logger = LoggerFactory.getLogger(SendDispatcherRunnable.class);
private @Nullable SoulissGatewayHandler gwHandler;
static boolean bPopSuspend = false;
protected static ArrayList<PacketStruct> packetsList = new ArrayList<>();
private long startTime = System.currentTimeMillis();
static int iDelay = 0; // equal to 0 if array is empty
static int sendMinDelay = 0;
public SendDispatcherRunnable(Bridge bridge) {
this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
}
/**
* Put packet to send in ArrayList PacketList
*/
public static synchronized void put(DatagramPacket packetToPUT, Logger logger) {
bPopSuspend = true;
var bPacchettoGestito = false;
// I extract the node addressed by the incoming packet. returns -1 if the package is not of the
// SOULISS_UDP_FUNCTION_FORCE type
int node = getNode(packetToPUT);
if (node >= 0) {
logger.debug("Push packet in queue - Node {}", node);
}
if (packetsList.isEmpty() || node < 0) {
bPacchettoGestito = false;
} else {
// OPTIMIZER
// scan packets list to sent
for (var i = 0; i < packetsList.size(); i++) {
if (node >= 0 && getNode(packetsList.get(i).getPacket()) == node && !packetsList.get(i).getSent()) {
// frame for the same node already present in the list
logger.debug("Frame UPD per nodo {} già presente in coda. Esecuzione ottimizzazione.", node);
bPacchettoGestito = true;
// if the packet to be inserted is shorter (or equal) than the one in the queue
// then I overwrite the bytes of the packet present in the queue
if (packetToPUT.getData().length <= packetsList.get(i).getPacket().getData().length) {
// it scrolls the command bytes and if the byte is non-zero overwrites the byte present in the
// queued packet
logger.trace("Optimizer. Packet to push: {}", macacoToString(packetToPUT.getData()));
logger.trace("Optimizer. Previous frame: {}",
macacoToString(packetsList.get(i).getPacket().getData()));
// typical values start from byte 12 onwards
for (var j = 12; j < packetToPUT.getData().length; j++) {
// if the j-th byte is different from zero then
// I overwrite it with the byte of the packet already present
if (packetToPUT.getData()[j] != 0) {
packetsList.get(i).getPacket().getData()[j] = packetToPUT.getData()[j];
}
}
logger.debug("Optimizer. Previous frame modified to: {}",
macacoToString(packetsList.get(i).getPacket().getData()));
} else {
// if the packet to be inserted is longer than the one in the list then
// I overwrite the bytes of the packet to be inserted, then I delete the one in the list
// and insert the new one
if (packetToPUT.getData().length > packetsList.get(i).getPacket().getData().length) {
for (var j = 12; j < packetsList.get(i).getPacket().getData().length; j++) {
// if the j-th byte is different from zero then I overwrite it with the byte of the
// packet already present
if ((packetsList.get(i).getPacket().getData()[j] != 0)
&& (packetToPUT.getData()[j] == 0)) {
// overwrite the bytes of the last frame
// only if the byte equals zero.
// If the last frame is nonzero
// takes precedence and must override
packetToPUT.getData()[j] = packetsList.get(i).getPacket().getData()[j];
}
}
// removes the packet
logger.debug("Optimizer. Remove frame: {}",
macacoToString(packetsList.get(i).getPacket().getData()));
packetsList.remove(i);
// inserts the new
logger.debug("Optimizer. Add frame: {}", macacoToString(packetToPUT.getData()));
packetsList.add(new PacketStruct(packetToPUT));
}
}
}
}
}
if (!bPacchettoGestito) {
logger.debug("Add packet: {}", macacoToString(packetToPUT.getData()));
packetsList.add(new PacketStruct(packetToPUT));
}
bPopSuspend = false;
}
@Override
public void run() {
DatagramSocket sender = null;
try (var channel = DatagramChannel.open();) {
if (checkTime()) {
PacketStruct sp = pop();
if (sp != null) {
logger.debug(
"SendDispatcherJob - Functional Code 0x{} - Packet: {} - Elementi rimanenti in lista: {}",
Integer.toHexString(sp.getPacket().getData()[7]), macacoToString(sp.getPacket().getData()),
packetsList.size());
sender = channel.socket();
sender.setReuseAddress(true);
sender.setBroadcast(true);
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
var sa = new InetSocketAddress(localGwHandler.getGwConfig().preferredLocalPortNumber);
sender.bind(sa);
sender.send(sp.getPacket());
}
}
// compare the states in memory with the frames sent.
// If match deletes the frame from the sent list
safeSendCheck();
resetTime();
}
} catch (Exception e) {
logger.warn("{}", e.getMessage());
} finally {
if (sender != null && !sender.isClosed()) {
sender.close();
}
}
}
/**
* Get node number from packet
*/
private static int getNode(DatagramPacket packet) {
// 7 is the byte of the VNet frame at which I find the command code
// 10 is the byte of the VNet frame at which I find the node ID
if (packet.getData()[7] == SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE) {
return packet.getData()[10];
}
return -1;
}
private static String macacoToString(byte[] frame2) {
byte[] frame = frame2.clone();
var sb = new StringBuilder();
sb.append("HEX: [");
for (byte b : frame) {
sb.append(String.format("%02X ", b));
}
sb.append("]");
return sb.toString();
}
/**
* check frame updates with packetList, where flag "sent" is true. If all
* commands was executed there delete packet in list.
*/
public void safeSendCheck() {
int node;
int iSlot;
SoulissGenericHandler localTyp;
var sCmd = "";
byte bExpected;
var sExpected = "";
// scan of the sent packets list
for (var i = 0; i < packetsList.size(); i++) {
if (packetsList.get(i).getSent()) {
node = getNode(packetsList.get(i).getPacket());
iSlot = 0;
for (var j = 12; j < packetsList.get(i).getPacket().getData().length; j++) {
// I check the slot only if the command is different from ZERO
if ((packetsList.get(i).getPacket().getData()[j] != 0) && (this.gwHandler != null)) {
localTyp = getHandler(node, iSlot, this.logger);
if (localTyp != null) {
bExpected = localTyp.getExpectedRawState(packetsList.get(i).getPacket().getData()[j]);
// if the expected value of the typical is -1 then it means that the typical does not
// support the
// function
// secureSend
if (bExpected < 0) {
localTyp = null;
}
// translate the command sent with the expected state e
// then compare with the current state
if (logger.isDebugEnabled() && localTyp != null) {
sCmd = Integer.toHexString(packetsList.get(i).getPacket().getData()[j]);
// command sent
sCmd = sCmd.length() < 2 ? "0x0" + sCmd.toUpperCase() : "0x" + sCmd.toUpperCase();
sExpected = Integer.toHexString(bExpected);
sExpected = sExpected.length() < 2 ? "0x0" + sExpected.toUpperCase()
: "0x" + sExpected.toUpperCase();
logger.debug(
"Compare. Node: {} Slot: {} Node Name: {} Command: {} Expected Souliss State: {} - Actual OH item State: {}",
node, iSlot, localTyp.getLabel(), sCmd, sExpected, localTyp.getRawState());
}
if (localTyp != null && checkExpectedState(localTyp.getRawState(), bExpected)) {
// if the value of the typical matches the value
// transmitted then I set the byte to zero.
// when all bytes are equal to zero then
// delete the frame
packetsList.get(i).getPacket().getData()[j] = 0;
logger.debug("{} Node: {} Slot: {} - OK Expected State", localTyp.getLabel(), node,
iSlot);
} else if (localTyp == null) {
if (bExpected < 0) {
// if the typical is not managed then I set the byte of the relative slot to zero
packetsList.get(i).getPacket().getData()[j] = 0;
} else {
// if there is no typical at slot j then it means that it is one
// slot
// connected
// to the previous one (ex: RGB, T31, ...)
// then if slot j-1 = 0 then j can also be set to 0
if (packetsList.get(i).getPacket().getData()[j - 1] == 0) {
packetsList.get(i).getPacket().getData()[j] = 0;
}
}
}
}
}
iSlot++;
}
// if the value of all bytes that make up the packet is 0 then I remove the packet from
// list
// also if the timout has elapsed then I set the packet to be resent
if (checkAllsSlotZero(packetsList.get(i).getPacket())) {
logger.debug("Command packet executed - Removed");
packetsList.remove(i);
} else {
// if the frame is not equal to zero I check the TIMEOUT and if
// it has expired so I set the SENT flag to false
long time = System.currentTimeMillis();
SoulissGatewayHandler localGwHandler = this.gwHandler;
if (localGwHandler != null) {
if ((localGwHandler.getGwConfig().timeoutToRequeue < time - packetsList.get(i).getTime())
&& (localGwHandler.getGwConfig().timeoutToRemovePacket < time
- packetsList.get(i).getTime())) {
logger.debug("Packet Execution timeout - Removed");
packetsList.remove(i);
} else {
logger.debug("Packet Execution timeout - Requeued");
packetsList.get(i).setSent(false);
}
}
}
}
}
}
private @Nullable SoulissGenericHandler getHandler(int node, int slot, Logger logger) {
SoulissGatewayHandler localGwHandler = this.gwHandler;
Iterator<Thing> thingsIterator;
if (localGwHandler != null) {
thingsIterator = localGwHandler.getThing().getThings().iterator();
Thing typ = null;
while (thingsIterator.hasNext()) {
typ = thingsIterator.next();
if (typ.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
continue;
}
SoulissGenericHandler handler = (SoulissGenericHandler) typ.getHandler();
// execute it only if binding is Souliss and update is for my
// Gateway
if ((handler != null) && (handler.getNode() == node && handler.getSlot() == slot)) {
return handler;
}
}
}
return null;
}
private static boolean checkExpectedState(byte itemState, byte expectedState) {
// if expected state is null than return true. The frame will not requeued
if (expectedState <= -1) {
return true;
}
return itemState == expectedState;
}
private static boolean checkAllsSlotZero(DatagramPacket packet) {
var bflag = true;
for (var j = 12; j < packet.getData().length; j++) {
if ((packet.getData()[j] != 0)) {
bflag = false;
}
}
return bflag;
}
long t = 0;
long tPrec = 0;
/**
* Pop SocketAndPacket from ArrayList PacketList
*/
@Nullable
private synchronized PacketStruct pop() {
synchronized (this) {
SoulissGatewayHandler localGwHandler = this.gwHandler;
// don't pop if bPopSuspend = true
// bPopSuspend is set by the put method
if ((localGwHandler != null) && (!bPopSuspend)) {
t = System.currentTimeMillis();
// brings the interval to the minimum only if:
// the length of the tail less than or equal to 1;
// if the SEND_DELAY time has elapsed.
if (packetsList.size() <= 1) {
iDelay = sendMinDelay;
} else {
iDelay = localGwHandler.getGwConfig().sendInterval;
}
var iPacket = 0;
var bFlagWhile = true;
// discard packages already sent
while ((iPacket < packetsList.size()) && bFlagWhile) {
if (packetsList.get(iPacket).getSent()) {
iPacket++;
} else {
bFlagWhile = false;
}
}
boolean tFlag = (t - tPrec) >= localGwHandler.getGwConfig().sendInterval;
// if we have reached the end of the list and then all
// packets have already been sent so I also place the tFlag
// to false (as if the timeout hasn't elapsed yet)
if (iPacket >= packetsList.size()) {
tFlag = false;
}
if ((!packetsList.isEmpty()) && tFlag) {
tPrec = System.currentTimeMillis();
// extract the first element of the list
PacketStruct sp = packetsList.get(iPacket);
// PACKAGE MANAGEMENT: deleted from the list or
// marked as sent if it is a FORCE
if (packetsList.get(iPacket).getPacket()
.getData()[7] == SoulissUDPConstants.SOULISS_UDP_FUNCTION_FORCE) {
// flag sent set to true
packetsList.get(iPacket).setSent(true);
// set time
packetsList.get(iPacket).setTime(System.currentTimeMillis());
} else {
packetsList.remove(iPacket);
}
logger.debug("POP: {} packets in memory", packetsList.size());
if (logger.isDebugEnabled()) {
var iPacketSentCounter = 0;
var i = 0;
while ((i < packetsList.size())) {
if (packetsList.get(i).getSent()) {
iPacketSentCounter++;
}
i++;
}
logger.debug("POP: {} force frame sent", iPacketSentCounter);
}
logger.debug("Pop frame {} - Delay for 'SendDispatcherThread' setted to {} mills.",
macacoToString(sp.getPacket().getData()), iDelay);
return sp;
}
}
}
return null;
}
private void resetTime() {
startTime = System.currentTimeMillis();
}
private boolean checkTime() {
return startTime < (System.currentTimeMillis() - iDelay);
}
}

View File

@@ -0,0 +1,586 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.SoulissBindingConstants;
import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
import org.openhab.binding.souliss.internal.SoulissUDPConstants;
import org.openhab.binding.souliss.internal.discovery.DiscoverResult;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.binding.souliss.internal.handler.SoulissGenericHandler;
import org.openhab.binding.souliss.internal.handler.SoulissT11Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT12Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT13Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT14Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT16Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT18Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT19Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT1AHandler;
import org.openhab.binding.souliss.internal.handler.SoulissT22Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT31Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT41Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT42Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT5nHandler;
import org.openhab.binding.souliss.internal.handler.SoulissT61Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT62Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT63Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT64Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT65Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT66Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT67Handler;
import org.openhab.binding.souliss.internal.handler.SoulissT68Handler;
import org.openhab.binding.souliss.internal.handler.SoulissTopicsHandler;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.ThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class decodes incoming Souliss packets, starting from decodevNet
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Alessandro Del Pex - Souliss App
*/
@NonNullByDefault
public class UDPDecoder {
private final Logger logger = LoggerFactory.getLogger(UDPDecoder.class);
private @Nullable DiscoverResult discoverResult;
private @Nullable SoulissGatewayHandler gwHandler;
private @Nullable Byte lastByteGatewayIp = null;
public UDPDecoder(Bridge bridge, @Nullable DiscoverResult pDiscoverResult) {
this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
this.discoverResult = pDiscoverResult;
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
this.lastByteGatewayIp = (byte) Integer
.parseInt(localGwHandler.getGwConfig().gatewayLanAddress.split("\\.")[3]);
}
}
/**
* Get packet from VNET Frame
*
* @param packet
* incoming datagram
*/
public void decodeVNetDatagram(DatagramPacket packet) {
int checklen = packet.getLength();
ArrayList<Byte> mac = new ArrayList<>();
for (var ig = 7; ig < checklen; ig++) {
mac.add((byte) (packet.getData()[ig] & 0xFF));
}
// Check if decoded Gw equal to ip of bridge handler or 1 (action messages)
Byte gwCheck = (byte) (packet.getData()[5] & 0xFF);
if ((gwCheck == 1) || (gwCheck.equals(this.lastByteGatewayIp))) {
decodeMacaco((byte) (packet.getData()[5] & 0xFF), mac);
}
}
/**
* Decodes lower level MaCaCo packet
*
* @param lastByteGatewayIP
*
* @param macacoPck
*/
private void decodeMacaco(byte lastByteGatewayIP, ArrayList<Byte> macacoPck) {
int functionalCode = macacoPck.get(0);
switch (functionalCode) {
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_PING_RESP:
logger.debug("Received functional code: 0x{}- Ping answer", Integer.toHexString(functionalCode));
decodePing(macacoPck);
break;
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_RESP:
logger.debug("Received functional code: 0x{} - Discover a gateway node answer (broadcast)",
Integer.toHexString(functionalCode));
try {
decodePingBroadcast(macacoPck);
} catch (UnknownHostException e) {
logger.warn("Error: {}", e.getLocalizedMessage());
}
break;
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_POLL_RESP:
logger.debug("Received functional code: 0x{} - subscribe response",
Integer.toHexString(functionalCode));
decodeStateRequest(macacoPck);
break;
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_SUBSCRIBE_RESP:
logger.debug("Received functional code: 0x{} - Read state answer", Integer.toHexString(functionalCode));
decodeStateRequest(macacoPck);
break;
// Answer for assigned typical logic
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_TYP_RESP:
logger.debug("Received functional code: 0x{}- Read typical logic answer",
Integer.toHexString(functionalCode));
decodeTypRequest(lastByteGatewayIP, macacoPck);
break;
// Answer
case SoulissUDPConstants.SOULISS_UDP_FUNCTION_HEALTHY_RESP:
// nodes healthy
logger.debug("Received functional code: 0x{} - Nodes Healthy", Integer.toHexString(functionalCode));
decodeHealthyRequest(macacoPck);
break;
case (byte) SoulissUDPConstants.SOULISS_UDP_FUNCTION_DBSTRUCT_RESP:
logger.debug("Received functional code: 0x{} - Database structure answer",
Integer.toHexString(functionalCode));
decodeDBStructRequest(macacoPck);
break;
case 0x83:
logger.debug("Functional code not supported");
break;
case 0x84:
logger.debug("Data out of range");
break;
case 0x85:
logger.debug("Subscription refused");
break;
case (byte) SoulissUDPConstants.SOULISS_UDP_FUNCTION_ACTION_MESSAGE:
logger.debug("Received functional code: 0x{} - Action Message (Topic)",
Integer.toHexString(functionalCode));
decodeActionMessages(macacoPck);
break;
default:
logger.debug("Received functional code: 0x{} - unused by OH Binding",
Integer.toHexString(functionalCode));
}
}
/**
* @param mac
*/
private void decodePing(ArrayList<Byte> mac) {
// not used
int putIn1 = mac.get(1);
// not used
int putIn2 = mac.get(2);
logger.debug("decodePing: putIn code: {}, {}", putIn1, putIn2);
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
localGwHandler.gatewayDetected();
}
}
private void decodePingBroadcast(ArrayList<Byte> macaco) throws UnknownHostException {
String ip = macaco.get(5) + "." + macaco.get(6) + "." + macaco.get(7) + "." + macaco.get(8);
byte[] addr = { (macaco.get(5)).byteValue(), (macaco.get(6)).byteValue(), (macaco.get(7)).byteValue(),
(macaco.get(8)).byteValue() };
logger.debug("decodePingBroadcast. Gateway Discovery. IP: {}", ip);
var localDiscoverResult = this.discoverResult;
if (localDiscoverResult != null) {
localDiscoverResult.gatewayDetected(InetAddress.getByAddress(addr), macaco.get(8).toString());
} else {
logger.debug("decodePingBroadcast aborted. 'discoverResult' is null");
}
}
/**
* decode Typicals Request Packet
* It read Souliss Network and create OH items
*
* @param lastByteGatewayIP
*
* @param mac
*/
private void decodeTypRequest(byte lastByteGatewayIP, ArrayList<Byte> mac) {
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
int typXnodo = localGwHandler.getMaxTypicalXnode();
byte tgtnode = mac.get(3);
int numberOf = mac.get(4);
// creates Souliss nodes
for (var j = 0; j < numberOf; j++) {
// create only not-empty typicals
if ((mac.get(5 + j) != 0) && (mac.get(5 + j) != SoulissProtocolConstants.SOULISS_T_RELATED)) {
byte typical = mac.get(5 + j);
byte slot = (byte) (j % typXnodo);
byte node = (byte) (j / typXnodo + tgtnode);
logger.debug("Thing Detected. IP (last byte): {}, Typical: 0x{}, Node: {}, Slot: {} ",
lastByteGatewayIP, Integer.toHexString(typical), node, slot);
var localDiscoverResult = this.discoverResult;
if (localDiscoverResult != null) {
localDiscoverResult.thingDetectedTypicals(lastByteGatewayIP, typical, node, slot);
} else {
logger.debug("decodeTypRequest aborted. 'discoverResult' is null");
}
}
}
}
}
/**
* decode Typicals Request Packet
* It read Action Messages on Souliss Network and create items
*
* @param lastByteGatewayIP
*
* @param mac
*/
private void decodeActionMessages(ArrayList<Byte> mac) {
String sTopicNumber;
String sTopicVariant;
float fRet = 0;
try {
// A 16-bit Topic Number: Define the topic itself
// A 8-bit Topic Variant : Define a variant for the topic
String[] sTopicNumberArray = { Integer.toHexString(mac.get(2)).toUpperCase(),
Integer.toHexString(mac.get(1)).toUpperCase() };
if (sTopicNumberArray[0].length() == 1) {
sTopicNumberArray[0] = "0" + sTopicNumberArray[0];
}
if (sTopicNumberArray[1].length() == 1) {
sTopicNumberArray[1] = "0" + sTopicNumberArray[1];
}
sTopicNumber = sTopicNumberArray[0] + sTopicNumberArray[1];
logger.debug("Topic Number: 0x{}", sTopicNumber);
sTopicVariant = Integer.toHexString(mac.get(3)).toUpperCase();
if (sTopicVariant.length() == 1) {
sTopicVariant = "0" + sTopicVariant;
}
logger.debug("Topic Variant: 0x{}", sTopicVariant);
if (mac.get(4) == 1) {
fRet = mac.get(5);
logger.debug("Topic Value (Payload one byte): {} ", Integer.toHexString(mac.get(5)).toUpperCase());
} else if (mac.get(4) == 2) {
byte[] value = { mac.get(5), mac.get(6) };
int shifted = value[1] << 8;
fRet = HalfFloatUtils.toFloat(shifted + value[0]);
logger.debug("Topic Value (Payload 2 bytes): {}", fRet);
}
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
var listThings = localGwHandler.getThing().getThings();
Boolean bIsPresent = false;
for (Thing t : listThings) {
if (t.getUID().toString().split(":")[2]
.equals(sTopicNumber + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + sTopicVariant)) {
var topicHandler = (SoulissTopicsHandler) (t.getHandler());
if (topicHandler != null) {
topicHandler.setState(DecimalType.valueOf(Float.toString(fRet)));
bIsPresent = true;
}
}
}
var localDiscoverResult = this.discoverResult;
if (localDiscoverResult != null && !bIsPresent) {
localDiscoverResult.thingDetectedActionMessages(sTopicNumber, sTopicVariant);
}
}
} catch (Exception uy) {
logger.warn("decodeActionMessages ERROR");
}
}
/**
* decode DB Struct Request Packet
* It return Souliss Network:
* node number
* max supported number of nodes
* max typical per node
* max requests
* See Souliss wiki for details
*
* @param lastByteGatewayIP
*
* @param mac
*/
private void decodeDBStructRequest(ArrayList<Byte> mac) {
int nodes = mac.get(5);
int maxTypicalXnode = mac.get(7);
SoulissGatewayHandler localGwHandler = this.gwHandler;
if (localGwHandler != null) {
localGwHandler.setNodes(nodes);
localGwHandler.setMaxTypicalXnode(maxTypicalXnode);
localGwHandler.dbStructAnswerReceived();
}
}
/**
* Decodes a souliss nodes health request
*
* @param macaco
* packet
*/
private void decodeHealthyRequest(ArrayList<Byte> mac) {
int numberOf = mac.get(4);
for (var i = 5; i < 5 + numberOf; i++) {
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
// build an array containing healths
List<Thing> listaThings = localGwHandler.getThing().getThings();
ThingHandler handler = null;
for (Thing thing : listaThings) {
if (thing.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
continue;
}
handler = thing.getHandler();
if (handler != null) {
int tgtnode = i - 5;
if (((SoulissGenericHandler) handler).getNode() == tgtnode) {
((SoulissGenericHandler) handler).setHealthy((mac.get(i)));
}
} else {
logger.debug("decode Healthy Request Warning. Thing handler is null");
}
}
}
}
}
private void decodeStateRequest(ArrayList<Byte> mac) {
int tgtnode = mac.get(3);
Iterator<Thing> thingsIterator = null;
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
thingsIterator = localGwHandler.getThing().getThings().iterator();
var bFound = false;
Thing typ = null;
while (thingsIterator.hasNext() && !bFound) {
typ = thingsIterator.next();
// if a topic continue
// ignoring it
if (typ.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
continue;
}
String[] sUIDArray = typ.getUID().getAsString().split(":");
ThingHandler handler = typ.getHandler();
// execute it only if binding is Souliss and update is for my
// Gateway
if (handler != null) {
// execute it
// only
// if it is
// node
// to update
if (((SoulissGenericHandler) handler).getNode() == tgtnode) {
// ...now check slot
int slot = ((SoulissGenericHandler) handler).getSlot();
// get typical value
var sVal = getByteAtSlot(mac, slot);
var decodingLiteralLabel = "Decoding {}{}";
var packetLabel = " packet";
// update Txx
switch (sUIDArray[1]) {
case SoulissBindingConstants.T11:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T11, packetLabel);
((SoulissT11Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T12:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T12, packetLabel);
((SoulissT12Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T13:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T13, packetLabel);
((SoulissT13Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T14:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T14, packetLabel);
((SoulissT14Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T16:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T16, packetLabel);
((SoulissT16Handler) handler).setRawStateCommand(sVal);
((SoulissT16Handler) handler).setRawStateRgb(getByteAtSlot(mac, slot + 1),
getByteAtSlot(mac, slot + 2), getByteAtSlot(mac, slot + 3));
break;
case SoulissBindingConstants.T18:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T18, packetLabel);
((SoulissT18Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T19:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T19, packetLabel);
((SoulissT19Handler) handler).setRawState(sVal);
((SoulissT19Handler) handler).setRawStateDimmerValue(getByteAtSlot(mac, slot + 1));
break;
case SoulissBindingConstants.T1A:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T1A, packetLabel);
((SoulissT1AHandler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T21:
case SoulissBindingConstants.T22:
logger.debug(decodingLiteralLabel,
SoulissBindingConstants.T21 + "/" + SoulissBindingConstants.T22, packetLabel);
((SoulissT22Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T31:
logger.debug("Decoding {}/{}", SoulissBindingConstants.T31,
SoulissBindingConstants.T31);
logger.debug("packet: ");
logger.debug("- bit0 (system on-off): {}", getBitState(sVal, 0));
logger.debug("- bit1 (heating on-off): {}", getBitState(sVal, 1));
logger.debug("- bit2 (cooling on-off): {}", getBitState(sVal, 2));
logger.debug("- bit3 (fan1 on-off): {}", getBitState(sVal, 3));
logger.debug("- bit4 (fan2 on-off): {}", getBitState(sVal, 4));
logger.debug("- bit5 (fan3 on-off): {}", getBitState(sVal, 5));
logger.debug("- bit6 (Manual/automatic fan mode): {}", getBitState(sVal, 6));
logger.debug("- bit7 (heating/cooling mode): {}", getBitState(sVal, 7));
((SoulissT31Handler) handler).setRawStateValues(sVal, getFloatAtSlot(mac, slot + 1),
getFloatAtSlot(mac, slot + 3));
break;
case SoulissBindingConstants.T41:
((SoulissT41Handler) handler).setRawState(sVal);
break;
case SoulissBindingConstants.T42:
((SoulissT42Handler) handler).setRawState(sVal);
switch (sVal) {
case SoulissProtocolConstants.SOULISS_T4N_NO_ANTITHEFT:
((SoulissT42Handler) handler).setState(StringType
.valueOf(SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL));
break;
case SoulissProtocolConstants.SOULISS_T4N_ALARM:
((SoulissT42Handler) handler).setState(StringType
.valueOf(SoulissBindingConstants.T4N_ALARMON_MESSAGE_CHANNEL));
break;
default:
break;
}
break;
case SoulissBindingConstants.T51:
case SoulissBindingConstants.T52:
case SoulissBindingConstants.T53:
case SoulissBindingConstants.T54:
case SoulissBindingConstants.T55:
case SoulissBindingConstants.T56:
case SoulissBindingConstants.T57:
case SoulissBindingConstants.T58:
logger.debug("Decoding T5n packet");
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT5nHandler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T61:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T61, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT61Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T62:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T62, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT62Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T63:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T63, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT63Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T64:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T64, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT64Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T65:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T65, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT65Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T66:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T66, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT66Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T67:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T67, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT67Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.T68:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.T68, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissT68Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
case SoulissBindingConstants.TOPICS:
logger.debug(decodingLiteralLabel, SoulissBindingConstants.TOPICS, packetLabel);
if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
((SoulissTopicsHandler) handler).setFloatValue(getFloatAtSlot(mac, slot));
}
break;
default:
logger.debug("Unsupported typical");
}
}
}
}
}
}
private byte getByteAtSlot(ArrayList<Byte> mac, int slot) {
return mac.get(5 + slot);
}
private float getFloatAtSlot(ArrayList<Byte> mac, int slot) {
int iOutput = mac.get(5 + slot) & 0xFF;
int iOutput2 = mac.get(5 + slot + 1) & 0xFF;
// we have two bytes, convert them...
int shifted = iOutput2 << 8;
return HalfFloatUtils.toFloat(shifted + iOutput);
}
public byte getBitState(byte vRaw, int iBit) {
final var maskBit1 = 0x1;
if (((vRaw >>> iBit) & maskBit1) == 0) {
return 0;
} else {
return 1;
}
}
}

View File

@@ -0,0 +1,116 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.souliss.internal.protocol;
import java.net.BindException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.channels.DatagramChannel;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.souliss.internal.discovery.DiscoverResult;
import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class provide receive packet from network
*
* @author Tonino Fazio - Initial contribution
* @author Luca Calcaterra - Refactor for OH3
* @author Alessandro Del Pex - Souliss App
*/
@NonNullByDefault
public class UDPListenDiscoverRunnable implements Runnable {
protected boolean bExit = false;
private @Nullable UDPDecoder decoder = null;
private final Logger logger = LoggerFactory.getLogger(UDPListenDiscoverRunnable.class);
private @Nullable SoulissGatewayHandler gwHandler;
public UDPListenDiscoverRunnable(Bridge bridge, @Nullable DiscoverResult pDiscoverResult) {
this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
decoder = new UDPDecoder(bridge, pDiscoverResult);
}
@Override
public void run() {
DatagramSocket socket = null;
while (!Thread.currentThread().isInterrupted()) {
try {
// open socket for listening...
var channel = DatagramChannel.open();
socket = channel.socket();
socket.setReuseAddress(true);
socket.setBroadcast(true);
var localGwHandler = this.gwHandler;
if (localGwHandler != null) {
var sa = new InetSocketAddress(localGwHandler.getGwConfig().preferredLocalPortNumber);
socket.bind(sa);
var buf = new byte[200];
// receive request
final var packet = new DatagramPacket(buf, buf.length);
socket.setSoTimeout(60000);
socket.receive(packet);
buf = packet.getData();
// **************** DECODER ********************
logger.debug("Packet received (port {}) {}", socket.getLocalPort(), HexUtils.bytesToHex(buf));
var localDecoder = this.decoder;
if (localDecoder != null) {
localDecoder.decodeVNetDatagram(packet);
}
}
} catch (BindException e) {
logger.warn("UDP Port busy, Souliss already listening? {} ", e.getLocalizedMessage());
try {
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (Exception e1) {
logger.warn("UDP socket close failed: {} ", e1.getLocalizedMessage());
}
} catch (SocketTimeoutException e2) {
logger.warn("UDP SocketTimeoutException close: {}", e2.getLocalizedMessage());
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (Exception ee) {
logger.warn("Exception receiving-decoding message: {} ", ee.getLocalizedMessage());
if (socket != null && !socket.isClosed()) {
socket.close();
}
} finally {
var localGwHandler = this.gwHandler;
if (socket != null && !socket.isClosed()) {
socket.close();
} else if ((socket == null) && (localGwHandler != null)) {
localGwHandler.setBridgeStatus(false);
}
}
}
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="souliss" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>Souliss Binding</name>
<description>This is the binding for Souliss. The Arduino based SmartHome..</description>
</binding:binding>