[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 8103 additions and 0 deletions

View File

@ -283,6 +283,7 @@
/bundles/org.openhab.binding.sonos/ @kgoderis @lolodomo /bundles/org.openhab.binding.sonos/ @kgoderis @lolodomo
/bundles/org.openhab.binding.sonyaudio/ @freke /bundles/org.openhab.binding.sonyaudio/ @freke
/bundles/org.openhab.binding.sonyprojector/ @lolodomo /bundles/org.openhab.binding.sonyprojector/ @lolodomo
/bundles/org.openhab.binding.souliss/ @lucacalcaterra @fazioa
/bundles/org.openhab.binding.spotify/ @Hilbrand /bundles/org.openhab.binding.spotify/ @Hilbrand
/bundles/org.openhab.binding.squeezebox/ @digitaldan @mhilbush /bundles/org.openhab.binding.squeezebox/ @digitaldan @mhilbush
/bundles/org.openhab.binding.surepetcare/ @renescherer @HerzScheisse /bundles/org.openhab.binding.surepetcare/ @renescherer @HerzScheisse

View File

@ -1393,6 +1393,11 @@
<artifactId>org.openhab.binding.sonyprojector</artifactId> <artifactId>org.openhab.binding.sonyprojector</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.souliss</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.openhab.addons.bundles</groupId> <groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.binding.spotify</artifactId> <artifactId>org.openhab.binding.spotify</artifactId>

View File

@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@ -0,0 +1,321 @@
# Souliss Binding
[Souliss](http://www.souliss.net/) is a networking framework for Arduino and compatibles boards, and is designed to let you easily build a smart home that is distributed over multiple boards via Ethernet, WiFi, wireless point-to-point and RS485 bus.
Souliss is an open-source and community driven project, you can use the [wiki](https://github.com/souliss/souliss/wiki) and [Community](https://github.com/souliss/souliss/wiki/Community) to get help and share your results.
## Prerequisites
The binding requires a deployed network.
As a minimum, you need one Souliss node with Ethernet or WiFi access configured as a [Gateway](https://github.com/souliss/souliss/wiki/Gateway).
A Gateway is a special node that is able to communicate with the user interfaces.
The binding interacts as a user interface for Souliss.
A starting point is the [Souliss wiki](https://github.com/souliss/souliss/wiki).
The best is to start with a single node and connect with SoulissApp.
The code for networking activities of this binding is based on [SoulissApp](https://github.com/souliss/souliss/wiki/SoulissApp) code, so once connected with SoulissApp, you can move to openHAB directly.
You can use SoulissApp and the Souliss binding at the same time, and generally up to five (by default, but can be increased) user interfaces simultaneously.
### Sketches
The easiest way is start with a simple example to control an ON/OFF light (though a relay).
You can go to project [Souliss](https://github.com/souliss/souliss), see a lot of examples sketches: [Souliss examples](https://github.com/souliss/souliss/tree/friariello/examples)
## Discovery
First add a gateway (one only is permitted on LAN at this moment), then discovery can find other things (Souliss Typicals)
## Supported Things
In Souliss Framework a Typical is one of predefined logic dedicated to smart home devices like lights, heating or antitheft.
Typical can be one of T11, T12, T13, T14, etc...
They are defined [here](https://github.com/souliss/souliss/wiki/Typicals).
Typicals match directly with openHAB Thing type.
| Device type | Typical Code | Thing type |
|-----------------------------------------------------------|----------------|------------|
| ON/OFF Digital Output with Timer Option | T11 | t11 |
| ON/OFF Digital Output with AUTO mode | T12 | t12 |
| Digital Input Value | T13 | t13 |
| Pulse Digital Output | T14 | t14 |
| RGB LED Strip | T16 | t16 |
| ON/OFF Digital Output | T18 | t18 |
| Single Color LED Strip | T19 | t19 |
| Digital Input Pass Through | T1A | t1A |
| Motorized devices with limit switches | T21 | t21 |
| Motorized devices with limit switches and middle position | T22 | t22 |
| Temperature control | T31 | t31 |
| Anti-theft integration (Main) | T41 | t41 |
| Anti-theft integration (Peer) | T42 | t42 |
| Analog input, half-precision floating point | T51 | t51 |
| Temperature measure (-20, +50) °C | T52 | t52 |
| Humidity measure (0, 100) % | T53 | t53 |
| Light Sensor (0, 40) kLux | T54 | t54 |
| Voltage (0, 400) V | T55 | t55 |
| Current (0, 25) A | T56 | t56 |
| Power (0, 6500) W | T57 | t57 |
| Pressure measure (0, 1500) hPa | T58 | t58 |
| Analog Setpoint | T61 | t61 |
| Analog Setpoint-Temperature measure (-20, +50) °C | T62 | t62 |
| Analog Setpoint-Humidity measure (0, 100) % | T63 | t63 |
| Analog Setpoint-Light Sensor (0, 40) kLux | T64 | t64 |
| Analog Setpoint-Voltage (0, 400) V | T65 | t65 |
| Analog Setpoint-Current (0, 25) A | T66 | t66 |
| Analog Setpoint-Power (0, 6500) W | T67 | t67 |
| Analog Setpoint-Pressure measure (0, 1500) hPa | T68 | t68 |
| Broadcast messages | Action Message | topic |
### Channels
The following matrix lists the capabilities (channels) for each type:
| Thing type / Channel | Switch / onOff | Switch / sleep | DateTime / lastStatusStored | Number / healthy | Switch / autoMode | Contact / stateOnOff | Contact / stateOpenClose | Switch / pulse | Switch / whiteMode | Rollershutter / rollerBrightness | Dimmer / dimmerBrightness | Color / ledColor | Switch / one | Switch / two | Switch / three | Switch / four | Switch / five | Switch / six | Switch / seven | Switch / eight |
|----------------------|----------------|----------------|-----------------------------|------------------|-------------------|----------------------|--------------------------|----------------|--------------------|----------------------------------|---------------------------|------------------|--------------|--------------|----------------|---------------|---------------|--------------|----------------|----------------|
| t11 | x | x | x | x | | | | | | | | | | | | | | | | |
| t12 | x | | x | x | x | | | | | | | | | | | | | | | |
| t13 | | | x | x | | x | x | | | | | | | | | | | | | |
| t14 | | | x | x | | | | x | | | | | | | | | | | | |
| t16 | x | x | x | x | | | | | x | x | x | x | | | | | | | | |
| t18 | x | | x | x | | | | | | | | | | | | | | | | |
| t19 | x | x | x | x | | | | | | x | x | | | | | | | | | |
| t1A | | | x | x | | | | | | | | | x | x | x | x | x | x | x | x |
| Thing type / Channel | DateTime / lastStatusStored | Number / healthy | Rollershutter / rollerShutter | (see below) / rollerShutterState | (see down) / mode | (see down) / fan | Switch / status | Number / setPoint | Switch / setAsMeasured | Switch / measured | Switch / statusAlarm | Switch / onOffAlarm | Switch / rearmAlarm |
|----------------------|-----------------------------|------------------|-------------------------------|----------------------------------|-------------------|------------------|-----------------|-------------------|------------------------|-------------------|----------------------|---------------------|---------------------|
| t21 | x | x | | x | | | | | | | | | |
| t22 | x | x | x | x | | | | | | | | | |
| t31 | x | x | | | x | x | x | x | x | x | | | |
| t41 | x | x | | | | | | | | | x | x | x |
| t42 | x | x | | | | | | | | | x | | x |
rollershutterstate = opening, closing, limSwitchOpen , limSwitchClose, stateOpen, stateClose, noLimSwitch
mode = COOLING_MODE, HEATING_MODE, POWEREDOFF_MODE
fan = AUTO, HIGH, MEDIUM, LOW, FANOFF
| Thing type / Channel | DateTime / lastStatusStored | Number / healthy | Number / value |
|----------------------|-----------------------------|------------------|----------------|
| t51 | x | x | x |
| t52 | x | x | x |
| t53 | x | x | x |
| t54 | x | x | x |
| t55 | x | x | x |
| t56 | x | x | x |
| t57 | x | x | x |
| t58 | x | x | x |
| Thing type / Channel | DateTime / lastStatusStored | Number / healthy | Number / value |
|----------------------|-----------------------------|------------------|----------------|
| t61 | x | x | x |
| t62 | x | x | x |
| t63 | x | x | x |
| t64 | x | x | x |
| t65 | x | x | x |
| t66 | x | x | x |
| t67 | x | x | x |
| t68 | x | x | x |
| topic | x | | x |
### Parameters
| Thing type | Parameters Name and Default Value | Description |
|------------|-----------------------------------|-------------------------------------------------------------------------------------------------------|
| Gateway | gatewayLanAddress="" | Mandatory - lan address of Gateway |
| " | gatewayWanAddress="" | (advanced) When gateway is outside local network can insert domain/ip in this field |
| " | gatewayPortNumber=230 | (advanced) Gateway UDP Port |
| " | preferredLocalPortNumber=23000 | (advanced) Local UDP Port |
| " | pingInterval=30 | (advanced) Interval in seconds to check for device presence |
| " | subscriptionInterval=2 | (advanced) Interval in minutes to subscribe Souliss Gateway |
| " | healthyInterval=35 | (advanced) Interval in seconds to send nodes healthy |
| " | userIndex=70 | (advanced) Generally the default is good. It must be different from other ui (ex: SoulissApp) |
| " | nodeIndex=120 | (advanced) Generally the default value work good. It must is different from other ui (ex: SoulissApp) |
| Txx (all) | Node | Node of typical |
| Txx (all) | Slot | Slot of typical |
| T11 | sleep=5 | Set sleep timer in cycles |
| T11 | secureSend=true | Ensure command is correctly executed |
| T12 | | |
| T13 | | |
| T14 | | |
| T16 | sleep=5 | Set sleep timer in cycles |
| T19 | sleep=5 | Set sleep timer in cycles |
| T1A | | |
| T21 | | |
| T22 | | |
| T31 | | |
| T4x | | |
| T5x | | |
| T6x | | |
## Full Example
souliss.things:
```
Bridge souliss:gateway:105 "Souliss Gateway - 105" [gatewayLanAddress="192.168.1.105", gatewayPortNumber=230, preferredLocalPortNumber=0, pingInterval=30, subscriptionInterval=2, healthyInterval=38, userIndex=72, nodeIndex=38, timeoutToRequeue=5000, timeoutToRemovePacket=20000]
{
Thing t14 1-6 "Portoncino"@"Rientro" [node=1,slot=6] //thing UID is named as node-slot only as mnemonic convention, but you are free to assign other values
Thing t14 1-7 "Cancello"@"Rientro" [node=1,slot=7]
Thing t57 1-4 "Consumo"@"Soggiorno" [node=1,slot=4]
Thing t57 4-0 "Fotovoltaico"@"Soggiorno" [node=4,slot=0]
Thing t57 4-6 "Pannelli Gruppo 1"@"Soggiorno" [node=4,slot=6]
Thing t57 4-8 "Pannelli Gruppo 2"@"Soggiorno" [node=4,slot=8]
Thing t52 4-10 "Temp.Pannelli Gruppo 1"@"Soggiorno" [node=4,slot=10]
Thing t52 4-12 "Temp.Pannelli Gruppo 2"@"Soggiorno" [node=4,slot=12]
Thing t52 3-0 "Temperatura Boiler Solare Termico" [node=3,slot=0]
Thing t52 3-2 "Temperatura Termocamino" [node=3,slot=2]
Thing t11 3-4 "Acqua Termocamino" [node=3,slot=4]
Thing t11 3-6 "Auto: Boiler / Termocamino" [node=3,slot=6]
Thing t31 3-7 "Acqua Auto: Boiler / Termocamino" [node=3,slot=7]
Thing t31 6-0 "Termostato Soggiorno"@"Soggiorno" [node=6,slot=0]
Thing t53 6-7 "Umidità"@"Soggiorno" [node=6,slot=7]
Thing t19 6-9 "Termostato Soggiorno - Luminosità"@"Soggiorno" [node=6,slot=9]
Thing t11 5-0 "Tettoia"@"Giardino" [node=5,slot=0]
Thing t11 12-0 "Divano"@"Soggiorno" [node=12,slot=0,sleep=10, secureSend=false]
Thing t16 8-0 "LYT1" [node=8,slot=0]
Thing t11 10-0 "Albero di Natale" [node=10,slot=0]
Thing t11 11-0 "Birra"@"Soppalco" [node=11,slot=0]
Thing t52 11-1 "Birra - Temp 1"@"Soppalco" [node=11,slot=1]
Thing t52 11-3 "Birra - Temp 2"@"Soppalco" [node=11,slot=3]
}
```
You have to write your Gateway IP Number and leave all other to default values
default.items:
```
Group Home "Tonino" <house>
Group FamilyRoom "Soggiorno" <parents_2_4> (Home)
Group Divano "Divano" (Home)
Group Outside "Esterno" <garden> (Home)
Group TV "TV" <television> (Home)
Group Elettricita
Group Diagnostic
Group TermostatoSoggiorno
Switch tettoia "Tettoia" <light> (Outside) ["Lighting"] {autoupdate="false", channel="souliss:t11:105:5-0:onoff"}
String tettoia_aggiornamento "Agg [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (Outside, Diagnostic) {channel="souliss:t31:105:5-0:lastStatusStored"}
Switch portoncino "Portoncino" <light> (FamilyRoom) ["Lighting"] {autoupdate="false",channel="souliss:t14:105:1-6:pulse"}
Switch cancello "Cancello" <light> (FamilyRoom) ["Lighting"] {autoupdate="false",channel="souliss:t14:105:1-7:pulse"}
Number FamilyRoom_Temperature "Temperatura [%.1f °C]" <temperature> (FamilyRoom) {channel="souliss:t31:105:6-0:measured"}
Number FamilyRoom_Humidity "Umidità [%.1f %%]" <humidity> (FamilyRoom) {channel="souliss:t53:105:6-7:value"}
String AggiornamentoNodo6 "Agg [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (FamilyRoom, Diagnostic) {channel="souliss:t31:105:6-0:lastStatusStored"}
Number Consumo "Consumo [%.1f W]" <energy> (FamilyRoom, Elettricita) {channel="souliss:t57:105:1-4:value"}
Number Fotovoltaico "Fotovoltaico [%.1f W]" <energy> (FamilyRoom, Elettricita) {channel="souliss:t57:105:4-0:value"}
String AggiornamentoNodo1 "Agg.Consumi [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (FamilyRoom, Elettricita, Diagnostic) {channel="souliss:t57:105:1-4:lastStatusStored"}
String AggiornamentoNodo4 "Agg.Fotovoltaico [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (FamilyRoom, Elettricita, Diagnostic) {channel="souliss:t57:105:4-0:lastStatusStored"}
Switch divano "Divano" <light> (FamilyRoom, Divano ) ["Switchable"] {autoupdate="false", channel="souliss:t11:105:12-0:onOff"}
String divano_aggiornamento "Agg. [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (FamilyRoom, Divano, Diagnostic) {channel="souliss:t57:105:12-0:lastStatusStored"}
String divano_healthy "Salute" <keyring> (FamilyRoom, Divano, Diagnostic) {channel="souliss:t57:105:12-0:healthy"}
Number termostatosoggiorno_temperatura "Temperatura [%.1f °C]" <temperature> (TermostatoSoggiorno) {channel="souliss:t31:105:6-0:measured"}
Number termostatosoggiorno_umidita "Umidità [%.1f %%]" <temperature> (TermostatoSoggiorno) {channel="souliss:t53:105:6-7:value" }
Number termostatosoggiorno_umidita "Umidità" <humidity> (TermostatoSoggiorno) {channel="souliss:t53:105:6-7:value" }
Number termostatosoggiorno_temperatura "Temperatura" <temperature> (TermostatoSoggiorno) {channel="souliss:t31:105:6-0:measured"}
Number termostatosoggiorno_setpoint "Regola Set Point [%.1f °c]" <heating> (TermostatoSoggiorno) {autoupdate="false", channel="souliss:t31:105:6-0:sePpoint"}
Switch termostatosoggiorno_setasmeasured "Set temp. attuale" <heating> (TermostatoSoggiorno) {channel="souliss:t31:105:6-0:setAsMeasured"}
String termostatosoggiorno_modo "Modo" (TermostatoSoggiorno) {autoupdate="false", channel="souliss:t31:105:6-0:mode"}
Switch termostatosoggiorno_power "Termostato" <powerIcon> (TermostatoSoggiorno) {channel="souliss:t31:105:6-0:system"}
Switch termostatosoggiorno_fire "Fire" <fire> (TermostatoSoggiorno) {channel="souliss:t31:105:6-0:fire"}
Dimmer TermostatoSoggiorno_displayBright "Lumin.min. display" (TermostatoSoggiorno) {channel="souliss:t19:105:6-9" }
String TermostatoSoggiorno_aggiornamento "Agg.[%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" <keyring> (TermostatoSoggiorno, Diagnostic) {channel="souliss:t31:105:6-0:lastStatusStored"}
Number TermostatoSoggiorno_healthy "Salute" <keyring> (TermostatoSoggiorno, Diagnostic ) {channel="souliss:t31:105:6-0:healthy"}
```
default.sitemaps:
```
sitemap default label="Tonino" {
Frame {
Text label="Rientro casa" icon="light" {
Switch item=portoncino mappings=[ON="Apri"]
Switch item=cancello mappings=[ON="Apri"]
}
}
Frame {
Group item=Outside
}
Text item=Consumo label="Consumo [%.1f W]"
Text item=Fotovoltaico label="Fotovoltaico [%.1f W]"
Frame {
Group item=Elettricita label="Elettricità" icon="energy"
}
Frame {
Group item=Divano icon="light"
}
Frame label="Temperature"{
Text label="Temperatura e umidità" icon="temperature" {
Default item=FamilyRoom_Temperature label="Temperatura"
Default item=FamilyRoom_Humidity label="Umidità"
Default item=AggiornamentoNodo6 icon="icon16x16"
}
Text label="Termostato soggiorno" icon="temperature" {
Setpoint item=termostatosoggiorno_setpoint step=0.5 minValue=10 maxValue=30
Default item=termostatosoggiorno_temperatura
Default item=termostatosoggiorno_umidita
Switch item=termostatosoggiorno_setasmeasured mappings=[ON="Set"]
Switch item=termostatosoggiorno_modo label="Heating Mode" mappings=[HEATING_MODE="Set"]
Switch item=termostatosoggiorno_power label="Power On/Off"
Default item=termostatosoggiorno_fire label="Fire"
Text item=termostatoSoggiorno_aggiornamento label="Aggiornato: [%1$td.%1$tm.%1$tY %1$tk:%1$tM:%1$tS]" icon="icon16x16"
Default item=termostatoSoggiorno_healthy
Slider item=termostatoSoggiorno_displayBright
}
}
}
```
## Community
Souliss is a small community and doesn't have sufficient human resources to be more active on openHAB official community.
These are some very popular forum:
English Group, [here](https://groups.google.com/forum/#!forum/souliss)
Italian Group, [here](https://groups.google.com/forum/#!forum/souliss-it)
Spanish Group, [here] (https://groups.google.com/forum/#!forum/souliss-es)
## Contribution
Official repository for contributing to the Souliss project, GitHub page: [here](https://github.com/souliss)
## Known issues
Securesend is, at moment, enabled and tested only for t11...

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.souliss</artifactId>
<name>openHAB Add-ons :: Bundles :: Souliss Binding</name>
</project>

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>

View File

@ -317,6 +317,7 @@
<module>org.openhab.binding.sonos</module> <module>org.openhab.binding.sonos</module>
<module>org.openhab.binding.sonyaudio</module> <module>org.openhab.binding.sonyaudio</module>
<module>org.openhab.binding.sonyprojector</module> <module>org.openhab.binding.sonyprojector</module>
<module>org.openhab.binding.souliss</module>
<module>org.openhab.binding.spotify</module> <module>org.openhab.binding.spotify</module>
<module>org.openhab.binding.squeezebox</module> <module>org.openhab.binding.squeezebox</module>
<module>org.openhab.binding.surepetcare</module> <module>org.openhab.binding.surepetcare</module>