diff --git a/.gitignore b/.gitignore
index ebbad56526f89..22acbbd1f42db 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
.DS_Store
*.iml
npm-debug.log
+.build.log
.metadata/
bin/
@@ -16,3 +17,6 @@ xtend-gen/
bundles/**/src/main/history
features/**/src/main/history
features/**/src/main/feature
+
+.vscode
+.factorypath
diff --git a/.travis.yml b/.travis.yml
index b5f2860ca3816..1897e094dc88e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,42 +10,18 @@ jdk:
cache:
directories:
- $HOME/.m2
- - $HOME/.p2
+ - $HOME/.bnd/cache/
before_cache:
# remove resolver-status.properties, they change with each run and invalidate the cache
- find $HOME/.m2 -name resolver-status.properties -exec rm {} \;
-
-before_install:
- - echo "MAVEN_OPTS='-Xms1g -Xmx2g -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn'" > ~/.mavenrc
-install:
- - |
- function prevent_timeout() {
- local i=0
- while [ -e /proc/$1 ]; do
- # print zero width char every 3 minutes while building
- if [ "$i" -eq "180" ]; then printf %b '\u200b'; i=0; else i=$((i+1)); fi
- sleep 1
- done
- }
- function print_reactor_summary() {
- sed -ne '/\[INFO\] Reactor Summary:/,$ p' "$1" | sed 's/\[INFO\] //'
- }
- function mvnp() {
- set -o pipefail # exit build with error when pipes fail
- local command=(mvn $@)
- exec "${command[@]}" 2>&1 | # execute, redirect stderr to stdout
- tee .build.log | # write output to log
- stdbuf -oL grep -E '^\[INFO\] Building .+ \[.+\]$' | # filter progress
- sed -uE 's/^\[INFO\] Building (.*[^ ])[ ]+\[([0-9]+\/[0-9]+)\]$/\2| \1/' | # prefix project name with progress
- sed -e :a -e 's/^.\{1,6\}|/ &/;ta' & # right align progress with padding
- local pid=$!
- prevent_timeout $pid &
- wait $pid
- }
-after_success:
- - print_reactor_summary .build.log
-after_failure:
- - tail -n 2000 .build.log
-script:
- - mvnp clean install -B -DskipChecks=true -DskipTests=true
+
+notifications:
+ webhooks: https://www.travisbuddy.com/
+
+travisBuddy:
+ insertMode: update
+ successBuildLog: true
+
+install: true
+script: ./buildci.sh "$TRAVIS_COMMIT_RANGE"
diff --git a/CODEOWNERS b/CODEOWNERS
index 2ca976d6f5e9f..63afc660f4523 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -122,6 +122,7 @@
/bundles/org.openhab.binding.plugwise/ @wborn
/bundles/org.openhab.binding.powermax/ @lolodomo
/bundles/org.openhab.binding.pulseaudio/ @peuter
+/bundles/org.openhab.binding.pushbullet/ @hakan42
/bundles/org.openhab.binding.regoheatpump/ @crnjan
/bundles/org.openhab.binding.rfxcom/ @martinvw @paulianttila
/bundles/org.openhab.binding.rme/ @kgoderis
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index bf733d6844d3b..6f00784adc50a 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -600,6 +600,11 @@
org.openhab.binding.pulseaudio${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.binding.pushbullet
+ ${project.version}
+ org.openhab.addons.bundlesorg.openhab.binding.regoheatpump
diff --git a/buildci.sh b/buildci.sh
new file mode 100755
index 0000000000000..f2b5072b08fbd
--- /dev/null
+++ b/buildci.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+function prevent_timeout() {
+ local i=0
+ while [ -e /proc/$1 ]; do
+ # print zero width char every 3 minutes while building
+ if [ "$i" -eq "180" ]; then printf %b '\u200b'; i=0; else i=$((i+1)); fi
+ sleep 1
+ done
+}
+
+function print_reactor_summary() {
+ sed -ne '/\[INFO\] Reactor Summary:/,$ p' "$1" | sed 's/\[INFO\] //'
+}
+
+function mvnp() {
+ set -o pipefail # exit build with error when pipes fail
+ local command=(mvn $@)
+ exec "${command[@]}" 2>&1 | # execute, redirect stderr to stdout
+ stdbuf -o0 grep -vE "Download(ed|ing) from [a-z.]+: https:" | # filter out downloads
+ tee .build.log | # write output to log
+ stdbuf -oL grep -E '^\[INFO\] Building .+ \[.+\]$' | # filter progress
+ stdbuf -o0 sed -uE 's/^\[INFO\] Building (.*[^ ])[ ]+\[([0-9]+\/[0-9]+)\]$/\2| \1/' | # prefix project name with progress
+ stdbuf -o0 sed -e :a -e 's/^.\{1,6\}|/ &/;ta' & # right align progress with padding
+ local pid=$!
+ prevent_timeout $pid &
+ wait $pid
+}
+
+COMMITS=${1:-"master...HEAD"}
+
+# Determine if this is a new addon -> Perform tests + integration tests and all SAT checks with increased warning level
+CHANGED_DIR=`git diff --dirstat=files,0 $COMMITS bundles/ | sed 's/^[ 0-9.]\+% bundles\///g' | grep -o -P "^([^/]*)" | uniq`
+CDIR=`pwd`
+
+if [ ! -z "$CHANGED_DIR" ] && [ -e "bundles/$CHANGED_DIR" ]; then
+ echo "Single addon pull request: Building $CHANGED_DIR"
+ echo "MAVEN_OPTS='-Xms1g -Xmx2g -Dorg.slf4j.simpleLogger.log.org.openhab.tools.analysis.report.ReportUtility=DEBUG -Dorg.slf4j.simpleLogger.defaultLogLevel=WARN'" > ~/.mavenrc
+ cd "bundles/$CHANGED_DIR"
+ mvn clean install -B 2>&1 |
+ stdbuf -o0 grep -vE "Download(ed|ing) from [a-z.]+: https:" | # Filter out Download(s)
+ stdbuf -o0 grep -v "target/code-analysis" | # filter out some debug code from reporting utility
+ tee $CDIR/.build.log
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+
+ if [ -e "../itests/$CHANGED_DIR" ]; then
+ echo "Single addon pull request: Building itest $CHANGED_DIR"
+ cd "../itests/$CHANGED_DIR"
+ mvn clean install -B 2>&1 |
+ stdbuf -o0 grep -vE "Download(ed|ing) from [a-z.]+: https:" | # Filter out Download(s)
+ stdbuf -o0 grep -v "target/code-analysis" | # filter out some debug code from reporting utility
+ tee -a $CDIR/.build.log
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ fi
+else
+ echo "Build all"
+ echo "MAVEN_OPTS='-Xms1g -Xmx2g -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn'" > ~/.mavenrc
+ mvnp clean install -B -DskipChecks=true -DskipTests=true
+ if [ $? -eq 0 ]; then
+ print_reactor_summary .build.log
+ else
+ tail -n 1000 .build.log
+ exit 1
+ fi
+fi
diff --git a/bundles/org.openhab.binding.allplay/lib/tchaikovsky-sources.jar b/bundles/org.openhab.binding.allplay/lib/tchaikovsky-sources.jar
deleted file mode 100644
index c3c04bb5785ab..0000000000000
Binary files a/bundles/org.openhab.binding.allplay/lib/tchaikovsky-sources.jar and /dev/null differ
diff --git a/bundles/org.openhab.binding.allplay/lib/tchaikovsky.jar b/bundles/org.openhab.binding.allplay/lib/tchaikovsky.jar
deleted file mode 100644
index c5eb425105870..0000000000000
Binary files a/bundles/org.openhab.binding.allplay/lib/tchaikovsky.jar and /dev/null differ
diff --git a/bundles/org.openhab.binding.allplay/pom.xml b/bundles/org.openhab.binding.allplay/pom.xml
index b7a991931811c..e792ca0297934 100644
--- a/bundles/org.openhab.binding.allplay/pom.xml
+++ b/bundles/org.openhab.binding.allplay/pom.xml
@@ -13,8 +13,13 @@
openHAB Add-ons :: Bundles :: AllPlay Binding
-
- org.slf4j.impl.*;resolution:=optional,de.kaizencode.tchaikovsky.*
-
+
+
+ org.openhab.osgiify
+ de.kaizencode.tchaikovsky
+ 0.0.1
+ provided
+
+
diff --git a/bundles/org.openhab.binding.allplay/src/main/feature/feature.xml b/bundles/org.openhab.binding.allplay/src/main/feature/feature.xml
index 386e237564666..0beed0ef008a1 100644
--- a/bundles/org.openhab.binding.allplay/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.allplay/src/main/feature/feature.xml
@@ -4,6 +4,7 @@
openhab-runtime-base
+ mvn:org.openhab.osgiify/de.kaizencode.tchaikovsky/0.0.1mvn:org.openhab.addons.bundles/org.openhab.binding.allplay/${project.version}
diff --git a/bundles/org.openhab.binding.amazondashbutton/pom.xml b/bundles/org.openhab.binding.amazondashbutton/pom.xml
index c68f3dda9127c..ffa046ecdae10 100644
--- a/bundles/org.openhab.binding.amazondashbutton/pom.xml
+++ b/bundles/org.openhab.binding.amazondashbutton/pom.xml
@@ -21,14 +21,14 @@
provided
- org.pcap4j
- pcap4j-core
+ org.openhab.osgiify
+ org.pcap4j.pcap4j-core1.6.6provided
- org.pcap4j
- pcap4j-packetfactory-static
+ org.openhab.osgiify
+ org.pcap4j.pcap4j-packetfactory-static1.6.6provided
diff --git a/bundles/org.openhab.binding.amazondashbutton/src/main/feature/feature.xml b/bundles/org.openhab.binding.amazondashbutton/src/main/feature/feature.xml
index bf017f318d3e9..eb9e5f48a4c1a 100644
--- a/bundles/org.openhab.binding.amazondashbutton/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.amazondashbutton/src/main/feature/feature.xml
@@ -4,10 +4,9 @@
openhab-runtime-base
- wrapmvn:net.java.dev.jna/jna/4.2.1
- wrap:mvn:org.pcap4j/pcap4j-core/1.6.6$Bundle-Name=Pcap4J%20Core&Bundle-SymbolicName=org.pcap4j.pcap4j-core&Bundle-Version=1.6.6
- wrap:mvn:org.pcap4j/pcap4j-packetfactory-static/1.6.6$Bundle-Name=Pcap4J%20Static%20Packet%20Factory&Bundle-SymbolicName=org.pcap4j.pcap4j-packetfactory-static&Bundle-Version=1.6.6
+ mvn:org.openhab.osgiify/org.pcap4j.pcap4j-core/1.6.6
+ mvn:org.openhab.osgiify/org.pcap4j.pcap4j-packetfactory-static/1.6.6mvn:org.openhab.addons.bundles/org.openhab.binding.amazondashbutton/${project.version}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/.classpath b/bundles/org.openhab.binding.amazonechocontrol/.classpath
index 084e4c97f76f2..a5d95095ccaaf 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/.classpath
+++ b/bundles/org.openhab.binding.amazonechocontrol/.classpath
@@ -1,14 +1,13 @@
-
+
+
-
-
+
-
@@ -19,6 +18,11 @@
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.amazonechocontrol/.project b/bundles/org.openhab.binding.amazonechocontrol/.project
index 29779e20d1765..875f2ada3f4f4 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/.project
+++ b/bundles/org.openhab.binding.amazonechocontrol/.project
@@ -10,21 +10,6 @@
-
- org.eclipse.pde.ManifestBuilder
-
-
-
-
- org.eclipse.pde.SchemaBuilder
-
-
-
-
- org.eclipse.pde.ds.core.builder
-
-
- org.eclipse.m2e.core.maven2Builder
@@ -32,8 +17,7 @@
- org.eclipse.m2e.core.maven2Nature
- org.eclipse.pde.PluginNatureorg.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
diff --git a/bundles/org.openhab.binding.amazonechocontrol/README.md b/bundles/org.openhab.binding.amazonechocontrol/README.md
index f4a85122bdda7..6c788b07af8f0 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/README.md
+++ b/bundles/org.openhab.binding.amazonechocontrol/README.md
@@ -1,6 +1,6 @@
# Amazon Echo Control Binding
-This binding can control Amazon Echo devices (Alexa) and their smart bulbs.
+This binding can control Amazon Echo devices (Alexa).
It provides features to control and view the current state of echo devices:
@@ -23,6 +23,8 @@ It provides features to control and view the current state of echo devices:
- start playing music by providing the voice command as text (Works with all music providers)
- get last spoken voice command
- change the volume of the alarm
+- change the equalizer settings
+- get information about the next alarm, reminder and timer
Also this binding includes the features to control your lights connected to your Echo devices:
@@ -50,6 +52,8 @@ Some ideas what you can do in your home by using rules and other openHAB control
- Have different flash briefing in the morning and evening
- Let alexa say 'welcome' to you if you open the door
- Implement own handling for voice commands in a rule
+- Change the equalizer settings depending on the bluetooth connection
+- Turn on a light on your alexa alarm time
With the possibility to control your lights you could do:
@@ -93,9 +97,6 @@ If the device type is not known by the binding, the device will not be discovere
But you can define any device listed in your alexa app with the best matching existing device (e.g. echo).
You will find the required serial number in settings of the device in the alexa app.
-Also you will see your lights in the inbox of openhab. They will automatically be discoverd by openhab based on your amazon login.
-If you configured any groups of lights in your amazon alexa app they will be discovered by openhab too.
-
## Binding Configuration
The binding does not have any configuration.
@@ -122,40 +123,48 @@ It will be configured at runtime by using the save channel to store the current
## Channels
-| Channel Type ID | Item Type | Access Mode | Thing Type | Description
-|-----------------------|-------------|-----------|-------------------------------|-----------------------------------------------------------------------
-| player | Player | R/W | echo, echoshow, echospot, wha | Control the music player e.g. pause/continue/next track/previous track
-| volume | Dimmer | R/W | echo, echoshow, echospot | Control the volume
-| shuffle | Switch | R/W | echo, echoshow, echospot, wha | Shuffle play if applicable, e.g. playing a playlist
-| imageUrl | String | R | echo, echoshow, echospot, wha | Url of the album image or radio station logo
-| title | String | R | echo, echoshow, echospot, wha | Title of the current media
-| subtitle1 | String | R | echo, echoshow, echospot, wha | Subtitle of the current media
-| subtitle2 | String | R | echo, echoshow, echospot, wha | Additional subtitle of the current media
-| providerDisplayName | String | R | echo, echoshow, echospot, wha | Name of the music provider
-| bluetoothMAC | String | R/W | echo, echoshow, echospot | Bluetooth device MAC. Used to connect to a specific device or disconnect if a empty string was provided
-| bluetooth | Switch | R/W | echo, echoshow, echospot | Connect/Disconnect to the last used bluetooth device (works after a bluetooth connection was established after the openHAB start)
-| bluetoothDeviceName | String | R | echo, echoshow, echospot | User friendly name of the connected bluetooth device
-| radioStationId | String | R/W | echo, echoshow, echospot, wha | Start playing of a TuneIn radio station by specifying it's id or stops playing if a empty string was provided
-| radio | Switch | R/W | echo, echoshow, echospot, wha | Start playing of the last used TuneIn radio station (works after the radio station started after the openhab start)
-| amazonMusicTrackId | String | R/W | echo, echoshow, echospot, wha | Start playing of a Amazon Music track by it's id od stops playing if a empty string was provided
+| Channel Type ID | Item Type | Access Mode | Thing Type | Description
+|-----------------------|-------------|-------------|------------|------------------------------------------------------------------------------------------
+| player | Player | R/W | echo, echoshow, echospot, wha | Control the music player (Supported commands: PLAY or ON, PAUSE or OFF, NEXT, PREVIOUS, REWIND, FASTFORWARD)
+| volume | Dimmer | R/W | echo, echoshow, echospot | Control the volume
+| equalizerTreble | Number | R/W | echo, echoshow, echospot | Control the treble (value from -6 to 6)
+| equalizerMidrange | Number | R/W | echo, echoshow, echospot | Control the midrange (value from -6 to 6)
+| equalizerBass | Number | R/W | echo, echoshow, echospot | Control the bass (value from -6 to 6)
+| shuffle | Switch | R/W | echo, echoshow, echospot, wha | Shuffle play if applicable, e.g. playing a playlist
+| imageUrl | String | R | echo, echoshow, echospot, wha | Url of the album image or radio station logo
+| title | String | R | echo, echoshow, echospot, wha | Title of the current media
+| subtitle1 | String | R | echo, echoshow, echospot, wha | Subtitle of the current media
+| subtitle2 | String | R | echo, echoshow, echospot, wha | Additional subtitle of the current media
+| providerDisplayName | String | R | echo, echoshow, echospot, wha | Name of the music provider
+| bluetoothMAC | String | R/W | echo, echoshow, echospot | Bluetooth device MAC. Used to connect to a specific device or disconnect if a empty string was provided
+| bluetooth | Switch | R/W | echo, echoshow, echospot | Connect/Disconnect to the last used bluetooth device (works after a bluetooth connection was established after the openHAB start)
+| bluetoothDeviceName | String | R | echo, echoshow, echospot | User friendly name of the connected bluetooth device
+| radioStationId | String | R/W | echo, echoshow, echospot, wha | Start playing of a TuneIn radio station by specifying it's id or stops playing if a empty string was provided
+| radio | Switch | R/W | echo, echoshow, echospot, wha | Start playing of the last used TuneIn radio station (works after the radio station started after the openhab start)
+| amazonMusicTrackId | String | R/W | echo, echoshow, echospot, wha | Start playing of a Amazon Music track by it's id od stops playing if a empty string was provided
| amazonMusicPlayListId | String | W | echo, echoshow, echospot, wha | Write Only! Start playing of a Amazon Music playlist by specifying it's id od stops playing if a empty string was provided. Selection will only work in PaperUI
-| amazonMusic | Switch | R/W | echo, echoshow, echospot, wha | Start playing of the last used Amazon Music song (works after at least one song was started after the openhab start)
-| remind | String | R/W | echo, echoshow, echospot | Write Only! Speak the reminder and sends a notification to the Alexa app (Currently the reminder is played and notified two times, this seems to be a bug in the amazon software)
-| startRoutine | String | W | echo, echoshow, echospot | Write Only! Type in what you normally say to Alexa without the preceding "Alexa,"
-| musicProviderId | String | R/W | echo, echoshow, echospot | Current Music provider
+| amazonMusic | Switch | R/W | echo, echoshow, echospot, wha | Start playing of the last used Amazon Music song (works after at least one song was started after the openhab start)
+| remind | String | R/W | echo, echoshow, echospot | Write Only! Speak the reminder and sends a notification to the Alexa app (Currently the reminder is played and notified two times, this seems to be a bug in the amazon software)
+| nextReminder | DateTime | R | echo, echoshow, echospot | Next reminder on the device
+| playAlarmSound | String | W | echo, echoshow, echospot | Write Only! Plays ans Alarm sound
+| nextAlarm | DateTime | R | echo, echoshow, echospot | Next alarm on the device
+| nextMusicAlarm | DateTime | R | echo, echoshow, echospot | Next music alarm on the device
+| nextTimer | DateTime | R | echo, echoshow, echospot | Next timer on the device
+| startRoutine | String | W | echo, echoshow, echospot | Write Only! Type in what you normally say to Alexa without the preceding "Alexa,"
+| musicProviderId | String | R/W | echo, echoshow, echospot | Current Music provider
| playMusicVoiceCommand | String | W | echo, echoshow, echospot | Write Only! Voice command as text. E.g. 'Yesterday from the Beatles'
| startCommand | String | W | echo, echoshow, echospot | Write Only! Used to start anything. Available options: Weather, Traffic, GoodMorning, SingASong, TellStory, FlashBriefing and FlashBriefing. (Note: The options are case sensitive)
-| textToSpeech | String | W | echo, echoshow, echospot | Write Only! Write some text to this channel and alexa will speak it
+| textToSpeech | String | W | echo, echoshow, echospot | Write Only! Write some text to this channel and alexa will speak it. It is possible to use plain text or SSML: e.g. `I want to tell you a secret.I am not a real human.`
| textToSpeechVolume | Dimmer | R/W | echo, echoshow, echospot | Volume of the textToSpeech channel, if 0 the current volume will be used
-| lastVoiceCommand | String | R/W | echo, echoshow, echospot | Last voice command spoken to the device. Writing to the channel starts voice output.
-| mediaProgress | Dimmer | R/W | echo, echoshow, echospot | Media progress in percent
-| mediaProgressTime | Number:Time | R/W | echo, echoshow, echospot | Media play time
-| mediaLength | Number:Time | R | echo, echoshow, echospot | Media length
-| notificationVolume | Dimmer | R | echo, echoshow, echospot | Notification volume
-| ascendingAlarm | Switch | R/W | echo, echoshow, echospot | Ascending alarm up to the configured volume
-| save | Switch | W | flashbriefingprofile | Write Only! Stores the current configuration of flash briefings within the thing
-| active | Switch | R/W | flashbriefingprofile | Active the profile
-| playOnDevice | String | W | flashbriefingprofile | Specify the echo serial number or name to start the flash briefing.
+| lastVoiceCommand | String | R/W | echo, echoshow, echospot | Last voice command spoken to the device. Writing to the channel starts voice output.
+| mediaProgress | Dimmer | R/W | echo, echoshow, echospot | Media progress in percent
+| mediaProgressTime | Number:Time | R/W | echo, echoshow, echospot | Media play time
+| mediaLength | Number:Time | R | echo, echoshow, echospot | Media length
+| notificationVolume | Dimmer | R | echo, echoshow, echospot | Notification volume
+| ascendingAlarm | Switch | R/W | echo, echoshow, echospot | Ascending alarm up to the configured volume
+| save | Switch | W | flashbriefingprofile | Write Only! Stores the current configuration of flash briefings within the thing
+| active | Switch | R/W | flashbriefingprofile | Active the profile
+| playOnDevice | String | W | flashbriefingprofile | Specify the echo serial number or name to start the flash briefing.
| lightState | Switch | R/W | light, lightGroup | Shows and changes the state (ON/OFF) of your light or lightgroup
| lightBrightness | Dimmer | R/W | light, lightGroup | Shows and changes the brightness of your light or lightgroup
| lightColor | String | R/W | light, lightGroup | Shows and changes the color of your light (groups are not able to show their color!)
@@ -199,6 +208,9 @@ Group Alexa_Living_Room
// Player control
Player Echo_Living_Room_Player "Player" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:player"}
Dimmer Echo_Living_Room_Volume "Volume [%.0f %%]" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:volume"}
+Number Echo_Living_Room_Treble "Treble" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:equalizerTreble"}
+Number Echo_Living_Room_Midrange "Midrange" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:equalizerMidrange"}
+Number Echo_Living_Room_Bass "Bass" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:equalizerBass"}
Switch Echo_Living_Room_Shuffle "Shuffle" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:shuffle"}
// Media channels
@@ -243,6 +255,11 @@ Switch Echo_Living_Room_AscendingAlarm "Ascending alarm"
// Feedbacks
String Echo_Living_Room_LastVoiceCommand "Last voice command" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:lastVoiceCommand"}
+DateTime Echo_Living_Room_NextReminder "Next reminder" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:nextReminder"}
+DateTime Echo_Living_Room_NextAlarm "Next alarm" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:nextAlarm"}
+DateTime Echo_Living_Room_NextMusicAlarm "Next music alarm" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:nextMusicAlarm"}
+DateTime Echo_Living_Room_NextTimer "Next timer" (Alexa_Living_Room) {channel="amazonechocontrol:echo:account1:echo1:nextTimer"}
+
// Flashbriefings
Switch FlashBriefing_Technical_Save "Save (Write only)" { channel="amazonechocontrol:flashbriefingprofile:account1:flashbriefing1:save"}
@@ -253,6 +270,7 @@ Switch FlashBriefing_LifeStyle_Save "Save (Write only)" { channel="amazonechoc
Switch FlashBriefing_LifeStyle_Active "Active" { channel="amazonechocontrol:flashbriefingprofile:account1:flashbriefing2:active"}
String FlashBriefing_LifeStyle_Play "Play (Write only)" { channel="amazonechocontrol:flashbriefingprofile:account1:flashbriefing2:playOnDevice"}
+
// Lights and lightgroups - you will find the applianceId in the properties of your light or lightgroup!
Switch Light_State "On/Off" { channel="amazonechocontrol:lightGroup:account1:applianceId:lightState" }
Dimmer Light_Brightness "Brightness" { channel="amazonechocontrol:lightGroup:account1:applianceId:lightBrightness" }
@@ -268,6 +286,10 @@ sitemap amazonechocontrol label="Echo Devices"
Frame label="Alexa" {
Default item=Echo_Living_Room_Player
Slider item=Echo_Living_Room_Volume
+ Setpoint item=Echo_Living_Room_Volume minValue=0 maxValue=100 step=5
+ Setpoint item=Echo_Living_Room_Treble minValue=-6 maxValue=6 step=1
+ Setpoint item=Echo_Living_Room_Midrange minValue=-6 maxValue=6 step=1
+ Setpoint item=Echo_Living_Room_Bass minValue=-6 maxValue=6 step=1
Slider item=Echo_Living_Room_MediaProgress
Text item=Echo_Living_Room_MediaProgressTime
Text item=Echo_Living_Room_MediaLength
@@ -318,13 +340,12 @@ sitemap amazonechocontrol label="Echo Devices"
Switch item=FlashBriefing_LifeStyle_Active
Text item=FlashBriefing_LifeStyle_Play
}
-
- Frame label="Lights and light groups" {
- Switch item=Light_State
- Slider item=Light_Brightness
- Selection item=Light_Color mappings=[ ''='', 'red'='Red', 'crimson'='Crimson', 'salmon'='Salmon', 'orange'='Orange', 'gold'='Gold', 'yellow'='Yellow', 'green'='Green', 'turquoise'='Turquoise', 'cyan'='Cyan', 'sky_blue'='Sky Blue', 'blue'='Blue', 'purple'='Purple', 'magenta'='Magenta', 'pink'='Pink', 'lavender'='Lavender' ]
- Selection item=Light_White mappings=[ ''='', 'warm_white'='Warm white', 'soft_white'='Soft white', 'white'='White', 'daylight_white'='Daylight white', 'cool_white'='Cool white' ]
- }
+ Frame label="Lights and light groups" {
+ Switch item=Light_State
+ Slider item=Light_Brightness
+ Selection item=Light_Color mappings=[ ''='', 'red'='Red', 'crimson'='Crimson', 'salmon'='Salmon', 'orange'='Orange', 'gold'='Gold', 'yellow'='Yellow', 'green'='Green', 'turquoise'='Turquoise', 'cyan'='Cyan', 'sky_blue'='Sky Blue', 'blue'='Blue', 'purple'='Purple', 'magenta'='Magenta', 'pink'='Pink', 'lavender'='Lavender' ]
+ Selection item=Light_White mappings=[ ''='', 'warm_white'='Warm white', 'soft_white'='Soft white', 'white'='White', 'daylight_white'='Daylight white', 'cool_white'='Cool white' ]
+ }
}
```
@@ -350,6 +371,17 @@ then
end
```
+You can also use [SSML](https://docs.aws.amazon.com/polly/latest/dg/supported-ssml.html) to provide a better voice experience
+
+```php
+rule "Say welcome if the door opens"
+when
+ Item Door_Contact changed to OPEN
+then
+ Echo_Living_Room_TTS.sendCommand('I want to tell you a secret.I am not a real human..Can you believe it?')
+end
+```
+
## Playing an alarm sound for 15 seconds with an openHAB rule if an door contact was opened:
1) Do get the ID of your sound, follow the steps in "How To Get IDs"
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AccountServlet.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AccountServlet.java
index e977ef38aa323..a4c32e59db2ab 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AccountServlet.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AccountServlet.java
@@ -76,19 +76,20 @@ public class AccountServlet extends HttpServlet {
private final Logger logger = LoggerFactory.getLogger(AccountServlet.class);
- HttpService httpService;
+ final HttpService httpService;
String servletUrlWithoutRoot;
- String servletUrl;
+ final String servletUrl;
AccountHandler account;
String id;
@Nullable
Connection connectionToInitialize;
- Gson gson = new Gson();
+ final Gson gson;
- public AccountServlet(HttpService httpService, String id, AccountHandler account) {
+ public AccountServlet(HttpService httpService, String id, AccountHandler account, Gson gson) {
this.httpService = httpService;
this.account = account;
this.id = id;
+ this.gson = gson;
try {
servletUrlWithoutRoot = "amazonechocontrol/" + URLEncoder.encode(id, "UTF8");
} catch (UnsupportedEncodingException e) {
@@ -112,7 +113,7 @@ private Connection reCreateConnection() {
if (oldConnection == null) {
oldConnection = account.findConnection();
}
- return new Connection(oldConnection);
+ return new Connection(oldConnection, this.gson);
}
public void dispose() {
@@ -157,7 +158,7 @@ void doVerb(String verb, @Nullable HttpServletRequest req, @Nullable HttpServlet
Map map = req.getParameterMap();
String domain = map.get("domain")[0];
String loginData = connection.serializeLoginData();
- Connection newConnection = new Connection(null);
+ Connection newConnection = new Connection(null, this.gson);
if (newConnection.tryRestoreLogin(loginData, domain)) {
account.setConnection(newConnection);
}
@@ -282,7 +283,7 @@ protected void doGet(@Nullable HttpServletRequest req, @Nullable HttpServletResp
}
// handle commands
if (baseUrl.equals("/newdevice") || baseUrl.equals("/newdevice/")) {
- this.connectionToInitialize = new Connection(null);
+ this.connectionToInitialize = new Connection(null, this.gson);
this.account.setConnection(null);
resp.sendRedirect(this.servletUrl);
return;
@@ -301,9 +302,7 @@ protected void doGet(@Nullable HttpServletRequest req, @Nullable HttpServletResp
Device device = account.findDeviceJson(serialNumber);
if (device != null) {
Thing thing = account.findThingBySerialNumber(device.serialNumber);
- if (thing != null) {
- handleIds(resp, connection, device, thing);
- }
+ handleIds(resp, connection, device, thing);
return;
}
}
@@ -331,7 +330,7 @@ protected void doGet(@Nullable HttpServletRequest req, @Nullable HttpServletResp
}
public Map getQueryMap(@Nullable String query) {
- Map map = new HashMap();
+ Map map = new HashMap<>();
if (query != null) {
String[] params = query.split("&");
for (String param : params) {
@@ -374,6 +373,12 @@ private void handleDefaultPageResult(HttpServletResponse resp, String message, C
html.append(" | ");
html.append(StringEscapeUtils.escapeHtml("Logout and create new device id"));
html.append("");
+ // customer id
+ html.append(" Customer Id: ");
+ html.append(StringEscapeUtils.escapeHtml(connection.getCustomerId()));
+ // customer name
+ html.append(" Customer Name: ");
+ html.append(StringEscapeUtils.escapeHtml(connection.getCustomerName()));
// device name
html.append(" App name: ");
html.append(StringEscapeUtils.escapeHtml(connection.getDeviceName()));
@@ -393,7 +398,7 @@ private void handleDefaultPageResult(HttpServletResponse resp, String message, C
// device list
html.append(
- "
Device
Serial Number
State
Thing
Type
Family
");
+ "
Device
Serial Number
State
Thing
Family
Type
Customer Id
");
for (Device device : this.account.getLastKnownDevices()) {
html.append("
");
@@ -599,11 +626,11 @@ void handleProxyRequest(Connection connection, HttpServletResponse resp, String
try {
Map headers = null;
if (referer != null) {
- headers = new HashMap();
+ headers = new HashMap<>();
headers.put("Referer", referer);
}
- urlConnection = connection.makeRequest(verb, url, postData, json, false, headers);
+ urlConnection = connection.makeRequest(verb, url, postData, json, false, headers, 0);
if (urlConnection.getResponseCode() == 302) {
{
String location = urlConnection.getHeaderField("location");
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlBindingConstants.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlBindingConstants.java
index 3aca19e0b336d..6b4ca63780e0e 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlBindingConstants.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlBindingConstants.java
@@ -45,13 +45,16 @@ public class AmazonEchoControlBindingConstants {
public static final ThingTypeUID THING_TYPE_LIGHT = new ThingTypeUID(BINDING_ID, "light");
public static final ThingTypeUID THING_TYPE_LIGHT_GROUP = new ThingTypeUID(BINDING_ID, "lightGroup");
- public static final Set SUPPORTED_THING_TYPES_UIDS = new HashSet(
+ public static final Set SUPPORTED_THING_TYPES_UIDS = new HashSet<>(
Arrays.asList(THING_TYPE_ACCOUNT, THING_TYPE_ECHO, THING_TYPE_ECHO_SPOT, THING_TYPE_ECHO_SHOW,
THING_TYPE_ECHO_WHA, THING_TYPE_FLASH_BRIEFING_PROFILE, THING_TYPE_LIGHT, THING_TYPE_LIGHT_GROUP));
// List of all Channel ids
public static final String CHANNEL_PLAYER = "player";
public static final String CHANNEL_VOLUME = "volume";
+ public static final String CHANNEL_EQUALIZER_TREBLE = "equalizerTreble";
+ public static final String CHANNEL_EQUALIZER_MIDRANGE = "equalizerMidrange";
+ public static final String CHANNEL_EQUALIZER_BASS = "equalizerBass";
public static final String CHANNEL_ERROR = "error";
public static final String CHANNEL_SHUFFLE = "shuffle";
public static final String CHANNEL_LOOP = "loop";
@@ -86,6 +89,10 @@ public class AmazonEchoControlBindingConstants {
public static final String CHANNEL_LIGHT_COLOR = "lightColor";
public static final String CHANNEL_LIGHT_WHITE_TEMPERATURE = "whiteTemperature";
public static final String CHANNEL_LIGHT_BRIGHTNESS = "lightBrightness";
+ public static final String CHANNEL_NEXT_REMINDER = "nextReminder";
+ public static final String CHANNEL_NEXT_ALARM = "nextAlarm";
+ public static final String CHANNEL_NEXT_MUSIC_ALARM = "nextMusicAlarm";
+ public static final String CHANNEL_NEXT_TIMER = "nextTimer";
public static final String CHANNEL_SAVE = "save";
public static final String CHANNEL_ACTIVE = "active";
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlHandlerFactory.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlHandlerFactory.java
index b454dfaafdfdb..cbb670561e08c 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlHandlerFactory.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/AmazonEchoControlHandlerFactory.java
@@ -44,6 +44,8 @@
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.http.HttpService;
+import com.google.gson.Gson;
+
/**
* The {@link AmazonEchoControlHandlerFactory} is responsible for creating things and thing
* handlers.
@@ -62,7 +64,9 @@ public class AmazonEchoControlHandlerFactory extends BaseThingHandlerFactory {
StorageService storageService;
@Nullable
BindingServlet bindingServlet;
-
+ @Nullable
+ Gson gson;
+
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
@@ -99,11 +103,17 @@ protected void deactivate(ComponentContext componentContext) {
if (storageService == null) {
return null;
}
+ Gson gson = this.gson;
+ if (gson == null)
+ {
+ gson = new Gson();
+ this.gson = gson;
+ }
if (thingTypeUID.equals(THING_TYPE_ACCOUNT)) {
Storage storage = storageService.getStorage(thing.getUID().toString(),
String.class.getClassLoader());
- AccountHandler bridgeHandler = new AccountHandler((Bridge) thing, httpService, storage);
+ AccountHandler bridgeHandler = new AccountHandler((Bridge) thing, httpService, storage, gson);
registerDiscoveryService(bridgeHandler);
BindingServlet bindingServlet = this.bindingServlet;
if (bindingServlet != null) {
@@ -122,7 +132,7 @@ protected void deactivate(ComponentContext componentContext) {
return new SmartHomeDeviceHandler(thing, storage);
}
if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
- return new EchoHandler(thing);
+ return new EchoHandler(thing, gson);
}
return null;
}
@@ -136,7 +146,7 @@ private synchronized void registerDiscoveryService(AccountHandler bridgeHandler)
AmazonEchoDiscovery discoveryService = new AmazonEchoDiscovery(bridgeHandler);
discoveryService.activate();
this.discoveryServiceRegistrations.put(bridgeHandler.getThing().getUID(), bundleContext
- .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable()));
+ .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
}
@Override
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/BindingServlet.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/BindingServlet.java
index bcefee5a83cde..112cd13a9a79b 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/BindingServlet.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/BindingServlet.java
@@ -49,7 +49,7 @@ public class BindingServlet extends HttpServlet {
String servletUrl;
HttpService httpService;
- List accountHandlers = new ArrayList();
+ List accountHandlers = new ArrayList<>();
public BindingServlet(HttpService httpService) {
this.httpService = httpService;
@@ -126,5 +126,4 @@ protected void doGet(@Nullable HttpServletRequest req, @Nullable HttpServletResp
logger.warn("return html failed with uri syntax error {}", e);
}
}
-
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/Connection.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/Connection.java
index 5fd3ace4fe898..a462bba67546f 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/Connection.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/Connection.java
@@ -12,7 +12,12 @@
*/
package org.openhab.binding.amazonechocontrol.internal;
-import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.DEVICE_PROPERTY_APPLIANCE_ID;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.INTERFACE_BRIGHTNESS;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.INTERFACE_COLOR;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.INTERFACE_COLOR_TEMPERATURE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.THING_TYPE_LIGHT;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.THING_TYPE_LIGHT_GROUP;
import java.io.IOException;
import java.io.InputStream;
@@ -34,7 +39,6 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -42,18 +46,20 @@
import java.util.Scanner;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HttpsURLConnection;
-import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.util.HexUtils;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities.Activity;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementContent;
@@ -65,6 +71,8 @@
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAutomation.Payload;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAutomation.Trigger;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBootstrapResult;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBootstrapResult.Authentication;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonColorTemperature;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonColors;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDeviceNotificationState;
@@ -72,6 +80,7 @@
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonEnabledFeeds;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonEqualizer;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonExchangeTokenResponse;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonExchangeTokenResponse.Cookie;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonFeed;
@@ -81,6 +90,7 @@
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationResponse;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationSound;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationSounds;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationsResponse;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlaySearchPhraseOperationPayload;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlayValidationResult;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlayerState;
@@ -95,7 +105,6 @@
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonRegisterAppResponse.Tokens;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonRenewTokenResponse;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeDeviceAlias;
-import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeDevices;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeDevices.SmartHomeDevice;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeGroups.SmartHomeGroup;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonStartRoutineRequest;
@@ -111,6 +120,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
@@ -122,6 +132,11 @@
*/
@NonNullByDefault
public class Connection {
+
+ private static final String THING_THREADPOOL_NAME = "thingHandler";
+
+ protected final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(THING_THREADPOOL_NAME);
+
private static final long expiresIn = 432000; // five days
private static final Pattern charsetPattern = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)");
@@ -141,11 +156,13 @@ public class Connection {
private long renewTime = 0;
private @Nullable String deviceName;
private @Nullable String accountCustomerId;
+ private @Nullable String customerName;
- private final Gson gson = new Gson();
+ private final Gson gson;
private final Gson gsonWithNullSerialization;
- public Connection(@Nullable Connection oldConnection) {
+ public Connection(@Nullable Connection oldConnection, Gson gson) {
+ this.gson = gson;
String frc = null;
String serial = null;
String deviceId = null;
@@ -170,7 +187,7 @@ public Connection(@Nullable Connection oldConnection) {
// generate serial
byte[] serialBinary = new byte[16];
rand.nextBytes(serialBinary);
- this.serial = DatatypeConverter.printHexBinary(serialBinary);
+ this.serial = HexUtils.bytesToHex(serialBinary);
}
if (deviceId != null) {
this.deviceId = deviceId;
@@ -247,13 +264,29 @@ public String getDeviceName() {
return deviceName;
}
+ public String getCustomerId() {
+ String customerId = this.accountCustomerId;
+ if (customerId == null) {
+ return "Unknown";
+ }
+ return customerId;
+ }
+
+ public String getCustomerName() {
+ String customerName = this.customerName;
+ if (customerName == null) {
+ return "Unknown";
+ }
+ return customerName;
+ }
+
public String serializeLoginData() {
Date loginTime = this.loginTime;
if (refreshToken == null || loginTime == null) {
return "";
}
StringBuilder builder = new StringBuilder();
- builder.append("6\n"); // version
+ builder.append("7\n"); // version
builder.append(frc);
builder.append("\n");
builder.append(serial);
@@ -334,8 +367,8 @@ public boolean tryRestoreLogin(@Nullable String data, @Nullable String overloade
}
Scanner scanner = new Scanner(data);
String version = scanner.nextLine();
- // check if serialize version
- if (!version.equals("5") && !version.equals("6")) {
+ // check if serialize version is supported
+ if (!"5".equals(version) && !"6".equals(version) && !"7".equals(version)) {
scanner.close();
return null;
}
@@ -357,8 +390,12 @@ public boolean tryRestoreLogin(@Nullable String data, @Nullable String overloade
if (intVersion > 5) {
String accountCustomerId = scanner.nextLine();
- if (!StringUtils.equals(accountCustomerId, "null")) {
- this.accountCustomerId = accountCustomerId;
+ // Note: version 5 have wrong customer id serialized.
+ // Only use it, if it at least version 6 of serialization
+ if (intVersion > 6) {
+ if (!StringUtils.equals(accountCustomerId, "null")) {
+ this.accountCustomerId = accountCustomerId;
+ }
}
}
@@ -415,6 +452,29 @@ public boolean tryRestoreLogin(@Nullable String data, @Nullable String overloade
return loginTime;
}
+ private @Nullable Authentication tryGetBootstrap() throws IOException, URISyntaxException {
+ HttpsURLConnection connection = makeRequest("GET", alexaServer + "/api/bootstrap", null, false, false, null, 0);
+ String contentType = connection.getContentType();
+ if (connection.getResponseCode() == 200 && StringUtils.startsWithIgnoreCase(contentType, "application/json")) {
+ try {
+ String bootstrapResultJson = convertStream(connection);
+ JsonBootstrapResult result = parseJson(bootstrapResultJson, JsonBootstrapResult.class);
+ Authentication authentication = result.authentication;
+ if (authentication != null && authentication.authenticated) {
+ this.customerName = authentication.customerName;
+ if (this.accountCustomerId == null) {
+ this.accountCustomerId = authentication.customerId;
+ }
+ return authentication;
+ }
+ } catch (JsonSyntaxException | IllegalStateException e) {
+ logger.info("No valid json received {}", e);
+ return null;
+ }
+ }
+ return null;
+ }
+
public String convertStream(HttpsURLConnection connection) throws IOException {
InputStream input = connection.getInputStream();
if (input == null) {
@@ -455,15 +515,20 @@ public String makeRequestAndReturnString(String url) throws IOException, URISynt
public String makeRequestAndReturnString(String verb, String url, @Nullable String postData, boolean json,
@Nullable Map customHeaders) throws IOException, URISyntaxException {
- HttpsURLConnection connection = makeRequest(verb, url, postData, json, true, customHeaders);
- return convertStream(connection);
+ HttpsURLConnection connection = makeRequest(verb, url, postData, json, true, customHeaders, 0);
+ String result = convertStream(connection);
+ this.logger.debug("Result of {} {}:{}", verb, url, result);
+ return result;
}
public HttpsURLConnection makeRequest(String verb, String url, @Nullable String postData, boolean json,
- boolean autoredirect, @Nullable Map customHeaders) throws IOException, URISyntaxException {
+ boolean autoredirect, @Nullable Map customHeaders, int badRequestRepeats)
+ throws IOException, URISyntaxException {
String currentUrl = url;
- for (int i = 0; i < 30; i++) // loop for handling redirect, using automatic redirect is not possible, because
- // all response headers must be catched
+ int redirectCounter = 0;
+ while (true) // loop for handling redirect and bad request, using automatic redirect is not possible,
+ // because
+ // all response headers must be catched
{
int code;
HttpsURLConnection connection = null;
@@ -481,7 +546,7 @@ public HttpsURLConnection makeRequest(String verb, String url, @Nullable String
if (customHeaders != null) {
for (String key : customHeaders.keySet()) {
String value = customHeaders.get(key);
- if (!StringUtil.isBlank(value)) {
+ if (StringUtils.isNotEmpty(value)) {
connection.setRequestProperty(key, value);
}
}
@@ -571,18 +636,35 @@ public HttpsURLConnection makeRequest(String verb, String url, @Nullable String
}
}
}
+ if (code == 400 && badRequestRepeats > 0) {
+ scheduler.schedule(() -> {
+ logger.debug("Retry call to {}", url);
+ try {
+ makeRequest(verb, url, postData, json, autoredirect, customHeaders, badRequestRepeats - 1);
+ } catch (IOException | URISyntaxException e) {
+ logger.debug("Repeat fails {}", e);
+ }
+ }, 500, TimeUnit.MILLISECONDS);
+ return connection;
+ }
if (code == 200) {
logger.debug("Call to {} succeeded", url);
return connection;
}
if (code == 302 && location != null) {
logger.debug("Redirected to {}", location);
+ redirectCounter++;
+ if (redirectCounter > 30) {
+ throw new ConnectionException("Too many redirects");
+ }
currentUrl = location;
if (autoredirect) {
- continue;
+ continue; // repeat with new location
}
return connection;
}
+ throw new HttpException(code, verb + " url '" + url + "' failed: " + connection.getResponseMessage());
+
} catch (IOException e) {
if (connection != null) {
@@ -596,18 +678,14 @@ public HttpsURLConnection makeRequest(String verb, String url, @Nullable String
}
throw e;
}
- if (code != 200) {
- throw new HttpException(code, verb + " url '" + url + "' failed: " + connection.getResponseMessage());
- }
}
- throw new ConnectionException("Too many redirects");
}
public String registerConnectionAsApp(String oAutRedirectUrl)
throws ConnectionException, IOException, URISyntaxException {
URI oAutRedirectUri = new URI(oAutRedirectUrl);
- Map queryParameters = new LinkedHashMap();
+ Map queryParameters = new LinkedHashMap<>();
String query = oAutRedirectUri.getQuery();
String[] pairs = query.split("&");
for (String pair : pairs) {
@@ -617,9 +695,9 @@ public String registerConnectionAsApp(String oAutRedirectUrl)
}
String accessToken = queryParameters.get("openid.oa2.access_token");
- Map cookieMap = new HashMap();
+ Map cookieMap = new HashMap<>();
- List webSiteCookies = new ArrayList();
+ List webSiteCookies = new ArrayList<>();
for (HttpCookie cookie : getSessionCookies("https://www.amazon.com")) {
cookieMap.put(cookie.getName(), cookie.getValue());
webSiteCookies.add(new JsonWebSiteCookie(cookie.getName(), cookie.getValue()));
@@ -632,7 +710,7 @@ public String registerConnectionAsApp(String oAutRedirectUrl)
webSiteCookiesArray);
String registerAppRequestJson = gson.toJson(registerAppRequest);
- HashMap registerHeaders = new HashMap();
+ HashMap registerHeaders = new HashMap<>();
registerHeaders.put("x-amzn-identity-auth-domain", "api.amazon.com");
String registerAppResultJson = makeRequestAndReturnString("POST", "https://api.amazon.com/auth/register",
@@ -669,6 +747,7 @@ public String registerConnectionAsApp(String oAutRedirectUrl)
setAmazonSite(host);
try {
exhangeToken();
+ tryGetBootstrap();
} catch (Exception e) {
logout();
throw e;
@@ -699,7 +778,7 @@ private void exhangeToken() throws IOException, URISyntaxException {
+ "&requested_token_type=auth_cookies&source_token_type=refresh_token&di.hw.version=iPhone&di.sdk.version=6.10.0&cookies="
+ cookiesBase64 + "&app_name=Amazon%20Alexa&di.os.version=11.4.1";
- HashMap exchangeTokenHeader = new HashMap();
+ HashMap exchangeTokenHeader = new HashMap<>();
exchangeTokenHeader.put("Cookie", "");
String exchangeTokenJson = makeRequestAndReturnString("POST",
@@ -782,22 +861,22 @@ public boolean verifyLogin() throws IOException, URISyntaxException {
if (this.refreshToken == null) {
return false;
}
- String response = makeRequestAndReturnString(alexaServer + "/api/bootstrap?version=0");
- Boolean result = response.contains("\"authenticated\":true");
- if (result) {
+ Authentication authentication = tryGetBootstrap();
+ if (authentication != null && authentication.authenticated) {
verifyTime = new Date();
if (loginTime == null) {
loginTime = verifyTime;
}
+ return true;
}
- return result;
+ return false;
}
public List getSessionCookies() {
try {
return cookieManager.getCookieStore().get(new URI(alexaServer));
} catch (URISyntaxException e) {
- return new ArrayList();
+ return new ArrayList<>();
}
}
@@ -805,7 +884,7 @@ public List getSessionCookies(String server) {
try {
return cookieManager.getCookieStore().get(new URI(server));
} catch (URISyntaxException e) {
- return new ArrayList();
+ return new ArrayList<>();
}
}
@@ -819,10 +898,10 @@ public void logout() {
}
// parser
- private T parseJson(String json, Class type) throws JsonSyntaxException {
+ private T parseJson(String json, Class type) throws JsonSyntaxException, IllegalStateException {
try {
return gson.fromJson(json, type);
- } catch (JsonSyntaxException e) {
+ } catch (JsonParseException | IllegalStateException e) {
logger.warn("Parsing json failed {}", e);
logger.warn("Illegal json: {}", json);
throw e;
@@ -893,8 +972,11 @@ public List getSmarthomeDeviceList() throws IOException, URISyn
ArrayList smartDevices = new ArrayList<>();
for (int i = 0; i < smartHomeDeviceArray.size(); ++i) {
- if (smartHomeDeviceArray.get(i).groupIdentity != null && group.applianceGroupIdentifier.value != null) {
- if (smartHomeDeviceArray.get(i).groupIdentity.equals(group.applianceGroupIdentifier.value)) {
+ if (smartHomeDeviceArray.get(i).groupIdentity != null && group.applianceGroupIdentifier != null) {
+ String groupIdentity = smartHomeDeviceArray.get(i).groupIdentity;
+ @SuppressWarnings("null")
+ String applianceGroupIdentifier = group.applianceGroupIdentifier.value;
+ if (groupIdentity != null && groupIdentity.equals(applianceGroupIdentifier)) {
smartDevices.add(smartHomeDeviceArray.get(i));
if (group.applianceGroupName != null) {
alias[0] = new JsonSmartHomeDeviceAlias(group.applianceGroupName, true);
@@ -907,8 +989,8 @@ public List getSmarthomeDeviceList() throws IOException, URISyn
smartDevices.toArray(smartDevicesArray);
if (group.applianceGroupName != null) {
- SmartHomeDevice shdGroup = new JsonSmartHomeDevices().new SmartHomeDevice(uuid, "Amazon",
- "Amazon Light Group", group.applianceGroupName, "reachable", uuid, alias, smartDevicesArray);
+ SmartHomeDevice shdGroup = new SmartHomeDevice(uuid, "Amazon", "Amazon Light Group",
+ group.applianceGroupName, "reachable", uuid, alias, smartDevicesArray);
smartHomeDeviceArray.add(shdGroup);
}
@@ -943,7 +1025,7 @@ public List getSmarthomeDeviceGroups() throws IOException, URISy
return smartHomeGroupArray;
}
- // Placeholder for an api-request
+ // Need to cache the light colors here
public List getEchoLightColors() {
ArrayList colors = new ArrayList<>();
String[] stringColors = { "red", "crimson", "salmon", "orange", "gold", "yellow", "green", "turquoise", "cyan",
@@ -955,7 +1037,7 @@ public List getEchoLightColors() {
return colors;
}
- // Placeholder for an api-request
+ // Need to cache the light temperature list here
public List getEchoLightTemperatures() {
ArrayList temperatures = new ArrayList<>();
String[] stringTemperatures = { "warm_white", "soft_white", "white", "daylight_white", "cool_white" };
@@ -1106,6 +1188,7 @@ public String getBulbState(Thing device) throws IOException, URISyntaxException
String state = null;
if (device.getThingTypeUID().equals(THING_TYPE_LIGHT)
|| device.getThingTypeUID().equals(THING_TYPE_LIGHT_GROUP)) {
+
JsonArray capabilities = this.getBulbCapabilities(applianceId);
for (JsonElement capability : capabilities) {
@@ -1213,7 +1296,7 @@ public JsonPlaylists getPlaylists(Device device) throws IOException, URISyntaxEx
public void command(Device device, String command) throws IOException, URISyntaxException {
String url = alexaServer + "/api/np/command?deviceSerialNumber=" + device.serialNumber + "&deviceType="
+ device.deviceType;
- makeRequest("POST", url, command, true, true, null);
+ makeRequest("POST", url, command, true, true, null, 0);
}
public void smartHomeCommand(String entityId, String action, @Nullable String color, double brightness)
@@ -1237,7 +1320,7 @@ public void smartHomeCommand(String entityId, String action, @Nullable String co
+ ", \"entityType\": \"APPLIANCE\", \"parameters\": { \"action\": " + "\"" + action + "\""
+ ", \"brightness\": \"" + brightness + "\" }}]}";
}
- makeRequest("PUT", url, requestBody, true, true, null);
+ makeRequest("PUT", url, requestBody, true, true, null, 0);
}
public void notificationVolume(Device device, int volume) throws IOException, URISyntaxException {
@@ -1245,7 +1328,7 @@ public void notificationVolume(Device device, int volume) throws IOException, UR
+ "/" + device.serialNumber;
String command = "{\"deviceSerialNumber\":\"" + device.serialNumber + "\",\"deviceType\":\"" + device.deviceType
+ "\",\"softwareVersion\":\"" + device.softwareVersion + "\",\"volumeLevel\":" + volume + "}";
- makeRequest("PUT", url, command, true, true, null);
+ makeRequest("PUT", url, command, true, true, null, 0);
}
public void ascendingAlarm(Device device, boolean ascendingAlarm) throws IOException, URISyntaxException {
@@ -1253,7 +1336,7 @@ public void ascendingAlarm(Device device, boolean ascendingAlarm) throws IOExcep
String command = "{\"ascendingAlarmEnabled\":" + (ascendingAlarm ? "true" : "false")
+ ",\"deviceSerialNumber\":\"" + device.serialNumber + "\",\"deviceType\":\"" + device.deviceType
+ "\",\"deviceAccountId\":null}";
- makeRequest("PUT", url, command, true, true, null);
+ makeRequest("PUT", url, command, true, true, null, 0);
}
public DeviceNotificationState[] getDeviceNotificationStates() {
@@ -1291,11 +1374,11 @@ public void bluetooth(Device device, @Nullable String address) throws IOExceptio
// disconnect
makeRequest("POST",
alexaServer + "/api/bluetooth/disconnect-sink/" + device.deviceType + "/" + device.serialNumber, "",
- true, true, null);
+ true, true, null, 0);
} else {
makeRequest("POST",
alexaServer + "/api/bluetooth/pair-sink/" + device.deviceType + "/" + device.serialNumber,
- "{\"bluetoothDeviceAddress\":\"" + address + "\"}", true, true, null);
+ "{\"bluetoothDeviceAddress\":\"" + address + "\"}", true, true, null, 0);
}
}
@@ -1309,7 +1392,7 @@ public void playRadio(Device device, @Nullable String stationId) throws IOExcept
+ "&contentType=station&callSign=&mediaOwnerCustomerId="
+ (StringUtils.isEmpty(this.accountCustomerId) ? device.deviceOwnerCustomerId
: this.accountCustomerId),
- "", true, true, null);
+ "", true, true, null, 0);
}
}
@@ -1324,7 +1407,7 @@ public void playAmazonMusicTrack(Device device, @Nullable String trackId) throws
+ (StringUtils.isEmpty(this.accountCustomerId) ? device.deviceOwnerCustomerId
: this.accountCustomerId)
+ "&shuffle=false",
- command, true, true, null);
+ command, true, true, null, 0);
}
}
@@ -1340,13 +1423,13 @@ public void playAmazonMusicPlayList(Device device, @Nullable String playListId)
+ (StringUtils.isEmpty(this.accountCustomerId) ? device.deviceOwnerCustomerId
: this.accountCustomerId)
+ "&shuffle=false",
- command, true, true, null);
+ command, true, true, null, 0);
}
}
public void sendNotificationToMobileApp(String customerId, String text, @Nullable String title)
throws IOException, URISyntaxException {
- Map parameters = new Hashtable();
+ Map parameters = new HashMap<>();
parameters.put("notificationMessage", text);
parameters.put("alexaUrl", "#v2/behaviors");
if (title != null && !StringUtils.isEmpty(title)) {
@@ -1358,9 +1441,9 @@ public void sendNotificationToMobileApp(String customerId, String text, @Nullabl
executeSequenceCommand(null, "Alexa.Notifications.SendMobilePush", parameters);
}
- public void sendAnnouncement(Device device, String text, @Nullable String title)
- throws IOException, URISyntaxException {
- Map parameters = new Hashtable();
+ public void sendAnnouncement(Device device, String text, String bodyText, @Nullable String title, int ttsVolume,
+ int standardVolume) throws IOException, URISyntaxException {
+ Map parameters = new HashMap<>();
parameters.put("expireAfter", "PT5S");
JsonAnnouncementContent[] contentArray = new JsonAnnouncementContent[1];
JsonAnnouncementContent content = new JsonAnnouncementContent();
@@ -1369,7 +1452,10 @@ public void sendAnnouncement(Device device, String text, @Nullable String title)
} else {
content.display.title = title;
}
- content.display.body = text;
+ content.display.body = bodyText;
+ if (text.startsWith("") && text.endsWith("")) {
+ content.speak.type = "ssml";
+ }
content.speak.value = text;
contentArray[0] = content;
@@ -1379,48 +1465,54 @@ public void sendAnnouncement(Device device, String text, @Nullable String title)
JsonAnnouncementTarget target = new JsonAnnouncementTarget();
target.customerId = device.deviceOwnerCustomerId;
TargetDevice[] devices = new TargetDevice[1];
- TargetDevice deviceTarget = target.new TargetDevice();
+ TargetDevice deviceTarget = new TargetDevice();
+ deviceTarget.deviceSerialNumber = device.serialNumber;
+ deviceTarget.deviceTypeId = device.deviceType;
devices[0] = deviceTarget;
target.devices = devices;
parameters.put("target", target);
- String customerId = device.deviceOwnerCustomerId;
+ String accountCustomerId = this.accountCustomerId;
+ String customerId = StringUtils.isEmpty(accountCustomerId) ? device.deviceOwnerCustomerId : accountCustomerId;
+
if (customerId != null) {
parameters.put("customerId", customerId);
}
- executeSequenceCommand(null, "AlexaAnnouncement", parameters);
+ executeSequenceCommandWithVolume(device, "AlexaAnnouncement", parameters, ttsVolume, standardVolume);
}
public void textToSpeech(Device device, String text, int ttsVolume, int standardVolume)
throws IOException, URISyntaxException {
+ Map parameters = new HashMap<>();
+ parameters.put("textToSpeak", text);
+ executeSequenceCommandWithVolume(device, "Alexa.Speak", parameters, ttsVolume, standardVolume);
+ }
+ private void executeSequenceCommandWithVolume(@Nullable Device device, String command,
+ @Nullable Map parameters, int ttsVolume, int standardVolume)
+ throws IOException, URISyntaxException {
if (ttsVolume != 0) {
JsonArray nodesToExecute = new JsonArray();
- Map parameters = new Hashtable();
-
+ Map volumeParameters = new HashMap<>();
// add tts volume
- parameters.clear();
- parameters.put("value", ttsVolume);
- nodesToExecute.add(createExecutionNode(device, "Alexa.DeviceControls.Volume", parameters));
+ volumeParameters.clear();
+ volumeParameters.put("value", ttsVolume);
+ nodesToExecute.add(createExecutionNode(device, "Alexa.DeviceControls.Volume", volumeParameters));
- // add tts
- parameters.clear();
- parameters.put("textToSpeak", text);
- nodesToExecute.add(createExecutionNode(device, "Alexa.Speak", parameters));
+ // add command
+ nodesToExecute.add(createExecutionNode(device, command, parameters));
// add volume
- parameters.clear();
- parameters.put("value", standardVolume);
- nodesToExecute.add(createExecutionNode(device, "Alexa.DeviceControls.Volume", parameters));
+ volumeParameters.clear();
+ volumeParameters.put("value", standardVolume);
+ nodesToExecute.add(createExecutionNode(device, "Alexa.DeviceControls.Volume", volumeParameters));
executeSequenceNodes(nodesToExecute);
} else {
- Map parameters = new Hashtable();
- parameters.put("textToSpeak", text);
- executeSequenceCommand(device, "Alexa.Speak", parameters);
+ executeSequenceCommand(device, command, parameters);
}
}
@@ -1441,10 +1533,10 @@ private void executeSequenceNode(JsonObject nodeToExecute) throws IOException, U
request.sequenceJson = gson.toJson(sequenceJson);
String json = gson.toJson(request);
- Map headers = new HashMap();
+ Map headers = new HashMap<>();
headers.put("Routines-Version", "1.1.218665");
- makeRequest("POST", alexaServer + "/api/behaviors/preview", json, true, true, null);
+ makeRequest("POST", alexaServer + "/api/behaviors/preview", json, true, true, null, 3);
}
private void executeSequenceNodes(JsonArray nodesToExecute) throws IOException, URISyntaxException {
@@ -1552,14 +1644,14 @@ public void startRoutine(Device device, String utterance) throws IOException, UR
request.sequenceJson = sequenceJson;
String requestJson = gson.toJson(request);
- makeRequest("POST", alexaServer + "/api/behaviors/preview", requestJson, true, true, null);
+ makeRequest("POST", alexaServer + "/api/behaviors/preview", requestJson, true, true, null, 3);
} else {
logger.warn("Routine {} not found", utterance);
}
}
public JsonAutomation[] getRoutines() throws IOException, URISyntaxException {
- String json = makeRequestAndReturnString(alexaServer + "/api/behaviors/automations");
+ String json = makeRequestAndReturnString(alexaServer + "/api/behaviors/automations?limit=2000");
JsonAutomation[] result = parseJson(json, JsonAutomation[].class);
return result;
}
@@ -1578,7 +1670,7 @@ public void setEnabledFlashBriefings(JsonFeed[] enabledFlashBriefing) throws IOE
JsonEnabledFeeds enabled = new JsonEnabledFeeds();
enabled.enabledFeeds = enabledFlashBriefing;
String json = gsonWithNullSerialization.toJson(enabled);
- makeRequest("POST", alexaServer + "/api/content-skills/enabled-feeds", json, true, true, null);
+ makeRequest("POST", alexaServer + "/api/content-skills/enabled-feeds", json, true, true, null, 0);
}
public JsonNotificationSound[] getNotificationSounds(Device device) throws IOException, URISyntaxException {
@@ -1593,12 +1685,22 @@ public JsonNotificationSound[] getNotificationSounds(Device device) throws IOExc
return new JsonNotificationSound[0];
}
+ public JsonNotificationResponse[] notifications() throws IOException, URISyntaxException {
+ String response = makeRequestAndReturnString(alexaServer + "/api/notifications");
+ JsonNotificationsResponse result = parseJson(response, JsonNotificationsResponse.class);
+ JsonNotificationResponse[] notifications = result.notifications;
+ if (notifications == null) {
+ return new JsonNotificationResponse[0];
+ }
+ return notifications;
+ }
+
public JsonNotificationResponse notification(Device device, String type, @Nullable String label,
@Nullable JsonNotificationSound sound) throws IOException, URISyntaxException {
Date date = new Date(new Date().getTime());
long createdDate = date.getTime();
Date alarm = new Date(createdDate + 5000); // add 5 seconds, because amazon does not except calls for times in
- // the past (compared with the server time)
+ // the past (compared with the server time)
long alarmTime = alarm.getTime();
JsonNotificationRequest request = new JsonNotificationRequest();
@@ -1636,7 +1738,7 @@ public JsonNotificationResponse getNotificationState(JsonNotificationResponse no
public List getMusicProviders() {
String response;
try {
- Map headers = new HashMap();
+ Map headers = new HashMap<>();
headers.put("Routines-Version", "1.1.218665");
response = makeRequestAndReturnString("GET",
alexaServer + "/api/behaviors/entities?skillId=amzn1.ask.1p.music", null, true, headers);
@@ -1654,7 +1756,8 @@ public List getMusicProviders() {
public void playMusicVoiceCommand(Device device, String providerId, String voiceCommand)
throws IOException, URISyntaxException {
JsonPlaySearchPhraseOperationPayload payload = new JsonPlaySearchPhraseOperationPayload();
- payload.customerId = device.deviceOwnerCustomerId;
+ payload.customerId = (StringUtils.isEmpty(this.accountCustomerId) ? device.deviceOwnerCustomerId
+ : this.accountCustomerId);
payload.locale = "ALEXA_CURRENT_LOCALE";
payload.musicProviderId = providerId;
payload.searchPhrase = voiceCommand;
@@ -1697,6 +1800,18 @@ public void playMusicVoiceCommand(Device device, String providerId, String voice
startRoutineRequest.status = null;
String postData = gson.toJson(startRoutineRequest);
- makeRequest("POST", alexaServer + "/api/behaviors/preview", postData, true, true, null);
+ makeRequest("POST", alexaServer + "/api/behaviors/preview", postData, true, true, null, 3);
+ }
+
+ public JsonEqualizer getEqualizer(Device device) throws IOException, URISyntaxException {
+ String json = makeRequestAndReturnString(
+ alexaServer + "/api/equalizer/" + device.serialNumber + "/" + device.deviceType);
+ return parseJson(json, JsonEqualizer.class);
+ }
+
+ public void SetEqualizer(Device device, JsonEqualizer settings) throws IOException, URISyntaxException {
+ String postData = gson.toJson(settings);
+ makeRequest("POST", alexaServer + "/api/equalizer/" + device.serialNumber + "/" + device.deviceType, postData,
+ true, true, null, 0);
}
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/WebSocketConnection.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/WebSocketConnection.java
index 949cfde646b55..302e7c90dcbaa 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/WebSocketConnection.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/WebSocketConnection.java
@@ -82,7 +82,7 @@ public WebSocketConnection(String amazonSite, List sessionCookies,
}
String deviceSerial = "";
- List cookiesForWs = new ArrayList();
+ List cookiesForWs = new ArrayList<>();
for (HttpCookie cookie : sessionCookies) {
if (cookie.getName().equals("ubid-acbde")) {
deviceSerial = cookie.getValue();
@@ -149,7 +149,18 @@ public void close() {
Session session = this.session;
this.session = null;
if (session != null) {
- session.close();
+ try {
+ session.close();
+ } catch (Exception e) {
+ logger.debug("Closing sessing failed {}", e);
+ }
+ }
+ try {
+ webSocketClient.stop();
+ } catch (InterruptedException e) {
+ // Just ignore
+ } catch (Exception e) {
+ logger.debug("Stopping websocket failed {}", e);
}
webSocketClient.destroy();
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandler.java
new file mode 100644
index 0000000000000..cd288e6dc3d46
--- /dev/null
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandler.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.channelhandler;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.types.Command;
+import org.openhab.binding.amazonechocontrol.internal.Connection;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * The {@link ChannelHandler} is the base class for all channel handlers
+ *
+ * @author Michael Geramb - Initial contribution
+ */
+public abstract class ChannelHandler {
+ public abstract boolean tryHandleCommand(Device device, Connection connection, String channelId, Command command)
+ throws IOException, URISyntaxException;
+
+ protected final IAmazonThingHandler thingHandler;
+ protected final Gson gson;
+ private final Logger logger;
+
+ protected ChannelHandler(IAmazonThingHandler thingHandler, Gson gson) {
+ this.logger = LoggerFactory.getLogger(this.getClass());
+ this.thingHandler = thingHandler;
+ this.gson = gson;
+ }
+
+ protected @Nullable T tryParseJson(String json, Class type) {
+ try {
+ return gson.fromJson(json, type);
+ } catch (JsonSyntaxException e) {
+ logger.debug("Json parse error {}", e);
+ return null;
+ }
+ }
+
+ protected @Nullable T parseJson(String json, Class type) throws JsonSyntaxException {
+ return gson.fromJson(json, type);
+
+ }
+}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandlerAnnouncement.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandlerAnnouncement.java
new file mode 100644
index 0000000000000..26425b44b21aa
--- /dev/null
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/ChannelHandlerAnnouncement.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.channelhandler;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.types.Command;
+import org.openhab.binding.amazonechocontrol.internal.Connection;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+
+/**
+ * The {@link ChannelHandlerAnnouncement} is responsible for the announcement channel
+ *
+ * @author Michael Geramb - Initial contribution
+ */
+public class ChannelHandlerAnnouncement extends ChannelHandler {
+ public static final String CHANNEL_NAME = "announcement";
+
+ public ChannelHandlerAnnouncement(IAmazonThingHandler thingHandler, Gson gson) {
+ super(thingHandler, gson);
+ }
+
+ @Override
+ public boolean tryHandleCommand(Device device, Connection connection, String channelId, Command command)
+ throws IOException, URISyntaxException {
+ if (channelId.equals(CHANNEL_NAME)) {
+ if (command instanceof StringType) {
+ String commandValue = ((StringType) command).toFullString();
+ String body = commandValue;
+ String title = null;
+ String speak = " "; // blank generates a beep
+ if (commandValue.startsWith("{") && commandValue.endsWith("}")) {
+ try {
+ AnnouncementRequestJson request = parseJson(commandValue, AnnouncementRequestJson.class);
+ if (request != null) {
+ title = request.title;
+ body = request.body;
+ if (body == null) {
+ body = "";
+ }
+ if (request.sound == false) {
+ speak = "";
+ }
+ }
+ } catch (JsonSyntaxException e) {
+ body = e.getLocalizedMessage();
+ }
+ }
+ connection.sendAnnouncement(device, speak, body, title, 0, 0);
+ }
+ RefreshChannel();
+ }
+ return false;
+ }
+
+ void RefreshChannel() {
+ thingHandler.updateChannelState(CHANNEL_NAME, new StringType(""));
+ }
+
+ class AnnouncementRequestJson {
+ public @Nullable Boolean sound;
+ public @Nullable String title;
+ public @Nullable String body;
+ }
+}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/IAmazonThingHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/IAmazonThingHandler.java
new file mode 100644
index 0000000000000..f0e412c9879ed
--- /dev/null
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/channelhandler/IAmazonThingHandler.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.channelhandler;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.types.State;
+
+/**
+ * The {@link IAmazonThingHandler} is used from ChannelHandlers to communicate with the thing
+ *
+ * @author Michael Geramb - Initial contribution
+ */
+@NonNullByDefault
+public interface IAmazonThingHandler {
+ void updateChannelState(String channelId, State state);
+}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/AmazonEchoDiscovery.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/AmazonEchoDiscovery.java
index 437961fb7890a..d5dd3ca0b46ca 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/AmazonEchoDiscovery.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/AmazonEchoDiscovery.java
@@ -15,8 +15,8 @@
import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
import java.util.Date;
+import java.util.HashMap;
import java.util.HashSet;
-import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
@@ -49,7 +49,7 @@ public class AmazonEchoDiscovery extends AbstractDiscoveryService implements Ext
AccountHandler accountHandler;
private final Logger logger = LoggerFactory.getLogger(AmazonEchoDiscovery.class);
- private final HashSet discoverdFlashBriefings = new HashSet();
+ private final HashSet discoverdFlashBriefings = new HashSet<>();
@Nullable
ScheduledFuture> startScanStateJob;
@@ -68,7 +68,7 @@ public AmazonEchoDiscovery(AccountHandler accountHandler) {
}
public void activate() {
- activate(new Hashtable());
+ activate(new HashMap<>());
}
@Override
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/SmartHomeDevicesDiscovery.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/SmartHomeDevicesDiscovery.java
index 1840da3783f82..3c75693c73f3c 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/SmartHomeDevicesDiscovery.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/discovery/SmartHomeDevicesDiscovery.java
@@ -1,3 +1,15 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.discovery;
import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
@@ -13,6 +25,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService;
import org.eclipse.smarthome.config.discovery.DiscoveryResult;
import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder;
@@ -127,6 +140,13 @@ synchronized void setSmartHomeDevices(List deviceList) {
return;
}
+ Configuration config = accountHandler.getThing().getConfiguration();
+ boolean discoverSmartHome = (boolean) config.getProperties().get("discoverSmartHome");
+
+ if (discoverSmartHome == false) {
+ return;
+ }
+
for (SmartHomeDevice smartHomeDevice : deviceList) {
ThingUID bridgeThingUID = this.accountHandler.getThing().getUID();
ThingTypeUID thingTypeId = smartHomeDevice.groupDevices != null ? THING_TYPE_LIGHT_GROUP : THING_TYPE_LIGHT;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/AccountHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/AccountHandler.java
index 8ceef6b571503..fa03318850fd3 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/AccountHandler.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/AccountHandler.java
@@ -16,6 +16,7 @@
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.net.UnknownHostException;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -54,10 +55,12 @@
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushActivity.Key;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushDevice;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushDevice.DopplerId;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushNotificationChange;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDeviceNotificationState.DeviceNotificationState;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonFeed;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonMusicProvider;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationResponse;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonNotificationSound;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPlaylists;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonPushCommand;
@@ -94,11 +97,12 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
private String currentFlashBriefingJson = "";
private final HttpService httpService;
private @Nullable AccountServlet accountServlet;
- private final Gson gson = new Gson();
+ private final Gson gson;
int checkDataCounter;
- public AccountHandler(Bridge bridge, HttpService httpService, Storage stateStorage) {
+ public AccountHandler(Bridge bridge, HttpService httpService, Storage stateStorage, Gson gson) {
super(bridge);
+ this.gson = gson;
this.httpService = httpService;
this.stateStorage = stateStorage;
}
@@ -110,11 +114,11 @@ public void initialize() {
synchronized (synchronizeConnection) {
Connection connection = this.connection;
if (connection == null) {
- this.connection = new Connection(null);
+ this.connection = new Connection(null, gson);
}
}
if (this.accountServlet == null) {
- this.accountServlet = new AccountServlet(httpService, this.getThing().getUID().getId(), this);
+ this.accountServlet = new AccountServlet(httpService, this.getThing().getUID().getId(), this, gson);
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Wait for login");
@@ -163,7 +167,7 @@ public void addSmartHomeDeviceHandler(SmartHomeDeviceHandler smartHomeDeviceHand
forceCheckData();
}
- void forceCheckData() {
+ public void forceCheckData() {
if (foceCheckDataJob == null) {
foceCheckDataJob = scheduler.schedule(this::forceCheckDataHandler, 1000, TimeUnit.MILLISECONDS);
}
@@ -197,7 +201,7 @@ public void addFlashBriefingProfileHandler(FlashBriefingProfileHandler flashBrie
flashBriefingProfileHandlers.add(flashBriefingProfileHandler);
}
Connection connection = this.connection;
- if (connection != null) {
+ if (connection != null && connection.getIsLoggedIn()) {
if (currentFlashBriefingJson.isEmpty()) {
updateFlashBriefingProfiles(connection);
}
@@ -205,6 +209,16 @@ public void addFlashBriefingProfileHandler(FlashBriefingProfileHandler flashBrie
}
}
+ private void scheduleUpdate() {
+ checkDataCounter = 999;
+ }
+
+ @Override
+ public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
+ super.childHandlerInitialized(childHandler, childThing);
+ scheduleUpdate();
+ }
+
@Override
public void handleRemoval() {
cleanup();
@@ -338,7 +352,7 @@ public void setConnection(@Nullable Connection connection) {
updateDeviceList();
updateFlashBriefingHandlers();
updateStatus(ThingStatus.ONLINE);
- checkDataCounter = 0;
+ scheduleUpdate();
checkData();
}
}
@@ -391,6 +405,30 @@ private void checkData() {
}
}
+ private void refreshNotifications(@Nullable JsonCommandPayloadPushNotificationChange pushPayload) {
+ Connection currentConnection = this.connection;
+ if (currentConnection == null) {
+ return;
+ }
+ if (!currentConnection.getIsLoggedIn()) {
+ return;
+ }
+ JsonNotificationResponse[] notifications;
+ ZonedDateTime timeStamp = ZonedDateTime.now();
+ try {
+ notifications = currentConnection.notifications();
+ } catch (IOException | URISyntaxException e) {
+ logger.debug("refreshNotifications failed {}", e);
+ return;
+ }
+ ZonedDateTime timeStampNow = ZonedDateTime.now();
+
+ for (EchoHandler child : echoHandlers) {
+ child.updateNotifications(timeStamp, timeStampNow, pushPayload, notifications);
+ }
+
+ }
+
private void refreshData() {
synchronized (synchronizeConnection) {
try {
@@ -486,6 +524,9 @@ private void refreshData() {
notificationSounds, musicProviders);
}
+ // refresh notifications
+ refreshNotifications(null);
+
// update account state
updateStatus(ThingStatus.ONLINE);
@@ -564,7 +605,7 @@ public List updateDeviceList() {
Connection currentConnection = connection;
if (currentConnection == null) {
- return new ArrayList();
+ return new ArrayList<>();
}
List devices = null;
@@ -606,7 +647,7 @@ public List updateDeviceList() {
if (devices != null) {
return devices;
}
- return new ArrayList();
+ return new ArrayList<>();
}
public void setEnabledFlashBriefingsJson(String flashBriefingJson) {
@@ -712,7 +753,9 @@ void handleWebsocketCommand(JsonPushCommand pushCommand) {
TimeUnit.MILLISECONDS);
break;
case "PUSH_NOTIFICATION_CHANGE":
- // Currently ignored
+ JsonCommandPayloadPushNotificationChange pushPayload = gson.fromJson(pushCommand.payload,
+ JsonCommandPayloadPushNotificationChange.class);
+ refreshNotifications(pushPayload);
break;
default:
String payload = pushCommand.payload;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/DeviceHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/DeviceHandler.java
index 1bd2ff07b9720..f3b031ebda1b6 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/DeviceHandler.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/DeviceHandler.java
@@ -33,9 +33,7 @@
import org.slf4j.LoggerFactory;
/**
- *
* @author Lukas Knoeller
- *
*/
public class DeviceHandler extends BaseThingHandler {
@@ -64,7 +62,7 @@ public void initialize() {
if (bridge != null) {
AccountHandler account = (AccountHandler) bridge.getHandler();
if (account != null) {
- // TODO
+ updateSmartHomeDevices();
}
}
}
@@ -73,7 +71,7 @@ public void initialize() {
public void handleCommand(ChannelUID channelUID, Command command) {
logger.trace("Command {} received from channel '{}'", command, channelUID);
if (command instanceof RefreshType) {
- // updateSmartHomeDevices();
+ updateSmartHomeDevices();
}
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/EchoHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/EchoHandler.java
index e9eed8bf1a418..2509589adeb1c 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/EchoHandler.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/EchoHandler.java
@@ -12,21 +12,71 @@
*/
package org.openhab.binding.amazonechocontrol.internal.handler;
-import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_AMAZON_MUSIC;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_AMAZON_MUSIC_PLAY_LIST_ID;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_AMAZON_MUSIC_TRACK_ID;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_ASCENDING_ALARM;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_BLUETOOTH;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_BLUETOOTH_DEVICE_NAME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_BLUETOOTH_MAC;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_EQUALIZER_BASS;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_EQUALIZER_MIDRANGE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_EQUALIZER_TREBLE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_IMAGE_URL;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_LAST_VOICE_COMMAND;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_MEDIA_LENGTH;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_MEDIA_PROGRESS;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_MEDIA_PROGRESS_TIME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_MUSIC_PROVIDER_ID;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_NEXT_ALARM;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_NEXT_MUSIC_ALARM;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_NEXT_REMINDER;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_NEXT_TIMER;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_NOTIFICATION_VOLUME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_PLAYER;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_PLAY_ALARM_SOUND;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_PLAY_MUSIC_VOICE_COMMAND;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_PLAY_ON_DEVICE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_PROVIDER_DISPLAY_NAME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_RADIO;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_RADIO_STATION_ID;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_REMIND;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_SHUFFLE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_START_COMMAND;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_START_ROUTINE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_SUBTITLE1;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_SUBTITLE2;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_TEXT_TO_SPEECH;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_TEXT_TO_SPEECH_VOLUME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_TITLE;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_VOLUME;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.DEVICE_PROPERTY_SERIAL_NUMBER;
+import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.FLASH_BRIEFING_COMMAND_PREFIX;
import java.io.IOException;
import java.net.URISyntaxException;
-import java.util.Hashtable;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.measure.quantity.Time;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.library.types.DateTimeType;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType;
import org.eclipse.smarthome.core.library.types.NextPreviousType;
@@ -45,18 +95,25 @@
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
+import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.amazonechocontrol.internal.Connection;
+import org.openhab.binding.amazonechocontrol.internal.ConnectionException;
import org.openhab.binding.amazonechocontrol.internal.HttpException;
+import org.openhab.binding.amazonechocontrol.internal.channelhandler.ChannelHandler;
+import org.openhab.binding.amazonechocontrol.internal.channelhandler.ChannelHandlerAnnouncement;
+import org.openhab.binding.amazonechocontrol.internal.channelhandler.IAmazonThingHandler;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities.Activity;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities.Activity.Description;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAscendingAlarm.AscendingAlarmModel;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates.BluetoothState;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonBluetoothStates.PairedDevice;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushNotificationChange;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonCommandPayloadPushVolumeChange;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDeviceNotificationState.DeviceNotificationState;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
+import org.openhab.binding.amazonechocontrol.internal.jsons.JsonEqualizer;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonMediaState;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonMediaState.QueueEntry;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonMusicProvider;
@@ -81,11 +138,12 @@
* @author Michael Geramb - Initial contribution
*/
@NonNullByDefault
-public class EchoHandler extends BaseThingHandler {
+public class EchoHandler extends BaseThingHandler implements IAmazonThingHandler {
private final Logger logger = LoggerFactory.getLogger(EchoHandler.class);
- private Gson gson = new Gson();
+ private Gson gson;
private @Nullable Device device;
+ private Set capabilities = new HashSet<>();
private @Nullable AccountHandler account;
private @Nullable ScheduledFuture> updateStateJob;
private @Nullable ScheduledFuture> ignoreVolumeChange;
@@ -100,6 +158,7 @@ public class EchoHandler extends BaseThingHandler {
private boolean isPaused = false;
private int lastKnownVolume = 25;
private int textToSpeechVolume = 0;
+ private @Nullable JsonEqualizer lastKnownEqualizer = null;
private @Nullable BluetoothState bluetoothState;
private boolean disableUpdate = false;
private boolean updateRemind = true;
@@ -113,6 +172,7 @@ public class EchoHandler extends BaseThingHandler {
private @Nullable JsonPlaylists playLists;
private @Nullable JsonNotificationSound @Nullable [] alarmSounds;
private @Nullable List musicProviders;
+ private List channelHandlers = new ArrayList<>();
private @Nullable JsonNotificationResponse currentNotification;
private @Nullable ScheduledFuture> currentNotifcationUpdateTimer;
@@ -121,8 +181,10 @@ public class EchoHandler extends BaseThingHandler {
long mediaStartMs;
String lastSpokenText = "";
- public EchoHandler(Thing thing) {
+ public EchoHandler(Thing thing, Gson gson) {
super(thing);
+ this.gson = gson;
+ channelHandlers.add(new ChannelHandlerAnnouncement(this, this.gson));
}
@Override
@@ -149,6 +211,10 @@ public boolean setDeviceAndUpdateThingState(AccountHandler accountHandler, @Null
return false;
}
this.device = device;
+ String[] capabilities = device.capabilities;
+ if (capabilities != null) {
+ this.capabilities = Stream.of(capabilities).filter(Objects::nonNull).collect(Collectors.toSet());
+ }
if (!device.online) {
updateStatus(ThingStatus.OFFLINE);
return false;
@@ -244,8 +310,14 @@ public void handleCommand(ChannelUID channelUID, Command command) {
return;
}
- // Player commands
String channelId = channelUID.getId();
+ for (ChannelHandler channelHandler : channelHandlers) {
+ if (channelHandler.tryHandleCommand(device, connection, channelId, command)) {
+ return;
+ }
+ }
+
+ // Player commands
if (channelId.equals(CHANNEL_PLAYER)) {
if (command == PlayPauseType.PAUSE || command == OnOffType.OFF) {
connection.command(device, "{\"type\":\"PauseCommand\"}");
@@ -356,7 +428,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
+ ",\"contentFocusClientId\":\"Default\"}");
} else {
- Map parameters = new Hashtable();
+ Map parameters = new HashMap<>();
parameters.put("value", volume);
connection.executeSequenceCommand(device, "Alexa.DeviceControls.Volume", parameters);
}
@@ -366,6 +438,14 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
}
+ // equalizer commands
+ if (channelId.equals(CHANNEL_EQUALIZER_BASS) || channelId.equals(CHANNEL_EQUALIZER_MIDRANGE)
+ || channelId.equals(CHANNEL_EQUALIZER_TREBLE)) {
+ if (handleEqualizerCommands(channelId, command, connection, device)) {
+ waitForUpdate = -1;
+ }
+ }
+
// shuffle command
if (channelId.equals(CHANNEL_SHUFFLE)) {
if (command instanceof OnOffType) {
@@ -638,6 +718,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
};
if (command instanceof RefreshType) {
waitForUpdate = 0;
+ account.forceCheckData();
}
if (waitForUpdate == 0) {
doRefresh.run();
@@ -651,6 +732,41 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
}
+ private boolean handleEqualizerCommands(String channelId, Command command, Connection connection, Device device)
+ throws URISyntaxException {
+ if (command instanceof RefreshType) {
+ this.lastKnownEqualizer = null;
+ }
+ if (command instanceof DecimalType) {
+ DecimalType value = (DecimalType) command;
+ if (this.lastKnownEqualizer == null) {
+ updateEqualizerState();
+ }
+ JsonEqualizer lastKnownEqualizer = this.lastKnownEqualizer;
+ if (lastKnownEqualizer != null) {
+ JsonEqualizer newEqualizerSetting = lastKnownEqualizer.createClone();
+ if (channelId.equals(CHANNEL_EQUALIZER_BASS)) {
+ newEqualizerSetting.bass = value.intValue();
+ }
+ if (channelId.equals(CHANNEL_EQUALIZER_MIDRANGE)) {
+ newEqualizerSetting.mid = value.intValue();
+ }
+ if (channelId.equals(CHANNEL_EQUALIZER_TREBLE)) {
+ newEqualizerSetting.treble = value.intValue();
+ }
+ try {
+ connection.SetEqualizer(device, newEqualizerSetting);
+ return true;
+ } catch (HttpException | IOException | ConnectionException e) {
+ logger.debug("Update equalizer failed {}", e);
+ this.lastKnownEqualizer = null;
+ }
+
+ }
+ }
+ return false;
+ }
+
private void startTextToSpeech(Connection connection, Device device, String text)
throws IOException, URISyntaxException {
if (textToSpeechVolume != 0) {
@@ -661,7 +777,12 @@ private void startTextToSpeech(Connection connection, Device device, String text
}
this.ignoreVolumeChange = scheduler.schedule(this::stopIgnoreVolumeChange, 2000, TimeUnit.MILLISECONDS);
}
- connection.textToSpeech(device, text, textToSpeechVolume, lastKnownVolume);
+ if (text.startsWith("") && text.endsWith("")) {
+ String bodyText = text.replaceAll("<[^>]+>", "");
+ connection.sendAnnouncement(device, text, bodyText, null, textToSpeechVolume, lastKnownVolume);
+ } else {
+ connection.textToSpeech(device, text, textToSpeechVolume, lastKnownVolume);
+ }
}
private void stopCurrentNotification() {
@@ -724,7 +845,7 @@ public void updateState(AccountHandler accountHandler, @Nullable Device device,
@Nullable JsonNotificationSound @Nullable [] alarmSounds,
@Nullable List musicProviders) {
try {
- this.logger.debug("Handle updateState {}", this.getThing().getUID().getAsString());
+ this.logger.debug("Handle updateState {}", this.getThing().getUID());
if (deviceNotificationState != null) {
noticationVolumeLevel = deviceNotificationState.volumeLevel;
@@ -742,16 +863,16 @@ public void updateState(AccountHandler accountHandler, @Nullable Device device,
this.musicProviders = musicProviders;
}
if (!setDeviceAndUpdateThingState(accountHandler, device, null)) {
- this.logger.debug("Handle updateState {} aborted: Not online", this.getThing().getUID().getAsString());
+ this.logger.debug("Handle updateState {} aborted: Not online", this.getThing().getUID());
return;
}
if (device == null) {
- this.logger.debug("Handle updateState {} aborted: No device", this.getThing().getUID().getAsString());
+ this.logger.debug("Handle updateState {} aborted: No device", this.getThing().getUID());
return;
}
if (this.disableUpdate) {
- this.logger.debug("Handle updateState {} aborted: Disabled", this.getThing().getUID().getAsString());
+ this.logger.debug("Handle updateState {} aborted: Disabled", this.getThing().getUID());
return;
}
Connection connection = this.findConnection();
@@ -759,6 +880,10 @@ public void updateState(AccountHandler accountHandler, @Nullable Device device,
return;
}
+ if (this.lastKnownEqualizer == null) {
+ updateEqualizerState();
+ }
+
PlayerInfo playerInfo = null;
Provider provider = null;
InfoText infoText = null;
@@ -790,6 +915,13 @@ public void updateState(AccountHandler accountHandler, @Nullable Device device,
if (StringUtils.startsWith(musicProviderId, "TUNEIN")) {
musicProviderId = "TUNEIN";
}
+ if (StringUtils.startsWithIgnoreCase(musicProviderId, "iHeartRadio")) {
+ musicProviderId = "I_HEART_RADIO";
+ }
+ if (StringUtils.containsIgnoreCase(musicProviderId, "Apple")
+ && StringUtils.containsIgnoreCase(musicProviderId, "Music")) {
+ musicProviderId = "APPLE_MUSIC";
+ }
}
}
progress = playerInfo.progress;
@@ -1052,13 +1184,51 @@ public void updateState(AccountHandler accountHandler, @Nullable Device device,
}
} catch (Exception e) {
- this.logger.debug("Handle updateState {} failed: {}", this.getThing().getUID().getAsString(), e);
+ this.logger.debug("Handle updateState {} failed: {}", this.getThing().getUID(), e);
disableUpdate = false;
throw e; // Rethrow same exception
}
}
+ private void updateEqualizerState() {
+ if (!this.capabilities.contains("SOUND_SETTINGS")) {
+ return;
+ }
+
+ Connection connection = findConnection();
+ if (connection == null) {
+ return;
+ }
+ Device device = findDevice();
+ if (device == null) {
+ return;
+ }
+ Integer bass;
+ Integer midrange;
+ Integer treble;
+ try {
+ JsonEqualizer equalizer = connection.getEqualizer(device);
+ bass = equalizer.bass;
+ midrange = equalizer.mid;
+ treble = equalizer.treble;
+ this.lastKnownEqualizer = equalizer;
+ } catch (IOException | URISyntaxException | HttpException | ConnectionException e) {
+ logger.debug("Get equalizer failes {}", e);
+ return;
+ }
+ if (bass != null) {
+ updateState(CHANNEL_EQUALIZER_BASS, new DecimalType(bass));
+ }
+ if (midrange != null) {
+ updateState(CHANNEL_EQUALIZER_MIDRANGE, new DecimalType(midrange));
+ }
+ if (treble != null) {
+ updateState(CHANNEL_EQUALIZER_TREBLE, new DecimalType(treble));
+ }
+
+ }
+
private void updateMediaProgress() {
updateMediaProgress(false);
}
@@ -1092,11 +1262,17 @@ private void updateMediaProgress(boolean updateMediaLength) {
}
public void handlePushActivity(Activity pushActivity) {
+ if ("DISCARDED_NON_DEVICE_DIRECTED_INTENT".equals(pushActivity.activityStatus)) {
+ return;
+ }
Description description = pushActivity.ParseDescription();
if (StringUtils.isEmpty(description.firstUtteranceId)
|| StringUtils.startsWithIgnoreCase(description.firstUtteranceId, "TextClient:")) {
return;
}
+ if (StringUtils.isEmpty(description.firstStreamId)) {
+ return;
+ }
String spokenText = description.summary;
if (spokenText != null && StringUtils.isNotEmpty(spokenText)) {
// remove wake word
@@ -1141,7 +1317,7 @@ public void handlePushCommand(String command, String payload) {
}
break;
case "PUSH_EQUALIZER_STATE_CHANGE":
- // Currently ignored
+ updateEqualizerState();
break;
default:
AccountHandler account = this.account;
@@ -1152,4 +1328,72 @@ public void handlePushCommand(String command, String payload) {
}
}
}
+
+ public void updateNotifications(ZonedDateTime currentTime, ZonedDateTime now,
+ @Nullable JsonCommandPayloadPushNotificationChange pushPayload, JsonNotificationResponse[] notifications) {
+ Device device = this.device;
+ if (device == null) {
+ return;
+ }
+
+ ZonedDateTime nextReminder = null;
+ ZonedDateTime nextAlarm = null;
+ ZonedDateTime nextMusicAlarm = null;
+ ZonedDateTime nextTimer = null;
+ for (JsonNotificationResponse notification : notifications) {
+ if (StringUtils.equals(notification.deviceSerialNumber, device.serialNumber)) {
+ // notification for this device
+ if (StringUtils.equals(notification.status, "ON")) {
+ if ("Reminder".equals(notification.type)) {
+ String offset = ZoneId.systemDefault().getRules().getOffset(Instant.now()).toString();
+ ZonedDateTime alarmTime = ZonedDateTime
+ .parse(notification.originalDate + "T" + notification.originalTime + offset);
+ if (StringUtils.isNotBlank(notification.recurringPattern) && alarmTime.isBefore(now)) {
+ continue; // Ignore recurring entry if alarm time is before now
+ }
+ if (nextReminder == null || alarmTime.isBefore(nextReminder)) {
+ nextReminder = alarmTime;
+ }
+ } else if ("Timer".equals(notification.type)) {
+ // use remaining time
+ ZonedDateTime alarmTime = currentTime.plus(notification.remainingTime, ChronoUnit.MILLIS);
+ if (nextTimer == null || alarmTime.isBefore(nextTimer)) {
+ nextTimer = alarmTime;
+ }
+ } else if ("Alarm".equals(notification.type)) {
+ String offset = ZoneId.systemDefault().getRules().getOffset(Instant.now()).toString();
+ ZonedDateTime alarmTime = ZonedDateTime
+ .parse(notification.originalDate + "T" + notification.originalTime + offset);
+ if (StringUtils.isNotBlank(notification.recurringPattern) && alarmTime.isBefore(now)) {
+ continue; // Ignore recurring entry if alarm time is before now
+ }
+ if (nextAlarm == null || alarmTime.isBefore(nextAlarm)) {
+ nextAlarm = alarmTime;
+ }
+ } else if ("MusicAlarm".equals(notification.type)) {
+ String offset = ZoneId.systemDefault().getRules().getOffset(Instant.now()).toString();
+ ZonedDateTime alarmTime = ZonedDateTime
+ .parse(notification.originalDate + "T" + notification.originalTime + offset);
+ if (StringUtils.isNotBlank(notification.recurringPattern) && alarmTime.isBefore(now)) {
+ continue; // Ignore recurring entry if alarm time is before now
+ }
+ if (nextMusicAlarm == null || alarmTime.isBefore(nextMusicAlarm)) {
+ nextMusicAlarm = alarmTime;
+ }
+ }
+ }
+ }
+ }
+
+ updateState(CHANNEL_NEXT_REMINDER, nextReminder == null ? UnDefType.UNDEF : new DateTimeType(nextReminder));
+ updateState(CHANNEL_NEXT_ALARM, nextAlarm == null ? UnDefType.UNDEF : new DateTimeType(nextAlarm));
+ updateState(CHANNEL_NEXT_MUSIC_ALARM,
+ nextMusicAlarm == null ? UnDefType.UNDEF : new DateTimeType(nextMusicAlarm));
+ updateState(CHANNEL_NEXT_TIMER, nextTimer == null ? UnDefType.UNDEF : new DateTimeType(nextTimer));
+ }
+
+ @Override
+ public void updateChannelState(String channelId, State state) {
+ updateState(channelId, state);
+ }
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/SmartHomeDeviceHandler.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/SmartHomeDeviceHandler.java
index 4bb024a5bbda3..087b1579135a2 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/SmartHomeDeviceHandler.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/handler/SmartHomeDeviceHandler.java
@@ -15,6 +15,7 @@
import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.*;
import java.io.IOException;
+import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
@@ -24,6 +25,7 @@
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.library.types.StringType;
@@ -42,9 +44,7 @@
import org.slf4j.LoggerFactory;
/**
- *
* @author Lukas Knoeller
- *
*/
public class SmartHomeDeviceHandler extends BaseThingHandler {
@@ -122,7 +122,12 @@ public void run() {
}
}
};
- updateStateJob = scheduler.scheduleWithFixedDelay(runnable, 0, 30, TimeUnit.SECONDS);
+
+ Configuration config = accountHandler.getThing().getConfiguration();
+
+ updateStateJob = scheduler.scheduleWithFixedDelay(runnable, 0,
+ ((BigDecimal) config.getProperties().get("pollingIntervalSmartHome")).longValue(),
+ TimeUnit.SECONDS);
}
}
@@ -142,15 +147,11 @@ public void handleCommand(ChannelUID channelUID, Command command) {
if (accountHandler == null) {
return;
}
- int waitForUpdate = -1;
try {
Map props = this.thing.getProperties();
String entityId = props.get(DEVICE_PROPERTY_LIGHT_ENTITY_ID);
String channelId = channelUID.getId();
- if (command instanceof RefreshType) {
- waitForUpdate = 0;
- }
if (channelId.equals(CHANNEL_LIGHT_STATE)) {
if (command instanceof OnOffType) {
connection = accountHandler.findConnection();
@@ -170,7 +171,6 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
}
}
- waitForUpdate = 1;
}
}
if (channelId.equals(CHANNEL_LIGHT_COLOR)) {
@@ -218,18 +218,9 @@ public void handleCommand(ChannelUID channelUID, Command command) {
((PercentType) command).floatValue() / 100);
}
}
- waitForUpdate = 1;
}
}
- if (waitForUpdate < 0) {
- return;
- }
-
- if (command instanceof RefreshType) {
- waitForUpdate = 0;
- }
-
} catch (Exception e) {
logger.warn("Handle command failed {}", e);
}
@@ -273,6 +264,16 @@ public boolean initialize(AccountHandler handler) {
}
public List updateSmartHomeDevices() {
+
+ /*
+ * Configuration config = accountHandler.getThing().getConfiguration();
+ * boolean discoverSmartHome = (boolean) config.getProperties().get("discoverSmartHome");
+ *
+ * if (discoverSmartHome == false) {
+ * return new ArrayList();
+ * }
+ */
+
Connection currentConnection = connection;
if (currentConnection == null) {
return new ArrayList();
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonActivities.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonActivities.java
index 910b1f347cf54..b09660af70a1e 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonActivities.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonActivities.java
@@ -29,7 +29,7 @@ public class JsonActivities {
public @Nullable Activity @Nullable [] activities;
- public class Activity {
+ public static class Activity {
public @Nullable String activityStatus;
public @Nullable Long creationTimestamp;
public @Nullable String description;
@@ -45,14 +45,14 @@ public class Activity {
public @Nullable String utteranceId;
public @Nullable Long version;
- public class SourceDeviceId {
+ public static class SourceDeviceId {
public @Nullable String deviceAccountId;
public @Nullable String deviceType;
public @Nullable String serialNumber;
}
- public class Description {
+ public static class Description {
public @Nullable String summary;
public @Nullable String firstUtteranceId;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementContent.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementContent.java
index 1ce05d0cbfa52..ce2296773e417 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementContent.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementContent.java
@@ -24,17 +24,17 @@
@NonNullByDefault
public class JsonAnnouncementContent {
- public @Nullable String locale;
+ public String locale = "";
public final Display display = new Display();
public final Speak speak = new Speak();
- public class Display {
+ public static class Display {
public @Nullable String title;
public @Nullable String body;
}
- public class Speak {
+ public static class Speak {
public String type = "text";
public @Nullable String value;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementTarget.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementTarget.java
index fcb8e884541f2..6e99bec84f1c6 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementTarget.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAnnouncementTarget.java
@@ -26,7 +26,7 @@ public class JsonAnnouncementTarget {
public @Nullable String customerId;
public @Nullable TargetDevice @Nullable [] devices;
- public class TargetDevice {
+ public static class TargetDevice {
public @Nullable String deviceSerialNumber;
public @Nullable String deviceTypeId;
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAscendingAlarm.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAscendingAlarm.java
index 68ebe7d70d936..95c4d6c81a8a5 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAscendingAlarm.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAscendingAlarm.java
@@ -25,7 +25,7 @@ public class JsonAscendingAlarm {
public @Nullable AscendingAlarmModel @Nullable [] ascendingAlarmModelList;
- public class AscendingAlarmModel {
+ public static class AscendingAlarmModel {
public @Nullable Boolean ascendingAlarmEnabled;
public @Nullable String deviceSerialNumber;
public @Nullable String deviceType;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAutomation.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAutomation.java
index 9f9b7cf99faf3..d3be585e7c7f4 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAutomation.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonAutomation.java
@@ -32,13 +32,13 @@ public class JsonAutomation {
public long creationTimeEpochMillis;
public long lastUpdatedTimeEpochMillis;
- public class Trigger {
+ public static class Trigger {
public @Nullable Payload payload;
public @Nullable String id;
public @Nullable String type;
}
- public class Payload {
+ public static class Payload {
public @Nullable String customerId;
public @Nullable String utterance;
public @Nullable String locale;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBluetoothStates.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBluetoothStates.java
index 5361887d5afb2..4d2ba0adb07cc 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBluetoothStates.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBluetoothStates.java
@@ -44,7 +44,7 @@ public class JsonBluetoothStates {
public @Nullable BluetoothState @Nullable [] bluetoothStates;
- public class PairedDevice {
+ public static class PairedDevice {
public @Nullable String address;
public boolean connected;
public @Nullable String deviceClass;
@@ -53,7 +53,7 @@ public class PairedDevice {
}
- public class BluetoothState {
+ public static class BluetoothState {
public @Nullable String deviceSerialNumber;
public @Nullable String deviceType;
public @Nullable String friendlyName;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBootstrapResult.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBootstrapResult.java
new file mode 100644
index 0000000000000..dffce100b83b8
--- /dev/null
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonBootstrapResult.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link JsonBluetoothStates} encapsulate the bootstrap result
+ *
+ * @author Michael Geramb - Initial contribution
+ */
+@NonNullByDefault
+public class JsonBootstrapResult {
+
+ public @Nullable Authentication authentication;
+
+ public static class Authentication {
+ public boolean authenticated;
+ public @Nullable Boolean canAccessPrimeMusicContent;
+ public @Nullable String customerEmail;
+ public @Nullable String customerId;
+ public @Nullable String customerName;
+ }
+}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColorTemperature.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColorTemperature.java
index 65ac12e075889..bdf8f94f004dd 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColorTemperature.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColorTemperature.java
@@ -1,8 +1,23 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+/**
+ * @author Lukas Knoeller
+ */
@NonNullByDefault
public class JsonColorTemperature {
public @Nullable String temperatureName;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColors.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColors.java
index 96d606174758f..129fe2988f37f 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColors.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonColors.java
@@ -1,8 +1,23 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+/**
+ * @author Lukas Knoeller
+ */
@NonNullByDefault
public class JsonColors {
public @Nullable String colorName;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushActivity.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushActivity.java
index 9fc7800324326..c53128cf0966a 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushActivity.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushActivity.java
@@ -28,7 +28,7 @@ public class JsonCommandPayloadPushActivity {
public @Nullable Key key;
- public class Key {
+ public static class Key {
public @Nullable String entryId;
public @Nullable String registeredUserId;
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushDevice.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushDevice.java
index f606635ab5e22..c7b42709229ec 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushDevice.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonCommandPayloadPushDevice.java
@@ -25,7 +25,7 @@ public class JsonCommandPayloadPushDevice {
public @Nullable DopplerId dopplerId;
- public class DopplerId {
+ public static class DopplerId {
public @Nullable String deviceSerialNumber;
public @Nullable String deviceType;
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDeviceNotificationState.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDeviceNotificationState.java
index 2f0a6ccb7701b..596c172a2048b 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDeviceNotificationState.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDeviceNotificationState.java
@@ -25,7 +25,7 @@ public class JsonDeviceNotificationState {
public @Nullable DeviceNotificationState @Nullable [] deviceNotificationStates;
- public class DeviceNotificationState {
+ public static class DeviceNotificationState {
public @Nullable String deviceSerialNumber;
public @Nullable String deviceType;
public @Nullable String softwareVersion;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDevices.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDevices.java
index 16f00449aac06..2ff3a02ad65d1 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDevices.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonDevices.java
@@ -23,7 +23,7 @@
@NonNullByDefault
public class JsonDevices {
- public class Device {
+ public static class Device {
public @Nullable String accountName;
public @Nullable String serialNumber;
public @Nullable String deviceOwnerCustomerId;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonExchangeTokenResponse.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonExchangeTokenResponse.java
index e95a1df7a873e..48807bea68910 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonExchangeTokenResponse.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonExchangeTokenResponse.java
@@ -26,15 +26,15 @@
public class JsonExchangeTokenResponse {
public @Nullable Response response;
- public class Response {
+ public static class Response {
public @Nullable Tokens tokens;
}
- public class Tokens {
+ public static class Tokens {
public @Nullable Map cookies;
}
- public class Cookie {
+ public static class Cookie {
public @Nullable String Path;
public @Nullable Boolean Secure;
public @Nullable String Value;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonMediaState.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonMediaState.java
index 69033b938c5e5..0d23fb92d1995 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonMediaState.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonMediaState.java
@@ -47,7 +47,7 @@ public class JsonMediaState {
// public long timeLastShuffled; parsing fails with some values, so do not use it
public int volume;
- public class QueueEntry {
+ public static class QueueEntry {
public @Nullable String album;
public @Nullable String albumAsin;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonNotificationResponse.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonNotificationResponse.java
index 48f1c1915e91c..e339d176c5bad 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonNotificationResponse.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonNotificationResponse.java
@@ -30,6 +30,10 @@ public class JsonNotificationResponse {
public @Nullable String id;
public @Nullable String status;
public @Nullable String type;
+ public long remainingTime;
+ public @Nullable String recurringPattern;
+ public @Nullable String originalDate;
+ public @Nullable String originalTime;
}
/*
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlayerState.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlayerState.java
index 79e4f508b6c97..f3013b518cc13 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlayerState.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlayerState.java
@@ -24,7 +24,7 @@
public class JsonPlayerState {
public @Nullable PlayerInfo playerInfo;
- public class PlayerInfo {
+ public static class PlayerInfo {
public @Nullable String state;
public @Nullable InfoText infoText;
public @Nullable InfoText miniInfoText;
@@ -37,7 +37,7 @@ public class PlayerInfo {
public @Nullable Progress progress;
- public class InfoText {
+ public static class InfoText {
public boolean multiLineMode;
public @Nullable String subText1;
public @Nullable String subText2;
@@ -45,24 +45,24 @@ public class InfoText {
}
- public class Provider {
+ public static class Provider {
public @Nullable String providerDisplayName;
public @Nullable String providerName;
}
- public class Volume {
+ public static class Volume {
public boolean muted;
public int volume;
}
- public class MainArt {
+ public static class MainArt {
public @Nullable String altText;
public @Nullable String artType;
public @Nullable String contentType;
public @Nullable String url;
}
- public class Progress {
+ public static class Progress {
public @Nullable Boolean allowScrubbing;
public @Nullable Object locationInfo;
public @Nullable Long mediaLength;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlaylists.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlaylists.java
index 1e8b8bcdcdeee..d079c686df8c5 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlaylists.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonPlaylists.java
@@ -27,7 +27,7 @@ public class JsonPlaylists {
public @Nullable Map playlists;
- public class PlayList {
+ public static class PlayList {
public @Nullable String playlistId;
public @Nullable String title;
public int trackCount;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppRequest.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppRequest.java
index 54b242a0cf0f1..8b2e2762a22d5 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppRequest.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppRequest.java
@@ -38,7 +38,7 @@ public JsonRegisterAppRequest(String serial, String access_token, String frc, Js
public UserContextMap user_context_map = new UserContextMap();
public String[] requested_token_type = { "bearer", "mac_dms", "website_cookies" };
- public class Cookies {
+ public static class Cookies {
@Nullable
public JsonWebSiteCookie @Nullable [] website_cookies;
@Nullable
@@ -46,7 +46,7 @@ public class Cookies {
}
- public class RegistrationData {
+ public static class RegistrationData {
public String domain = "Device";
public String app_version = "2.2.223830.0";
public String device_type = "A2IVLV5VM2W81";
@@ -59,12 +59,12 @@ public class RegistrationData {
public String software_version = "1";
}
- public class AuthData {
+ public static class AuthData {
@Nullable
public String access_token;
}
- public class UserContextMap {
+ public static class UserContextMap {
public String frc = "";
}
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppResponse.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppResponse.java
index 9c6539c066aca..b2a22649f54ea 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppResponse.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonRegisterAppResponse.java
@@ -29,19 +29,21 @@ public class JsonRegisterAppResponse {
@Nullable
public String request_id;
- public class Response {
+ public static class Response {
@Nullable
public Success success;
}
- public class Success {
+ public static class Success {
@Nullable
public Extensions extensions;
@Nullable
public Tokens tokens;
+ @Nullable
+ public String customer_id;
}
- public class Extensions {
+ public static class Extensions {
@Nullable
public DeviceInfo device_info;
@Nullable
@@ -50,7 +52,7 @@ public class Extensions {
public String customer_id;
}
- public class DeviceInfo {
+ public static class DeviceInfo {
@Nullable
public String device_name;
@Nullable
@@ -60,7 +62,7 @@ public class DeviceInfo {
}
- public class CustomerInfo {
+ public static class CustomerInfo {
@Nullable
public String account_pool;
@Nullable
@@ -73,7 +75,7 @@ public class CustomerInfo {
public String given_name;
}
- public class Tokens {
+ public static class Tokens {
@Nullable
public Object website_cookies;
@Nullable
@@ -82,14 +84,14 @@ public class Tokens {
public Bearer bearer;
}
- public class MacDms {
+ public static class MacDms {
@Nullable
public String device_private_key;
@Nullable
public String adp_token;
}
- public class Bearer {
+ public static class Bearer {
@Nullable
public String access_token;
@Nullable
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDeviceAlias.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDeviceAlias.java
index 65cafc30fb12b..81d62666ea991 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDeviceAlias.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDeviceAlias.java
@@ -1,10 +1,22 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
- * @author Lukas Knoeller - Initial contribution
+ * @author Lukas Knoeller
*/
@NonNullByDefault
public class JsonSmartHomeDeviceAlias {
@@ -15,4 +27,7 @@ public JsonSmartHomeDeviceAlias(String friendlyName, Boolean enabled) {
this.friendlyName = friendlyName;
this.enabled = enabled;
}
+
+ public JsonSmartHomeDeviceAlias() {
+ }
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDevices.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDevices.java
index d34f891edc678..441c4deaeb121 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDevices.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeDevices.java
@@ -16,12 +16,12 @@
import org.eclipse.jdt.annotation.Nullable;
/**
- * @author Lukas Knoeller - Contributor
+ * @author Lukas Knoeller
*/
@NonNullByDefault
public class JsonSmartHomeDevices {
- public class SmartHomeDevice {
+ public static class SmartHomeDevice {
public @Nullable String applianceId;
public @Nullable String manufacturerName;
public @Nullable String friendlyDescription;
@@ -36,7 +36,7 @@ public class SmartHomeDevice {
public boolean colorTemperature = false;
public SmartHomeDevice(String applianceId, String manufacturerName, String friendlyDescription,
- String friendlyName, String reachability, String entityId, JsonSmartHomeDeviceAlias[] alias,
+ @Nullable String friendlyName, String reachability, String entityId, JsonSmartHomeDeviceAlias[] alias,
SmartHomeDevice[] groupDevices) {
this.applianceId = applianceId;
this.manufacturerName = manufacturerName;
@@ -47,6 +47,9 @@ public SmartHomeDevice(String applianceId, String manufacturerName, String frien
this.alias = alias;
this.groupDevices = groupDevices;
}
+
+ public SmartHomeDevice() {
+ }
}
public @Nullable SmartHomeDevice @Nullable [] smarthomeDevices;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroupIdentifiers.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroupIdentifiers.java
index a20d85355bbae..bd766a06c3b0a 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroupIdentifiers.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroupIdentifiers.java
@@ -1,12 +1,27 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+/**
+ * @author Lukas Knoeller
+ */
@NonNullByDefault
public class JsonSmartHomeGroupIdentifiers {
- public class SmartHomeGroupIdentifier {
+ public static class SmartHomeGroupIdentifier {
public @Nullable String value;
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroups.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroups.java
index ade1d91152892..3f54db9051ecf 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroups.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonSmartHomeGroups.java
@@ -1,13 +1,28 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonSmartHomeGroupIdentifiers.SmartHomeGroupIdentifier;
+/**
+ * @author Lukas Knoeller
+ */
@NonNullByDefault
public class JsonSmartHomeGroups {
- public class SmartHomeGroup {
+ public static class SmartHomeGroup {
public @Nullable String applianceGroupName;
public @Nullable Boolean isSpace;
public @Nullable Boolean space;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonWakeWords.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonWakeWords.java
index c8af33b41867c..c59a5bca171ab 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonWakeWords.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/jsons/JsonWakeWords.java
@@ -24,7 +24,7 @@
public class JsonWakeWords {
public @Nullable WakeWord @Nullable [] wakeWords;
- public class WakeWord {
+ public static class WakeWord {
public @Nullable Boolean active;
public @Nullable String deviceSerialNumber;
public @Nullable String deviceType;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionProvider.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionProvider.java
index dcd9c3acc966d..bf0b21394e49e 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionProvider.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionProvider.java
@@ -123,8 +123,9 @@ protected void unsetThingRegistry(ThingRegistry thingRegistry) {
if (device == null) {
continue;
}
- if (device.address != null && device.friendlyName != null) {
- options.add(new StateOption(device.address, device.friendlyName));
+ final String value = device.address;
+ if (value != null && device.friendlyName != null) {
+ options.add(new StateOption(value, device.friendlyName));
}
}
StateDescription result = new StateDescription(originalStateDescription.getMinimum(),
@@ -151,8 +152,8 @@ protected void unsetThingRegistry(ThingRegistry thingRegistry) {
for (PlayList[] innerLists : playlistMap.values()) {
if (innerLists != null && innerLists.length > 0) {
PlayList playList = innerLists[0];
- if (playList.playlistId != null && playList.title != null) {
- final String value = playList.playlistId;
+ final String value = playList.playlistId;
+ if (value != null && playList.title != null) {
options.add(new StateOption(value,
String.format("%s (%d)", playList.title, playList.trackCount)));
}
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionSmartHome.java b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionSmartHome.java
index a9e6d9d450cde..63cd4b88cd3b8 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionSmartHome.java
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/java/org/openhab/binding/amazonechocontrol/internal/statedescription/AmazonEchoDynamicStateDescriptionSmartHome.java
@@ -1,3 +1,15 @@
+/**
+ * Copyright (c) 2010-2019 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.amazonechocontrol.internal.statedescription;
import static org.openhab.binding.amazonechocontrol.internal.AmazonEchoControlBindingConstants.CHANNEL_TYPE_LIGHT_COLOR;
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/binding/binding.xml b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/binding/binding.xml
index b6c76c2bd9f9a..27d95905a731b 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/binding/binding.xml
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/binding/binding.xml
@@ -4,6 +4,6 @@
Amazon Echo Control BindingBinding to control Amazon Echo devices (Alexa). This binding enables openHAB to control the volume, playing state, bluetooth connection of your amazon echo devices or allow to use it as TTS device.
- Michael Geramb
+ Michael Geramb, Lukas Knoeller
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/i18n/amazonechocontrol_de.properties b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/i18n/amazonechocontrol_de.properties
index e3b6d0b14de0a..cb836e9130991 100755
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/i18n/amazonechocontrol_de.properties
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/i18n/amazonechocontrol_de.properties
@@ -6,6 +6,7 @@ binding.amazonechocontrol.description = Binding zum Steuern von Amazon Echo (Ale
thing-type.amazonechocontrol.account.label = Amazon Konto
thing-type.amazonechocontrol.account.description = Amazon Konto bei dem die Amazon Echo Geräte registriert sind.
+thing-type.amazonechocontrol.account.config-description.pollingIntervalSmartHome.description = Definiert die Sekundenanzahl, wie häufig OpenHab den Status der Alexa-Lampen abfragt.
thing-type.amazonechocontrol.echo.label = Amazon Echo
thing-type.amazonechocontrol.echo.description = Amazon Echo Gerät (Amazon Echo, Amazon Echo Dot, Amazon Echo Plus...)
@@ -34,6 +35,12 @@ thing-type.config.wha.echoshow.serialNumber.description = Die Seriennummer des G
thing-type.amazonechocontrol.flashbriefingprofile.label = Tägliche Zusammenfassungsprofile
thing-type.amazonechocontrol.flashbriefingprofile.description = Speichert und läd eine Tägliches Zusammenfassungskonfiguration
+thing-type.amazonechocontrol.light.label = Amazon Echo Licht
+thing-type.amazonechocontrol.light.description = Eine mit deinem Amazon Account verbundene Lampe
+
+thing-type.amazonechocontrol.lightGroup.label = Amazon Echo Lichtergruppe
+thing-type.amazonechocontrol.lightGroup.description = Eine in deinem Amazon Account angelegte Gruppe von Lichtern
+
# channel types
channel-type.amazonechocontrol.bluetoothDeviceName.label = Bluetooth Gerät
channel-type.amazonechocontrol.bluetoothDeviceName.description = Verbundenes Bluetoothgerät
@@ -56,6 +63,9 @@ channel-type.amazonechocontrol.providerDisplayName.description = Name des Musika
channel-type.amazonechocontrol.bluetoothMAC.label = Bluetooth Verbindung
channel-type.amazonechocontrol.bluetoothMAC.description = MAC-Adresse des verbundenen Bluetoothgerätes
+channel-type.amazonechocontrol.announcement.label = Ankündigung
+channel-type.amazonechocontrol.announcement.description = Zeigt die Ankündungsnachricht am Display (Nur schreiben). In der Binding Beschreibung ist im Tutorials Abschnitt eine Erklärung wie der Title gesetzt und der Sound deaktiviert wird.
+
channel-type.amazonechocontrol.textToSpeech.label = Sprich
channel-type.amazonechocontrol.textToSpeech.description = Spricht den Text (Nur schreiben). Es kann reiner Text oder SSML verwendet werden: e.g. Ich will dir ein Geheimnis erzählen.Ich bin nicht wirklich ein Mensch.
@@ -163,3 +173,35 @@ channel-type.amazonechocontrol.playCommand.option.GoodMorning = Guten Morgen
channel-type.amazonechocontrol.playCommand.option.SingASong = Lied
channel-type.amazonechocontrol.playCommand.option.TellStory = Geschichte
channel-type.amazonechocontrol.playCommand.option.TellStory = Zusammenfassung
+
+channel-type-amazonechocontrol.lightState.label = Status der Lampe
+channel-type-amazonechocontrol.lightState.description = Zustand (Ein/Aus) der Lampe
+
+channel-type-amazonechocontrol.lightColor.label = Farbe deiner Lampe
+channel-type-amazonechocontrol.lightColor.description = Farbe der smarten Lampe
+channel-type-amazonechocontrol.lightColor.option.red = Rot
+channel-type-amazonechocontrol.lightColor.option.crimson = Purpur
+channel-type-amazonechocontrol.lightColor.option.salmon = Lachs
+channel-type-amazonechocontrol.lightColor.option.orange = Orange
+channel-type-amazonechocontrol.lightColor.option.gold = Gold
+channel-type-amazonechocontrol.lightColor.option.yellow = Gelb
+channel-type-amazonechocontrol.lightColor.option.green = Grün
+channel-type-amazonechocontrol.lightColor.option.turquoise = Türkis
+channel-type-amazonechocontrol.lightColor.option.cyan = Cyan
+channel-type-amazonechocontrol.lightColor.option.sky_blue = Himmelblau
+channel-type-amazonechocontrol.lightColor.option.blue = Blau
+channel-type-amazonechocontrol.lightColor.option.purple = Lila
+channel-type-amazonechocontrol.lightColor.option.magenta = Magenta
+channel-type-amazonechocontrol.lightColor.option.pink = Pink
+channel-type-amazonechocontrol.lightColor.option.lavender = Lavendel
+
+channel-type-amazonechocontrol.whiteTemperature.label = Weißton der Lampe
+channel-type-amazonechocontrol.whiteTemperature.description = Weißtemperatur der Lampe am Amazon Echo
+channel-type-amazonechocontrol.whiteTemperature.option.warm_white = Warmweiß
+channel-type-amazonechocontrol.whiteTemperature.option.soft_white = Sanftes Weiß
+channel-type-amazonechocontrol.whiteTemperature.option.white = Weiß
+channel-type-amazonechocontrol.whiteTemperature.option.daylight_white = Tageslicht
+channel-type-amazonechocontrol.whiteTemperature.option.cool_white = Kaltweiß
+
+channel-type-amazonechocontrol.lightBrightness.label = Helligkeit
+channel-type-amazonechocontrol.lightBrightness.description = Helligkeit der Lampe
diff --git a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/thing/thing-types.xml
index 54b7acb0f7a42..e5b9607d00336 100644
--- a/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.amazonechocontrol/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -1,11 +1,18 @@
-Amazon Account where the amazon echo devices are registered.
+
+
+ 20
+ Defines the time in seconds for openhab to pull the state of the bulbs.
+
+ true
+ Defines if openhab should discover your bulbs connected to the Amazon Echo.
+
@@ -27,14 +34,17 @@
-
+
-
+
-
+
@@ -47,7 +57,8 @@
-
+
@@ -80,15 +91,19 @@
-
+
-
+
-
+
+
@@ -100,7 +115,8 @@
-
+
@@ -133,15 +149,19 @@
-
+
-
+
-
+
+
@@ -153,7 +173,8 @@
-
+
@@ -182,11 +203,13 @@
-
+
-
+ serialNumber
@@ -210,6 +233,32 @@
+
+
+
+
+
+ Represents a light in your amazon account
+
+
+
+
+
+
+
+
+
+
+
+
+ Group of light bulbs in your amazon account
+
+
+
+
+
+
+ Switch
@@ -267,7 +316,8 @@
Amazon Music play list id (Write only, no current state)
-
+ StringId of the playlist which was started with openHAB
@@ -365,6 +415,11 @@
Voice command as text. E.g. 'Yesterday from the Beatles' (Write only)
+
+ String
+
+ Display the announcement message on the display (Write only). See in the tutorial section of the binding description to learn how it's possible to set the title and turn off the sound.
+ String
@@ -426,6 +481,7 @@
Ascending alarm up to the configured volume
+
DateTime
@@ -450,4 +506,52 @@
Next timer
+
+ Switch
+
+ State (ON/OFF) of a light
+
+
+ String
+
+ The color of a smart bulb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ String
+
+ The temperature of white
+
+
+
+
+
+
+
+
+
+
+
+ Dimmer
+
+ The brightness of the light
+
diff --git a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Sun.java b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Sun.java
index 891c5c4b9b824..708896475c03e 100644
--- a/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Sun.java
+++ b/bundles/org.openhab.binding.astro/src/main/java/org/openhab/binding/astro/internal/model/Sun.java
@@ -193,6 +193,22 @@ public void setNight(Range night) {
ranges.put(SunPhaseName.NIGHT, night);
}
+ /**
+ * Sets the rise range.
+ */
+ public void setRise(Range rise) {
+ super.setRise(rise);
+ ranges.put(SunPhaseName.SUN_RISE, rise);
+ }
+
+ /**
+ * Sets the set range.
+ */
+ public void setSet(Range set) {
+ super.setSet(set);
+ ranges.put(SunPhaseName.SUN_SET, set);
+ }
+
/**
* Returns the sun position.
*/
diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java
new file mode 100644
index 0000000000000..c93c38be7ffa8
--- /dev/null
+++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/calc/SunCalcTest.java
@@ -0,0 +1,282 @@
+/**
+ * Copyright (c) 2010-2019 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.astro.internal.calc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.openhab.binding.astro.internal.model.Sun;
+import org.openhab.binding.astro.internal.model.SunPhaseName;
+
+/***
+ * Specific unit tests to check if {@link SunCalc} generates correct data for
+ * Amsterdam city on 27 February 2019. In particular the following cases are
+ * covered:
+ *
+ *
checks if generated data are the same (with some accuracy) as produced by
+ * haevens-above.com
+ *
checks if the generated {@link Sun#getAllRanges()} are consistent with
+ * each other
+ *
+ *
+ * @author Witold Markowski
+ * @see [astro]
+ * Sun Phase returns UNDEF
+ * @see Heavens Above Sun
+ */
+public class SunCalcTest {
+
+ private final static Calendar FEB_27_2019 = new GregorianCalendar(2019, Calendar.FEBRUARY, 27);
+ private final static double AMSTERDAM_LATITUDE = 52.367607;
+ private final static double AMSTERDAM_LONGITUDE = 4.8978293;
+ private final static double AMSTERDAM_ALTITUDE = 0.0;
+ private final static int ACCURACY_IN_MILLIS = 3 * 60 * 1000;
+
+ private SunCalc sunCalc;
+
+ @Before
+ public void init() {
+ FEB_27_2019.setTimeZone(TimeZone.getTimeZone("Europe/Amsterdam"));
+ sunCalc = new SunCalc();
+ }
+
+ @Test
+ public void testGetSunInfoForOldDate() {
+ Calendar calendar = new GregorianCalendar(2019, Calendar.FEBRUARY, 27);
+ TimeZone.getAvailableIDs();
+ calendar.setTimeZone(TimeZone.getTimeZone("Europe/Amsterdam"));
+
+ Sun sun = sunCalc.getSunInfo(calendar, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertNotNull(sun.getNight());
+
+ assertNotNull(sun.getAstroDawn());
+ assertNotNull(sun.getNauticDawn());
+ assertNotNull(sun.getCivilDawn());
+
+ assertNotNull(sun.getRise());
+
+ assertNotNull(sun.getDaylight());
+ assertNotNull(sun.getNoon());
+ assertNotNull(sun.getSet());
+
+ assertNotNull(sun.getCivilDusk());
+ assertNotNull(sun.getNauticDusk());
+ assertNotNull(sun.getAstroDusk());
+ assertNotNull(sun.getNight());
+
+ assertNotNull(sun.getMorningNight());
+ assertNotNull(sun.getEveningNight());
+
+ // for an old date the phase is always null
+ assertNull(sun.getPhase().getName());
+ }
+
+ @Test
+ public void testGetSunInfoForAstronomicalDawnAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 05:39 till 06:18
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 5, 39).getTimeInMillis(),
+ sun.getAstroDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 6, 18).getTimeInMillis(),
+ sun.getAstroDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForNauticDawnAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 06:18 till 06:58
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 6, 18).getTimeInMillis(),
+ sun.getNauticDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 6, 58).getTimeInMillis(),
+ sun.getNauticDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForCivilDawnAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 06:58 till 07:32
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 6, 58).getTimeInMillis(),
+ sun.getCivilDawn().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 7, 32).getTimeInMillis(),
+ sun.getCivilDawn().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForRiseAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 07:32
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 7, 32).getTimeInMillis(),
+ sun.getRise().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForSunNoonAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 12:54
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 12, 54).getTimeInMillis(),
+ sun.getNoon().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForSetAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 18:15
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 18, 15).getTimeInMillis(),
+ sun.getSet().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForCivilDuskAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 18:15 till 18:50
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 18, 15).getTimeInMillis(),
+ sun.getCivilDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 18, 50).getTimeInMillis(),
+ sun.getCivilDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForNauticDuskAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 18:50 till 19:29
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 18, 50).getTimeInMillis(),
+ sun.getNauticDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 19, 29).getTimeInMillis(),
+ sun.getNauticDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ public void testGetSunInfoForAstronomicalDuskAccuracy() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ // expected result from haevens-above.com is 27 Feb 2019 19:29 till 20:09
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 19, 29).getTimeInMillis(),
+ sun.getAstroDusk().getStart().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ assertEquals(new GregorianCalendar(2019, Calendar.FEBRUARY, 27, 20, 9).getTimeInMillis(),
+ sun.getAstroDusk().getEnd().getTimeInMillis(), ACCURACY_IN_MILLIS);
+ }
+
+ @Test
+ @Ignore
+ public void testRangesForCoherenceBetweenNightEndAndAstroDawnStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.NIGHT).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenMorningNightEndAndAstroDawnStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.MORNING_NIGHT).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenAstroDownEndAndNauticDawnStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DAWN).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.NAUTIC_DAWN).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenNauticDawnEndAndCivilDawnStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.NAUTIC_DAWN).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.CIVIL_DAWN).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenCivilDawnEndAndSunRiseStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.CIVIL_DAWN).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.SUN_RISE).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenSunRiseEndAndDaylightStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.SUN_RISE).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.DAYLIGHT).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenDaylightEndAndSunSetStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.DAYLIGHT).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.SUN_SET).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenSunSetEndAndCivilDuskStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.SUN_SET).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.CIVIL_DUSK).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenCivilDuskEndAndNauticDuskStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.CIVIL_DUSK).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.NAUTIC_DUSK).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenNauticDuskEndAndAstroDuskStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.NAUTIC_DUSK).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenAstroDuskEndAndNightStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.NIGHT).getStart());
+ }
+
+ @Test
+ public void testRangesForCoherenceBetweenAstroDuskEndAndEveningNightStart() {
+ Sun sun = sunCalc.getSunInfo(FEB_27_2019, AMSTERDAM_LATITUDE, AMSTERDAM_LONGITUDE, AMSTERDAM_ALTITUDE);
+
+ assertEquals(sun.getAllRanges().get(SunPhaseName.ASTRO_DUSK).getEnd(),
+ sun.getAllRanges().get(SunPhaseName.EVENING_NIGHT).getStart());
+ }
+}
diff --git a/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/model/SunTest.java b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/model/SunTest.java
new file mode 100644
index 0000000000000..c966029d7c448
--- /dev/null
+++ b/bundles/org.openhab.binding.astro/src/test/java/org/openhab/binding/astro/internal/model/SunTest.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2010-2019 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.astro.internal.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.types.UnDefType;
+import org.junit.Before;
+import org.junit.Test;
+import org.openhab.binding.astro.internal.util.PropertyUtils;
+
+/***
+ * A set of standard unit test of {@link Sun} class. In particular it checks if
+ * {@link Sun#getAllRanges()} contains a correct {@link SunPhaseName}.
+ *
+ * @author Witold Markowski
+ * @see [astro]
+ * Sun Phase returns UNDEF
+ */
+public class SunTest {
+
+ private Sun sun;
+
+ @Before
+ public void init() {
+ sun = new Sun();
+ }
+
+ @Test
+ public void testConstructor() throws Exception {
+ assertNotNull(sun.getPhase());
+ assertEquals(UnDefType.UNDEF, PropertyUtils.getState(new ChannelUID("astro:sun:home:phase#name"), null, sun));
+ }
+
+ @Test
+ public void testGetStateWhenNullPhaseName() throws Exception {
+ sun.getPhase().setName(null);
+
+ assertEquals(UnDefType.UNDEF, PropertyUtils.getState(new ChannelUID("astro:sun:home:phase#name"), null, sun));
+ }
+
+ @Test
+ public void testGetStateWhenNotNullPhaseName() throws Exception {
+ sun.getPhase().setName(SunPhaseName.DAYLIGHT);
+
+ assertEquals(new StringType("DAYLIGHT"),
+ PropertyUtils.getState(new ChannelUID("astro:sun:home:phase#name"), null, sun));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetStateWhenNullPhase() throws Exception {
+ sun.setPhase(null);
+
+ assertNull(sun.getPhase());
+ assertEquals(UnDefType.UNDEF, PropertyUtils.getState(new ChannelUID("astro:sun:home:phase#name"), null, sun));
+ }
+
+ @Test
+ public void testGetAllRangesForNight() {
+ sun.setNight(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.NIGHT));
+ }
+
+ @Test
+ public void testGetAllRangesForMorningNight() {
+ sun.setMorningNight(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.MORNING_NIGHT));
+ }
+
+ @Test
+ public void testGetAllRangesForAstroDawn() {
+ sun.setAstroDawn(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.ASTRO_DAWN));
+ }
+
+ @Test
+ public void testGetAllRangesForNauticDawn() {
+ sun.setNauticDawn(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.NAUTIC_DAWN));
+ }
+
+ @Test
+ public void testGetAllRangesForCivilDawn() {
+ sun.setCivilDawn(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.CIVIL_DAWN));
+ }
+
+ @Test
+ public void testGetAllRangesForRise() {
+ sun.setRise(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.SUN_RISE));
+ }
+
+ @Test
+ public void testGetAllRangesForDaylight() {
+ sun.setDaylight(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.DAYLIGHT));
+ }
+
+ @Test
+ public void testGetAllRangesForNoon() {
+ sun.setNoon(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.NOON));
+ }
+
+ @Test
+ public void testGetAllRangesForSet() {
+ sun.setSet(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.SUN_SET));
+ }
+
+ @Test
+ public void testGetAllRangesForCivilDusk() {
+ sun.setCivilDusk(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.CIVIL_DUSK));
+ }
+
+ @Test
+ public void testGetAllRangesForNauticDusk() {
+ sun.setNauticDusk(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.NAUTIC_DUSK));
+ }
+
+ @Test
+ public void testGetAllRangesForAstroDusk() {
+ sun.setAstroDusk(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.ASTRO_DUSK));
+ }
+
+ @Test
+ public void testGetAllRangesForEveningNight() {
+ sun.setEveningNight(new Range());
+
+ assertTrue(sun.getAllRanges().containsKey(SunPhaseName.EVENING_NIGHT));
+ }
+}
diff --git a/bundles/org.openhab.binding.avmfritz/pom.xml b/bundles/org.openhab.binding.avmfritz/pom.xml
index 7fed52f88efaf..481597298aa46 100644
--- a/bundles/org.openhab.binding.avmfritz/pom.xml
+++ b/bundles/org.openhab.binding.avmfritz/pom.xml
@@ -33,9 +33,9 @@
provided
- javax.activation
- activation
- 1.1.1
+ org.apache.servicemix.specs
+ org.apache.servicemix.specs.activation-api-1.1
+ 2.9.0provided
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/lib/tinyb-0.5.1.jar b/bundles/org.openhab.binding.bluetooth.bluez/lib/tinyb-0.5.1.jar
new file mode 100644
index 0000000000000..dca6d7ad8bd83
Binary files /dev/null and b/bundles/org.openhab.binding.bluetooth.bluez/lib/tinyb-0.5.1.jar differ
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/pom.xml b/bundles/org.openhab.binding.bluetooth.bluez/pom.xml
index f21776a482aaa..8d92f24bb8a47 100644
--- a/bundles/org.openhab.binding.bluetooth.bluez/pom.xml
+++ b/bundles/org.openhab.binding.bluetooth.bluez/pom.xml
@@ -20,11 +20,6 @@
${project.version}provided
-
- org.sputnikdev
- bluetooth-manager-tinyb
- 1.3.3
- provided
-
+
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/feature/feature.xml b/bundles/org.openhab.binding.bluetooth.bluez/src/main/feature/feature.xml
index 297798a45403b..9c1f255ac4d0a 100644
--- a/bundles/org.openhab.binding.bluetooth.bluez/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.bluetooth.bluez/src/main/feature/feature.xml
@@ -5,8 +5,6 @@
openhab-runtime-baseopenhab-transport-serial
- wrap
- wrap:mvn:org.sputnikdev/bluetooth-manager-tinyb/1.3.3$Bundle-Name=Tinyb&Bundle-SymbolicName=org.sputnikdev.bluetooth-manager-tinyb&Bundle-Version=1.3.3mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth/${project.version}mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth.bluez/${project.version}
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/handler/BlueZBridgeHandler.java b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/handler/BlueZBridgeHandler.java
index 38d8953c4e37a..54bf41a03014c 100644
--- a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/handler/BlueZBridgeHandler.java
+++ b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/handler/BlueZBridgeHandler.java
@@ -88,8 +88,12 @@ public BlueZBridgeHandler(Bridge bridge) {
@Override
public void initialize() {
+ BluetoothManager manager;
try {
- BluetoothManager.getBluetoothManager();
+ manager = BluetoothManager.getBluetoothManager();
+ if (manager == null) {
+ throw new IllegalStateException("Received null BlueZ manager");
+ }
} catch (UnsatisfiedLinkError e) {
throw new IllegalStateException("BlueZ JNI connection cannot be established.", e);
} catch (RuntimeException e) {
@@ -116,9 +120,14 @@ public void initialize() {
}
logger.debug("Creating BlueZ adapter with address '{}'", address);
- for (tinyb.BluetoothAdapter a : BluetoothManager.getBluetoothManager().getAdapters()) {
- if (a.getAddress().equals(address.toString())) {
- adapter = a;
+
+ for (tinyb.BluetoothAdapter adapter : manager.getAdapters()) {
+ if (adapter == null) {
+ logger.warn("got null adapter from bluetooth manager");
+ continue;
+ }
+ if (adapter.getAddress().equals(address.toString())) {
+ this.adapter = adapter;
updateStatus(ThingStatus.ONLINE);
startDiscovery();
discoveryJob = scheduler.scheduleWithFixedDelay(this::refreshDevices, 0, 10, TimeUnit.SECONDS);
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/package-info.java b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/package-info.java
new file mode 100644
index 0000000000000..857b851de19e0
--- /dev/null
+++ b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/package-info.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2010-2019 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
+ */
+@org.osgi.annotation.bundle.Header(name = org.osgi.framework.Constants.BUNDLE_NATIVECODE, value = "lib/armv6hf/libjavatinyb.so;lib/armv6hf/libtinyb.so;processor=arm;osname=linux")
+package org.openhab.binding.bluetooth.bluez;
+
+/**
+ * Additional information for BlueZ package
+ *
+ * @author Jan N. Klug - Initial contribution
+ *
+ */
\ No newline at end of file
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libjavatinyb.so b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libjavatinyb.so
new file mode 100644
index 0000000000000..b1b5da17fc90b
Binary files /dev/null and b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libjavatinyb.so differ
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libtinyb.so b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libtinyb.so
new file mode 100644
index 0000000000000..bf444a7f101d5
Binary files /dev/null and b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/armv6hf/libtinyb.so differ
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libjavatinyb.so b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libjavatinyb.so
new file mode 100644
index 0000000000000..308abed357c2a
Binary files /dev/null and b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libjavatinyb.so differ
diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libtinyb.so b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libtinyb.so
new file mode 100644
index 0000000000000..430f3b6c44495
Binary files /dev/null and b/bundles/org.openhab.binding.bluetooth.bluez/src/main/resources/lib/x86-64/libtinyb.so differ
diff --git a/bundles/org.openhab.binding.boschindego/pom.xml b/bundles/org.openhab.binding.boschindego/pom.xml
index 82d82726c5d49..af10b3acb4cfa 100644
--- a/bundles/org.openhab.binding.boschindego/pom.xml
+++ b/bundles/org.openhab.binding.boschindego/pom.xml
@@ -33,8 +33,8 @@
provided
- de.zazaz.iot.bosch.indego
- bosch-indego-controller-lib
+ org.openhab.osgiify
+ de.zazaz.iot.bosch.indego.bosch-indego-controller-lib0.8provided
diff --git a/bundles/org.openhab.binding.boschindego/src/main/feature/feature.xml b/bundles/org.openhab.binding.boschindego/src/main/feature/feature.xml
index 13cb6434cc123..a25418aadaef1 100644
--- a/bundles/org.openhab.binding.boschindego/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.boschindego/src/main/feature/feature.xml
@@ -4,13 +4,12 @@
openhab-runtime-base
- wrapmvn:com.fasterxml.jackson.core/jackson-annotations/2.9.8mvn:com.fasterxml.jackson.core/jackson-core/2.9.8mvn:com.fasterxml.jackson.core/jackson-databind/2.9.8mvn:org.apache.httpcomponents/httpcore-osgi/4.4.9mvn:org.apache.httpcomponents/httpclient-osgi/4.5.5
- wrap:mvn:de.zazaz.iot.bosch.indego/bosch-indego-controller-lib/0.8$Bundle-Name=Bosch%20Indego;Bundle-SymbolicName=de.zazaz.iot.bosch.indego.bosch-indego-controller-lib&Bundle-Version=0.8
+ mvn:org.openhab.osgiify/de.zazaz.iot.bosch.indego.bosch-indego-controller-lib/0.8mvn:org.openhab.addons.bundles/org.openhab.binding.boschindego/${project.version}
diff --git a/bundles/org.openhab.binding.buienradar/README.md b/bundles/org.openhab.binding.buienradar/README.md
index 05781207aef14..03d0133d1cc2d 100644
--- a/bundles/org.openhab.binding.buienradar/README.md
+++ b/bundles/org.openhab.binding.buienradar/README.md
@@ -1,12 +1,17 @@
# Buienradar Binding
-The Buienradar Binding periodically (5 minute intervals) retrieves rainfall predictions from the Dutch buienradar.nl webservice API.
+The Buienradar Binding periodically (5 minute intervals) retrieves rainfall predictions from the Dutch
+[buienradar.nl webservice API.](https://www.buienradar.nl/overbuienradar/gratis-weerdata).
-This allows us to warn of upcoming rainfal when there are still open windows, or prevents watering the outside plants needlessly.
+Using the binding, we can
+
+* warn of upcoming rainfall when there are open windows or doors
+* prevent watering the outside plants needlessly,
+* warn when we are about to leave the house.
## Supported Things
-The webservice supports one thing, which can be added manually via the web interface. The thing needs longitude and latitude of the location which needs forecasts.
+The binding supports one thing, which can be added manually via the web interface. The thing needs longitude and latitude of the location which needs forecasts.
## Discovery
@@ -50,3 +55,20 @@ Number RAIN_115MIN "Rain 115 min." (Rain) {channel="buienradar:rain_forecast:hom
Number RAIN_120MIN "Rain 120 min." (Rain) {channel="buienradar:rain_forecast:home:forecast_120" }
```
+## Example data visualisation
+
+In this example we use the 'Discrete' plugin of Grafana to visualize the predictions. Mappings are made according to precipitation intensity (light, medium, heavy) and those categories are given appropriate colors.
+
+![Z-Way Binding](doc/img/grafana-dashboard.png)
+
+The mappings are as follows:
+
+* 0 – 0.01: None (rgba(204, 204, 204, 0))
+* 0.01 – 1: Very light (#badff4)
+* 1 – 5: Light (#6ed0e0)
+* 5 – 20: Medium (#1f78c1)
+* 20 – 50: Heavy (#ef843c)
+* 50 – 80: Very heavy (#e24d42)
+* 80 – 100: Extremely heavy (#890f02)
+
+
diff --git a/bundles/org.openhab.binding.buienradar/doc/img/grafana-dashboard.png b/bundles/org.openhab.binding.buienradar/doc/img/grafana-dashboard.png
new file mode 100644
index 0000000000000..466102e9690c3
Binary files /dev/null and b/bundles/org.openhab.binding.buienradar/doc/img/grafana-dashboard.png differ
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarBindingConstants.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarBindingConstants.java
index a009b6ea1c1a9..c3df364683531 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarBindingConstants.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarBindingConstants.java
@@ -29,6 +29,7 @@ public class BuienradarBindingConstants {
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_RAIN_FORECAST = new ThingTypeUID(BINDING_ID, "rain_forecast");
+ public static final String ACTUAL_DATETIME = "actual_datetime";
public static final String FORECAST_0 = "forecast_0";
public static final String FORECAST_5 = "forecast_5";
public static final String FORECAST_10 = "forecast_10";
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarConfiguration.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarConfiguration.java
index 65e46acc5beb2..601b0c74876fd 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarConfiguration.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarConfiguration.java
@@ -28,4 +28,15 @@ public class BuienradarConfiguration {
* Refresh interval for retrieving results from buienradar.
*/
public Integer refreshIntervalMinutes;
+
+ /**
+ * Number of retries to try to retrieve buienradar results.
+ */
+ public Integer retries;
+
+ /**
+ * Exponential backoff base value for retries in seconds. For example, when this is 2 seconds, will retry at 2, 4,
+ * 8, 16, 32, 64 seconds.
+ */
+ public Integer exponentialBackoffRetryBaseInSeconds;
}
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarHandler.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarHandler.java
index 4431c42c54ac8..02dd02ff7e617 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarHandler.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/BuienradarHandler.java
@@ -20,15 +20,20 @@
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Locale;
+import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
-import javax.measure.Unit;
import javax.measure.quantity.Speed;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.library.types.DateTimeType;
import org.eclipse.smarthome.core.library.types.PointType;
import org.eclipse.smarthome.core.library.types.QuantityType;
+import org.eclipse.smarthome.core.library.unit.SmartHomeUnits;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
@@ -41,8 +46,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import tec.uom.se.unit.Units;
-
/**
* The {@link BuienradarHandler} is responsible for handling commands, which are
* sent to one of the channels.
@@ -58,10 +61,14 @@ public class BuienradarHandler extends BaseThingHandler {
private @NonNullByDefault({}) ScheduledFuture> listenableFuture;
+ /**
+ * Prevents race-condition access to listenableFuture.
+ */
+ private final Lock listenableFutureLock = new ReentrantLock();
+
private @NonNullByDefault({}) PointType location;
- private static final Unit MILLIMETRE_PER_HOUR = Units.METRE.divide(1000).divide(Units.HOUR)
- .asType(Speed.class);
+ private @NonNullByDefault({}) BuienradarConfiguration config;
public BuienradarHandler(Thing thing) {
super(thing);
@@ -75,7 +82,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
@SuppressWarnings("null")
@Override
public void initialize() {
- BuienradarConfiguration config = getConfigAs(BuienradarConfiguration.class);
+ this.config = getConfigAs(BuienradarConfiguration.class);
boolean configValid = true;
if (StringUtils.trimToNull(config.location) == null) {
@@ -96,29 +103,59 @@ public void initialize() {
if (configValid) {
updateStatus(ThingStatus.UNKNOWN);
}
- if (listenableFuture == null || listenableFuture.isCancelled()) {
- listenableFuture = scheduler.scheduleWithFixedDelay(this::refresh, 0L, config.refreshIntervalMinutes,
- MINUTES);
+ try {
+ listenableFutureLock.lock();
+ if (listenableFuture == null || listenableFuture.isCancelled()) {
+ listenableFuture = scheduler.scheduleWithFixedDelay(() -> refresh(), 0L, config.refreshIntervalMinutes,
+ MINUTES);
+ }
+ } finally {
+ listenableFutureLock.unlock();
}
}
private void refresh() {
+ refresh(config.retries, ZonedDateTime.now().plusMinutes(config.refreshIntervalMinutes),
+ config.exponentialBackoffRetryBaseInSeconds);
+ }
+
+ private void refresh(int tries, ZonedDateTime nextRefresh, int retryInSeconds) {
+ if (nextRefresh.isBefore(ZonedDateTime.now())) {
+ // The next refresh is already running, stop retries.
+ return;
+ }
+ if (tries <= 0) {
+ // We are out of tries, stop retrying.
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
+ return;
+ }
try {
@SuppressWarnings("null")
- final List predictions = client.getPredictions(location);
+ final Optional> predictionsOpt = client.getPredictions(location);
+ if (!predictionsOpt.isPresent()) {
+ // Did not get a result, retry the retrieval.
+ logger.warn("Did not get a result from buienradar. Retrying. {} tries remaining, waiting {} seconds.",
+ tries, retryInSeconds);
+ scheduler.schedule(() -> refresh(tries - 1, nextRefresh, retryInSeconds * 2), retryInSeconds,
+ TimeUnit.SECONDS);
+ return;
+ }
+ final List predictions = predictionsOpt.get();
+ if (!predictions.isEmpty()) {
+ final ZonedDateTime actual = predictions.get(0).getActualDateTime();
+ updateState(BuienradarBindingConstants.ACTUAL_DATETIME, new DateTimeType(actual));
+ }
for (final Prediction prediction : predictions) {
final BigDecimal intensity = prediction.getIntensity();
- final ZonedDateTime nowPlusThree = ZonedDateTime.now().plusMinutes(3);
- final ZonedDateTime lastFiveMinute = nowPlusThree.withMinute((nowPlusThree.getMinute() / 5) * 5)
- .withSecond(0).withNano(0);
- final long minutesFromNow = lastFiveMinute.until(prediction.getDateTime(), ChronoUnit.MINUTES);
- final long minuteClass = minutesFromNow;
- logger.debug("Forecast for {} at {} is {}", minutesFromNow, prediction.getDateTime(), intensity);
- if (minuteClass >= 0 && minuteClass <= 115) {
- final String label = String.format(Locale.ENGLISH, "forecast_%d", minuteClass);
-
- /** @TODO: edejong 2019-04-03 Change to SmartHomeUnits.MILLIMETRE_PER_HOUR for OH 2.5 */
- updateState(label, new QuantityType(intensity, MILLIMETRE_PER_HOUR));
+
+ final long minutesFromNow = prediction.getActualDateTime().until(prediction.getDateTimeOfPrediction(),
+ ChronoUnit.MINUTES);
+ logger.debug("Forecast for {} at {} made at {} is {}", minutesFromNow,
+ prediction.getDateTimeOfPrediction(), prediction.getActualDateTime(), intensity);
+ if (minutesFromNow >= 0 && minutesFromNow <= 115) {
+ final String label = String.format(Locale.ENGLISH, "forecast_%d", minutesFromNow);
+
+ updateState(label, new QuantityType(intensity, SmartHomeUnits.MILLIMETRE_PER_HOUR));
}
}
@@ -133,9 +170,14 @@ private void refresh() {
@SuppressWarnings("null")
@Override
public void dispose() {
- if (listenableFuture != null && !listenableFuture.isCancelled()) {
- listenableFuture.cancel(true);
- listenableFuture = null;
+ try {
+ listenableFutureLock.lock();
+ if (listenableFuture != null && !listenableFuture.isCancelled()) {
+ listenableFuture.cancel(true);
+ listenableFuture = null;
+ }
+ } finally {
+ listenableFutureLock.unlock();
}
}
}
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/BuienradarPredictionAPI.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/BuienradarPredictionAPI.java
index cc4c71845f055..6efff28380790 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/BuienradarPredictionAPI.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/BuienradarPredictionAPI.java
@@ -20,15 +20,15 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
+import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.smarthome.io.net.http.HttpUtil;
import org.eclipse.smarthome.core.library.types.PointType;
+import org.eclipse.smarthome.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -101,10 +101,13 @@ public static ZonedDateTime parseDateTime(String timeStr, ZonedDateTime now) thr
*
* @param line The line to parse, such as 100|23:00
* @param now The reference time to determine which instant to match to.
+ * @param actual The date time of the 'actual' prediction if known. If None is given, it is assumed this is the
+ * first row of the results.
* @return A Prediction interface, which contains the tuple with the intensity and the time.
* @throws BuienradarParseException Thrown when the line could not be correctly parsed.
*/
- public static Prediction parseLine(String line, ZonedDateTime now) throws BuienradarParseException {
+ public static Prediction parseLine(String line, ZonedDateTime now, Optional actual)
+ throws BuienradarParseException {
final String[] lineElements = line.trim().split("\\|");
if (lineElements.length != 2) {
throw new BuienradarParseException(
@@ -120,29 +123,44 @@ public final BigDecimal getIntensity() {
}
@Override
- public final ZonedDateTime getDateTime() {
+ public ZonedDateTime getDateTimeOfPrediction() {
return dateTime;
}
+
+ @Override
+ public ZonedDateTime getActualDateTime() {
+ return actual.orElseGet(this::getDateTimeOfPrediction);
+ }
};
}
@Override
- public List getPredictions(PointType location) throws IOException {
- final String address = String.format(Locale.ENGLISH, BASE_ADDRESS + "?lat=%.8f&lon=%.8f",
+ public Optional> getPredictions(PointType location) throws IOException {
+ final String address = String.format(Locale.ENGLISH, BASE_ADDRESS + "?lat=%.2f&lon=%.2f",
location.getLatitude().doubleValue(), location.getLongitude().doubleValue());
- final String result = HttpUtil.executeUrl("GET", address, TIMEOUT_MS);
+
+ final String result;
+ try {
+ result = HttpUtil.executeUrl("GET", address, TIMEOUT_MS);
+ } catch (IOException e) {
+ logger.warn("IO Exception when trying to retrieve Buienradar results", e);
+ return Optional.empty();
+ }
if (result.trim().isEmpty()) {
logger.warn(String.format("Buienradar API at URI %s return empty result", address));
- return Collections.emptyList();
+ return Optional.empty();
}
final List predictions = new ArrayList(24);
final List errors = new LinkedList();
logger.debug("Returned result from buienradar: {}", result);
final String[] lines = result.split("\n");
+ Optional actual = Optional.empty();
for (String line : lines) {
try {
- predictions.add(parseLine(line, ZonedDateTime.now()));
+ final Prediction prediction = parseLine(line, ZonedDateTime.now(), actual);
+ actual = Optional.of(prediction.getActualDateTime());
+ predictions.add(prediction);
} catch (BuienradarParseException e) {
errors.add(e.getMessage());
}
@@ -150,7 +168,7 @@ public List getPredictions(PointType location) throws IOException {
if (!errors.isEmpty()) {
logger.warn("Could not parse all results: " + errors.stream().collect(Collectors.joining(", ")));
}
- return predictions;
+ return Optional.of(predictions);
}
}
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/Prediction.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/Prediction.java
index 7764566ac687b..8aabe8d33c7de 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/Prediction.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/Prediction.java
@@ -32,5 +32,10 @@ public interface Prediction {
/**
* Date-time of prediction.
*/
- ZonedDateTime getDateTime();
+ ZonedDateTime getDateTimeOfPrediction();
+
+ /**
+ * Date-time of when the prediction was made.
+ */
+ ZonedDateTime getActualDateTime();
}
diff --git a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/PredictionAPI.java b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/PredictionAPI.java
index d3a23f5dd82b5..18f3ea978281a 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/PredictionAPI.java
+++ b/bundles/org.openhab.binding.buienradar/src/main/java/org/openhab/binding/buienradar/internal/buienradarapi/PredictionAPI.java
@@ -14,6 +14,7 @@
import java.io.IOException;
import java.util.List;
+import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.PointType;
@@ -25,5 +26,6 @@
*/
@NonNullByDefault
public interface PredictionAPI {
- List getPredictions(PointType location) throws IOException;
+
+ Optional> getPredictions(PointType location) throws IOException;
}
diff --git a/bundles/org.openhab.binding.buienradar/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.buienradar/src/main/resources/ESH-INF/thing/thing-types.xml
index effd19fd2f2a1..0ff4e018c8c02 100644
--- a/bundles/org.openhab.binding.buienradar/src/main/resources/ESH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.buienradar/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -11,6 +11,7 @@
two hours, in 5 minute increments using the buienradar.nl webservice.
+
@@ -50,10 +51,29 @@
Refresh interval in minutes5
+
+
+
+ Number of retries to try to retrieve buienradar results
+ 4
+
+
+
+
+ Exponential back-off base value for retries in seconds. For example, when this is 2 seconds, will retry at 2, 4, 8, 16, 32, 64 seconds.
+ 5
+
+
+ DateTime
+
+ The actual date and time when the prediction was made."
+
+
+
Number:Speed
diff --git a/bundles/org.openhab.binding.buienradar/src/test/java/org/openhab/binding/buienradar/BuienradarPredictionAPITest.java b/bundles/org.openhab.binding.buienradar/src/test/java/org/openhab/binding/buienradar/BuienradarPredictionAPITest.java
index 2290d02d1ef14..f60a5e329d85b 100644
--- a/bundles/org.openhab.binding.buienradar/src/test/java/org/openhab/binding/buienradar/BuienradarPredictionAPITest.java
+++ b/bundles/org.openhab.binding.buienradar/src/test/java/org/openhab/binding/buienradar/BuienradarPredictionAPITest.java
@@ -17,6 +17,7 @@
import java.math.BigDecimal;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.util.Optional;
import org.junit.Test;
import org.openhab.binding.buienradar.internal.buienradarapi.BuienradarParseException;
@@ -26,6 +27,9 @@
public class BuienradarPredictionAPITest {
private static final ZonedDateTime NOW = ZonedDateTime.of(2019, 3, 10, 20, 37, 0, 0, ZoneId.of("Europe/Amsterdam"));
+ private static final ZonedDateTime ACTUAL = ZonedDateTime.of(2019, 3, 10, 20, 35, 0, 0,
+ ZoneId.of("Europe/Amsterdam"));
+
private static final ZonedDateTime NOW_LONDON = ZonedDateTime.of(2019, 3, 10, 20, 37, 0, 0,
ZoneId.of("Europe/London"));
@@ -71,8 +75,9 @@ public void testParseDateTimeTomorrow() throws BuienradarParseException {
@Test
public void testParseLine() throws BuienradarParseException {
- final Prediction parsed = BuienradarPredictionAPI.parseLine("000|19:35", NOW);
- assertEquals(ZonedDateTime.of(2019, 3, 11, 19, 35, 0, 0, ZoneId.of("Europe/Amsterdam")), parsed.getDateTime());
+ final Prediction parsed = BuienradarPredictionAPI.parseLine("000|19:35", NOW, Optional.of(ACTUAL));
+ assertEquals(ZonedDateTime.of(2019, 3, 11, 19, 35, 0, 0, ZoneId.of("Europe/Amsterdam")),
+ parsed.getDateTimeOfPrediction());
assertEquals(BigDecimal.valueOf(0, 2), parsed.getIntensity());
}
diff --git a/bundles/org.openhab.binding.denonmarantz/pom.xml b/bundles/org.openhab.binding.denonmarantz/pom.xml
index c42085c14a42a..c84e3469d47b4 100644
--- a/bundles/org.openhab.binding.denonmarantz/pom.xml
+++ b/bundles/org.openhab.binding.denonmarantz/pom.xml
@@ -34,9 +34,9 @@
provided
- javax.activation
- activation
- 1.1.1
+ org.apache.servicemix.specs
+ org.apache.servicemix.specs.activation-api-1.1
+ 2.9.0provided
diff --git a/bundles/org.openhab.binding.dlinksmarthome/pom.xml b/bundles/org.openhab.binding.dlinksmarthome/pom.xml
index 242f0fe90ddad..235a072239bff 100644
--- a/bundles/org.openhab.binding.dlinksmarthome/pom.xml
+++ b/bundles/org.openhab.binding.dlinksmarthome/pom.xml
@@ -34,9 +34,9 @@
provided
- javax.activation
- activation
- 1.1.1
+ org.apache.servicemix.specs
+ org.apache.servicemix.specs.activation-api-1.1
+ 2.9.0provided
diff --git a/bundles/org.openhab.binding.dmx/README.md b/bundles/org.openhab.binding.dmx/README.md
index daa0deeee8eda..5c60b9774c6b9 100644
--- a/bundles/org.openhab.binding.dmx/README.md
+++ b/bundles/org.openhab.binding.dmx/README.md
@@ -194,7 +194,7 @@ The next `ON` command uses these values instead of the default (or configuration
|-----------------|---------------------|----------------------|----------------------------------------------------|
|brightness |dimmer, tunablewhite |Switch, Dimmer | controls the brightness |
|color |color |Switch, Dimmer, Color | allows to set the color and brightness |
-|colortemperature |tunablewhite |Number | allows to set the color temperature |
+|color_temperature|tunablewhite |Number | allows to set the color temperature |
|brightness_r |color |Switch, Dimmer | controls the brightness of the red channel |
|brightness_g |color |Switch, Dimmer | controls the brightness of the green channel |
|brightness_b |color |Switch, Dimmer | controls the brightness of the blue channel |
diff --git a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/config/EnOceanChannelRollershutterConfig.java b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/config/EnOceanChannelRollershutterConfig.java
index 8d2eb503fb781..9e2291b8028e1 100644
--- a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/config/EnOceanChannelRollershutterConfig.java
+++ b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/config/EnOceanChannelRollershutterConfig.java
@@ -18,7 +18,7 @@
*/
public class EnOceanChannelRollershutterConfig {
- public Integer shutTime;
+ public int shutTime;
public EnOceanChannelRollershutterConfig() {
shutTime = 255;
diff --git a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/A5_3F/A5_3F_7F_EltakoFSB.java b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/A5_3F/A5_3F_7F_EltakoFSB.java
index 39173b6620bec..0da5eb17c2132 100644
--- a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/A5_3F/A5_3F_7F_EltakoFSB.java
+++ b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/A5_3F/A5_3F_7F_EltakoFSB.java
@@ -96,16 +96,24 @@ protected State convertToStateImpl(String channelId, String channelTypeId,
State currentState = getCurrentStateFunc.apply(channelId);
if (currentState != null) {
- int direction = getDB_1() == MoveUp ? -1 : 1;
int duration = ((getDB_3Value() << 8) + getDB_2Value()) / 10; // => Time in DB3 and DB2 is given
// in ms
- PercentType current = currentState.as(PercentType.class);
- if (config != null && current != null) {
+ if (config != null) {
EnOceanChannelRollershutterConfig c = config.as(EnOceanChannelRollershutterConfig.class);
- if (c.shutTime != -1 && c.shutTime != 0) {
- return new PercentType(Math.min(100, (Math.max(0, current.intValue()
- + direction * ((duration * PercentType.HUNDRED.intValue()) / c.shutTime)))));
+ if (duration == c.shutTime) {
+ return getDB_1() == MoveUp ? PercentType.ZERO : PercentType.HUNDRED;
+ } else {
+ PercentType current = PercentType.ZERO;
+ if (currentState instanceof PercentType) {
+ current = currentState.as(PercentType.class);
+ }
+
+ int direction = getDB_1() == MoveUp ? -1 : 1;
+ if (c.shutTime != -1 && c.shutTime != 0) {
+ return new PercentType(Math.min(100, (Math.max(0, current.intValue()
+ + direction * ((duration * PercentType.HUNDRED.intValue()) / c.shutTime)))));
+ }
}
}
}
diff --git a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/EEPType.java b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/EEPType.java
index 3ea9ba2ce78ad..e36fc16cd1d16 100644
--- a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/EEPType.java
+++ b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/eep/EEPType.java
@@ -257,7 +257,7 @@ public enum EEPType {
CHANNEL_MOTIONDETECTION, CHANNEL_BATTERY_VOLTAGE),
OCCUPANCYSENSOR_A5_07_02(RORG._4BS, 0x07, 0x02, false, A5_07_02.class, THING_TYPE_OCCUPANCYSENSOR,
CHANNEL_MOTIONDETECTION, CHANNEL_BATTERY_VOLTAGE),
- OCCUPANCYSENSOR_A5_07_03(RORG._4BS, 0x07, 0x02, false, A5_07_03.class, THING_TYPE_OCCUPANCYSENSOR,
+ OCCUPANCYSENSOR_A5_07_03(RORG._4BS, 0x07, 0x03, false, A5_07_03.class, THING_TYPE_OCCUPANCYSENSOR,
CHANNEL_ILLUMINATION, CHANNEL_MOTIONDETECTION, CHANNEL_BATTERY_VOLTAGE),
LightTemperatureOccupancySensor_A5_08_01(RORG._4BS, 0x08, 0x01, false, A5_08_01.class,
diff --git a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/handler/EnOceanBaseSensorHandler.java b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/handler/EnOceanBaseSensorHandler.java
index 2cddf477f78a1..542dd1780a6b1 100644
--- a/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/handler/EnOceanBaseSensorHandler.java
+++ b/bundles/org.openhab.binding.enocean/src/main/java/org/openhab/binding/enocean/internal/handler/EnOceanBaseSensorHandler.java
@@ -154,7 +154,7 @@ public void espPacketReceived(ESP3Packet packet) {
EEP eep = EEPFactory.buildEEP(receivingEEPType, (ERP1Message) packet);
logger.debug("ESP Packet payload {} for {} received", HexUtils.bytesToHex(packet.getPayload()),
- config.enoceanId);
+ HexUtils.bytesToHex(msg.getSenderId()));
if (eep.isValid()) {
byte[] senderId = msg.getSenderId();
diff --git a/bundles/org.openhab.binding.enocean/src/main/resources/ESH-INF/thing/Rollershutter.xml b/bundles/org.openhab.binding.enocean/src/main/resources/ESH-INF/thing/Rollershutter.xml
index 541d58f82ded1..89aae59187e69 100644
--- a/bundles/org.openhab.binding.enocean/src/main/resources/ESH-INF/thing/Rollershutter.xml
+++ b/bundles/org.openhab.binding.enocean/src/main/resources/ESH-INF/thing/Rollershutter.xml
@@ -48,6 +48,7 @@
+
4true
diff --git a/bundles/org.openhab.binding.globalcache/README.md b/bundles/org.openhab.binding.globalcache/README.md
index b2d905edd7ce4..4004bc3e05228 100644
--- a/bundles/org.openhab.binding.globalcache/README.md
+++ b/bundles/org.openhab.binding.globalcache/README.md
@@ -135,7 +135,7 @@ A *Contact Closure channel* activates the contact closure (relay) on the iTach o
For example, the following item links to the module 1, connector 1 channel on an iTach CC device.
```
-Contact MyRelay "My Relay [%s]" (gRelays) { channel="globalcache:itachCC:000C1E039BCF:cc-m1#c1" }
+Switch MyRelay "My Relay [%s]" (gRelays) { channel="globalcache:itachCC:000C1E039BCF:cc-m1#c1" }
```
The item definition for an iTach Flex WiFi device would look like this.
diff --git a/bundles/org.openhab.binding.globalcache/src/main/resources/ESH-INF/thing/channel-types.xml b/bundles/org.openhab.binding.globalcache/src/main/resources/ESH-INF/thing/channel-types.xml
index 103e1eac1b866..9bbe57a5bf5a3 100644
--- a/bundles/org.openhab.binding.globalcache/src/main/resources/ESH-INF/thing/channel-types.xml
+++ b/bundles/org.openhab.binding.globalcache/src/main/resources/ESH-INF/thing/channel-types.xml
@@ -12,7 +12,7 @@
- Contact
+ SwitchTransmits contact closure command on module:connector
diff --git a/bundles/org.openhab.binding.innogysmarthome/pom.xml b/bundles/org.openhab.binding.innogysmarthome/pom.xml
index 366501912c7ca..289ff4e26c46a 100644
--- a/bundles/org.openhab.binding.innogysmarthome/pom.xml
+++ b/bundles/org.openhab.binding.innogysmarthome/pom.xml
@@ -33,8 +33,8 @@
provided
- com.google.http-client
- google-http-client-gson
+ org.openhab.osgiify
+ com.google.http-client.google-http-client-gson1.27.0provided
diff --git a/bundles/org.openhab.binding.innogysmarthome/src/main/feature/feature.xml b/bundles/org.openhab.binding.innogysmarthome/src/main/feature/feature.xml
index c2480a7983ee1..77b5edaceaced 100644
--- a/bundles/org.openhab.binding.innogysmarthome/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.innogysmarthome/src/main/feature/feature.xml
@@ -4,14 +4,13 @@
openhab-runtime-base
- wrapmvn:org.apache.httpcomponents/httpcore-osgi/4.4.4mvn:org.apache.httpcomponents/httpclient-osgi/4.5.2mvn:com.google.guava/guava/20.0mvn:commons-codec/commons-codec/1.10mvn:com.google.oauth-client/google-oauth-client/1.27.0mvn:com.google.http-client/google-http-client/1.27.0
- wrap:mvn:com.google.http-client/google-http-client-gson/1.27.0$Bundle-Name=GSON%202%20Extensions&Bundle-SymbolicName=com.google.http-client.google-http-client-gson&Bundle-Version=1.27.0
+ mvn:org.openhab.osgiify/com.google.http-client.google-http-client-gson/1.27.0mvn:org.openhab.addons.bundles/org.openhab.binding.innogysmarthome/${project.version}
diff --git a/bundles/org.openhab.binding.ipp/pom.xml b/bundles/org.openhab.binding.ipp/pom.xml
index af9380935729e..e2eb11d1f912f 100644
--- a/bundles/org.openhab.binding.ipp/pom.xml
+++ b/bundles/org.openhab.binding.ipp/pom.xml
@@ -15,8 +15,8 @@
- org.cups4j
- cups4j
+ org.openhab.osgiify
+ org.cups4j.cups4j0.7.6provided
diff --git a/bundles/org.openhab.binding.ipp/src/main/feature/feature.xml b/bundles/org.openhab.binding.ipp/src/main/feature/feature.xml
index 5fa38a8fed4fe..f61734a2a0a26 100644
--- a/bundles/org.openhab.binding.ipp/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.ipp/src/main/feature/feature.xml
@@ -5,8 +5,7 @@
openhab-runtime-baseopenhab-transport-mdns
- wrap
- wrap:mvn:org.cups4j/cups4j/0.7.6$Bundle-Name=Cups4J&Bundle-SymbolicName=org.cups4j.cups4j&Bundle-Version=0.7.6
+ mvn:org.openhab.osgiify/org.cups4j.cups4j/0.7.6mvn:org.apache.httpcomponents/httpcore-osgi/4.4.4mvn:org.apache.httpcomponents/httpclient-osgi/4.5.2mvn:org.openhab.addons.bundles/org.openhab.binding.ipp/${project.version}
diff --git a/bundles/org.openhab.binding.jeelink/src/main/java/org/openhab/binding/jeelink/internal/connection/JeeLinkSerialConnection.java b/bundles/org.openhab.binding.jeelink/src/main/java/org/openhab/binding/jeelink/internal/connection/JeeLinkSerialConnection.java
index b94a0c42b39b6..cbd393731f4f4 100644
--- a/bundles/org.openhab.binding.jeelink/src/main/java/org/openhab/binding/jeelink/internal/connection/JeeLinkSerialConnection.java
+++ b/bundles/org.openhab.binding.jeelink/src/main/java/org/openhab/binding/jeelink/internal/connection/JeeLinkSerialConnection.java
@@ -16,7 +16,6 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.Reader;
import java.util.TooManyListenersException;
import org.slf4j.Logger;
@@ -79,26 +78,25 @@ public synchronized void openConnection() {
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
- try (Reader isr = new InputStreamReader(serialPort.getInputStream());
- BufferedReader input = new BufferedReader(isr)) {
- serialPort.addEventListener(new SerialPortEventListener() {
- @Override
- public void serialEvent(SerialPortEvent event) {
- try {
- if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
- propagateLine(input.readLine());
- }
- } catch (IOException ex) {
- logger.debug("Error reading from serial port!", ex);
- closeConnection();
- notifyAbort("propagate: " + ex.getMessage());
+ final BufferedReader input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
+
+ serialPort.addEventListener(new SerialPortEventListener() {
+ @Override
+ public void serialEvent(SerialPortEvent event) {
+ try {
+ if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
+ propagateLine(input.readLine());
}
+ } catch (IOException ex) {
+ logger.debug("Error reading from serial port!", ex);
+ closeConnection();
+ notifyAbort("propagate: " + ex.getMessage());
}
- });
+ }
+ });
- serialPort.notifyOnDataAvailable(true);
- notifyOpen();
- }
+ serialPort.notifyOnDataAvailable(true);
+ notifyOpen();
}
} catch (UnsupportedCommOperationException | IOException | TooManyListenersException ex) {
closeConnection();
diff --git a/bundles/org.openhab.binding.keba/README.md b/bundles/org.openhab.binding.keba/README.md
index 9d91b67597578..84c623b2d0f9d 100644
--- a/bundles/org.openhab.binding.keba/README.md
+++ b/bundles/org.openhab.binding.keba/README.md
@@ -42,6 +42,7 @@ All devices support the following channels:
| sessionrfidtag | String | yes | RFID tag used for the last charging session |
| sessionrfidclass | String | yes | RFID tag class used for the last charging session |
| sessionid | Number | yes | session ID of the last charging session |
+| setenergylimit | Number | no | set an energy limit for an already running or the next charging session|
## Example
@@ -76,6 +77,7 @@ Number KebaSessionEnergy {channel="keba:kecontact:1:sessionconsumption"}
Number KebaTotalEnergy {channel="keba:kecontact:1:totalconsumption"}
Switch KebaInputSwitch {channel="keba:kecontact:1:input"}
Switch KebaOutputSwitch {channel="keba:kecontact:1:output"}
+Number KebaSetEnergyLimit {channel="keba:kecontact:1:setenergylimit"}
```
demo.sitemap:
@@ -96,6 +98,7 @@ sitemap demo label="Main Menu"
Text item=KebaFailSafeCurrent label="Failsafe supply current [%.0f mA]"
Text item=KebaSessionEnergy label="Energy during current session [%.0f Wh]"
Text item=KebaTotalEnergy label="Energy during all sessions [%.0f Wh]"
+ Switch item=KebaSetEnergyLimit label="Set charge energy limit" mappings=[0="off", 20000="20kWh"]
}
}
```
diff --git a/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/KebaBindingConstants.java b/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/KebaBindingConstants.java
index 68d663bb77310..c10fe983e9a43 100644
--- a/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/KebaBindingConstants.java
+++ b/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/KebaBindingConstants.java
@@ -69,6 +69,7 @@ public class KebaBindingConstants {
public static final String CHANNEL_SESSION_RFID_TAG = "sessionrfidtag";
public static final String CHANNEL_SESSION_RFID_CLASS = "sessionrfidclass";
public static final String CHANNEL_SESSION_SESSION_ID = "sessionid";
+ public static final String CHANNEL_SETENERGY = "setenergylimit";
public enum KebaType {
P20,
diff --git a/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/handler/KeContactHandler.java b/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/handler/KeContactHandler.java
index bcf684c616042..123db4d738dde 100644
--- a/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/handler/KeContactHandler.java
+++ b/bundles/org.openhab.binding.keba/src/main/java/org/openhab/binding/keba/internal/handler/KeContactHandler.java
@@ -467,6 +467,12 @@ protected void onData(ByteBuffer byteBuffer) {
updateState(CHANNEL_SESSION_SESSION_ID, newState);
break;
}
+ case "Setenergy": {
+ int state = entry.getValue().getAsInt() / 10;
+ State newState = new DecimalType(state);
+ updateState(CHANNEL_SETENERGY, newState);
+ break;
+ }
}
}
} catch (JsonParseException e) {
@@ -548,6 +554,14 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}
break;
}
+ case CHANNEL_SETENERGY: {
+ if (command instanceof DecimalType) {
+ transceiver.send(
+ "setenergy " + String.valueOf(
+ Math.min(Math.max(0, ((DecimalType) command).intValue()*10), 999999999)), this);
+ }
+ break;
+ }
}
}
}
diff --git a/bundles/org.openhab.binding.keba/src/main/resources/ESH-INF/thing/kecontact.xml b/bundles/org.openhab.binding.keba/src/main/resources/ESH-INF/thing/kecontact.xml
index dea303d475a7e..2d8c5f3919f5f 100644
--- a/bundles/org.openhab.binding.keba/src/main/resources/ESH-INF/thing/kecontact.xml
+++ b/bundles/org.openhab.binding.keba/src/main/resources/ESH-INF/thing/kecontact.xml
@@ -53,6 +53,7 @@
+
@@ -245,4 +246,10 @@
Session ID of the last charging session
+
+ Number
+
+ An energy limit for an already running or the next charging session.
+
+
diff --git a/bundles/org.openhab.binding.knx/README.md b/bundles/org.openhab.binding.knx/README.md
index 1f963dd5fa890..fd2ec6128d57a 100644
--- a/bundles/org.openhab.binding.knx/README.md
+++ b/bundles/org.openhab.binding.knx/README.md
@@ -183,22 +183,50 @@ Each configuration parameter has a `mainGA` where commands are written to and op
The `dpt` element is optional. If ommitted, the corresponding default value will be used (see the channel descriptions above).
-## Examples
-
-### Full Example
+## Examples
+The following two templates are sufficient for almost all purposes. Only add parameters to the Bridge and Thing configuration if you know exactly what functionality it is needed for.
+### Type ROUTER mode configuration Template
+knx.things:
+```xtend
+Bridge knx:ip:bridge [
+ type="ROUTER",
+ autoReconnectPeriod=60 //optional, do not set <30 sec.
+] {
+ Thing device knx_device "knx_device_name" @ "knx_device_group_in_paperui" [
+ //readInterval=3600 //optional, only used if reading values are present
+ ] {
+ //Items configurations
+ }
+}
+```
+### Type TUNNEL mode configuration Template
knx.things:
-
```xtend
Bridge knx:ip:bridge [
+ type="TUNNEL",
+ ipAddress="192.168.0.111",
+ autoReconnectPeriod=60 //optional, do not set <30 sec.
+] {
+ Thing device knx_device "knx_device_name" @ "knx_device_group_in_paperui" [
+ //readInterval=3600 //optional, only used if reading values are present
+ ] {
+ //Items configurations
+ }
+}
+```
+### Full Example
+```xtend
+//TUNNEL
+Bridge knx:ip:bridge [
+ type="TUNNEL",
ipAddress="192.168.0.10",
portNumber=3671,
- localIp="192.168.0.11",
- type="TUNNEL",
+ localIp="192.168.0.11",
readingPause=50,
responseTimeout=10,
readRetriesLimit=3,
- autoReconnectPeriod=1,
+ autoReconnectPeriod=60,
localSourceAddr="0.0.0"
] {
Thing device generic [
@@ -216,6 +244,19 @@ Bridge knx:ip:bridge [
Type datetime : demoDatetime "Alarm" [ ga="5/5/42" ]
}
}
+
+//ROUTER
+Bridge knx:ip:bridge [
+ type="ROUTER",
+ ipAddress="224.0.23.12",
+ portNumber=3671,
+ localIp="192.168.0.11",
+ readingPause=50,
+ responseTimeout=10,
+ readRetriesLimit=3,
+ autoReconnectPeriod=60,
+ localSourceAddr="0.0.0"
+] {}
```
knx.items:
@@ -258,7 +299,7 @@ Bridge knx:serial:bridge [
readingPause=50,
responseTimeout=10,
readRetriesLimit=3,
- autoReconnectPeriod=1
+ autoReconnectPeriod=60
] {
Thing device generic {
Type switch-control : controlSwitch "Control Switch" [ ga="3/3/10+<3/3/11" ] // '<' signs are allowed but will be ignored for control Channels
diff --git a/bundles/org.openhab.binding.knx/pom.xml b/bundles/org.openhab.binding.knx/pom.xml
index 87f34a22b8446..1c122758d11b9 100644
--- a/bundles/org.openhab.binding.knx/pom.xml
+++ b/bundles/org.openhab.binding.knx/pom.xml
@@ -15,8 +15,8 @@
- com.github.calimero
- calimero-core
+ org.openhab.osgiify
+ com.github.calimero.calimero-core2.4provided
@@ -27,8 +27,8 @@
- com.github.calimero
- calimero-device
+ org.openhab.osgiify
+ com.github.calimero.calimero-device2.4provided
@@ -39,8 +39,8 @@
- com.github.calimero
- calimero-rxtx
+ org.openhab.osgiify
+ com.github.calimero.calimero-rxtx2.4provided
diff --git a/bundles/org.openhab.binding.knx/src/main/feature/feature.xml b/bundles/org.openhab.binding.knx/src/main/feature/feature.xml
index e790a77310d4e..a38f9be53b9e0 100644
--- a/bundles/org.openhab.binding.knx/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.knx/src/main/feature/feature.xml
@@ -5,10 +5,9 @@
openhab-runtime-baseopenhab-transport-serial
- wrap
- wrap:mvn:com.github.calimero/calimero-core/2.4$Bundle-Name=Calimero%20Core&Bundle-SymbolicName=com.github.calimero.calimero-core&Bundle-Version=2.4
- wrap:mvn:com.github.calimero/calimero-device/2.4$Bundle-Name=Calimero%20KNX%20Device&Bundle-SymbolicName=com.github.calimero.calimero-device&Bundle-Version=2.4
- wrap:mvn:com.github.calimero/calimero-rxtx/2.4$Bundle-Name=Calimero%20rxtx%20Adapter&Bundle-SymbolicName=com.github.calimero.calimero-rxtx&Bundle-Version=2.4
+ mvn:org.openhab.osgiify/com.github.calimero.calimero-core/2.4
+ mvn:org.openhab.osgiify/com.github.calimero.calimero-device/2.4
+ mvn:org.openhab.osgiify/com.github.calimero.calimero-rxtx/2.4mvn:org.openhab.addons.bundles/org.openhab.binding.knx/${project.version}
diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/AbstractKNXClient.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/AbstractKNXClient.java
index ae9e33dd075aa..97e73ed91009c 100644
--- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/AbstractKNXClient.java
+++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/client/AbstractKNXClient.java
@@ -142,17 +142,17 @@ public void initialize() {
private boolean scheduleReconnectJob() {
if (autoReconnectPeriod > 0) {
- connectJob = knxScheduler.scheduleWithFixedDelay(() -> connect(), 0, autoReconnectPeriod, TimeUnit.SECONDS);
+ connectJob = knxScheduler.schedule(this::connect, autoReconnectPeriod, TimeUnit.SECONDS);
return true;
} else {
return false;
}
}
- private void cancelReconnectJob(boolean kill) {
+ private void cancelReconnectJob() {
ScheduledFuture> currentReconnectJob = connectJob;
if (currentReconnectJob != null) {
- currentReconnectJob.cancel(kill);
+ currentReconnectJob.cancel(true);
connectJob = null;
}
}
@@ -200,11 +200,12 @@ private synchronized boolean connect() {
TimeUnit.MILLISECONDS);
statusUpdateCallback.updateStatus(ThingStatus.ONLINE);
- cancelReconnectJob(false);
+ connectJob = null;
return true;
} catch (KNXException | InterruptedException e) {
logger.debug("Error connecting to the bus: {}", e.getMessage(), e);
disconnect(e);
+ scheduleReconnectJob();
return false;
}
}
@@ -219,6 +220,7 @@ private void disconnect(@Nullable Exception e) {
}
}
+ @SuppressWarnings("null")
private void releaseConnection() {
logger.debug("Bridge {} is disconnecting from the KNX bus", thingUID);
readDatapoints.clear();
@@ -277,29 +279,28 @@ private void readNextQueuedDatapoint() {
return;
}
ReadDatapoint datapoint = readDatapoints.poll();
- if (datapoint != null) {
- datapoint.incrementRetries();
- try {
- logger.trace("Sending a Group Read Request telegram for {}", datapoint.getDatapoint().getMainAddress());
- processCommunicator.read(datapoint.getDatapoint());
- } catch (KNXException e) {
- if (datapoint.getRetries() < datapoint.getLimit()) {
- readDatapoints.add(datapoint);
- logger.debug("Could not read value for datapoint {}: {}. Going to retry.",
- datapoint.getDatapoint().getMainAddress(), e.getMessage());
- } else {
- logger.warn("Giving up reading datapoint {}, the number of maximum retries ({}) is reached.",
- datapoint.getDatapoint().getMainAddress(), datapoint.getLimit());
- }
- } catch (InterruptedException e) {
- logger.debug("Interrupted sending KNX read request");
- return;
+
+ datapoint.incrementRetries();
+ try {
+ logger.trace("Sending a Group Read Request telegram for {}", datapoint.getDatapoint().getMainAddress());
+ processCommunicator.read(datapoint.getDatapoint());
+ } catch (KNXException e) {
+ if (datapoint.getRetries() < datapoint.getLimit()) {
+ readDatapoints.add(datapoint);
+ logger.debug("Could not read value for datapoint {}: {}. Going to retry.",
+ datapoint.getDatapoint().getMainAddress(), e.getMessage());
+ } else {
+ logger.warn("Giving up reading datapoint {}, the number of maximum retries ({}) is reached.",
+ datapoint.getDatapoint().getMainAddress(), datapoint.getLimit());
}
+ } catch (InterruptedException e) {
+ logger.debug("Interrupted sending KNX read request");
+ return;
}
}
public void dispose() {
- cancelReconnectJob(true);
+ cancelReconnectJob();
disconnect(null);
}
diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/BridgeConfiguration.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/BridgeConfiguration.java
index 0605b3d8728da..164fd6abbe5c9 100644
--- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/BridgeConfiguration.java
+++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/config/BridgeConfiguration.java
@@ -23,13 +23,12 @@
*
*/
public class BridgeConfiguration {
-
- private BigDecimal autoReconnectPeriod;
+ private int autoReconnectPeriod;
private BigDecimal readingPause;
private BigDecimal readRetriesLimit;
private BigDecimal responseTimeout;
- public BigDecimal getAutoReconnectPeriod() {
+ public int getAutoReconnectPeriod() {
return autoReconnectPeriod;
}
@@ -45,4 +44,7 @@ public BigDecimal getResponseTimeout() {
return responseTimeout;
}
+ public void setAutoReconnectPeriod(int period) {
+ autoReconnectPeriod = period;
+ }
}
diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/IPBridgeThingHandler.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/IPBridgeThingHandler.java
index 82a0404a8037f..038ebad9459e0 100644
--- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/IPBridgeThingHandler.java
+++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/IPBridgeThingHandler.java
@@ -27,6 +27,8 @@
import org.openhab.binding.knx.internal.client.KNXClient;
import org.openhab.binding.knx.internal.client.NoOpClient;
import org.openhab.binding.knx.internal.config.IPBridgeConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* The {@link IPBridgeThingHandler} is responsible for handling commands, which are
@@ -39,13 +41,12 @@
*/
@NonNullByDefault
public class IPBridgeThingHandler extends KNXBridgeBaseThingHandler {
-
private static final String MODE_ROUTER = "ROUTER";
private static final String MODE_TUNNEL = "TUNNEL";
- @Nullable
- private IPClient client;
+ private final Logger logger = LoggerFactory.getLogger(IPBridgeThingHandler.class);
+ private @Nullable IPClient client;
private final NetworkAddressService networkAddressService;
public IPBridgeThingHandler(Bridge bridge, NetworkAddressService networkAddressService) {
@@ -56,6 +57,13 @@ public IPBridgeThingHandler(Bridge bridge, NetworkAddressService networkAddressS
@Override
public void initialize() {
IPBridgeConfiguration config = getConfigAs(IPBridgeConfiguration.class);
+ int autoReconnectPeriod = config.getAutoReconnectPeriod();
+ if (autoReconnectPeriod != 0 && autoReconnectPeriod < 30) {
+ logger.info("autoReconnectPeriod set to {}s, allowed range is 0 (never) or >30", thing.getUID(),
+ autoReconnectPeriod);
+ autoReconnectPeriod = 30;
+ config.setAutoReconnectPeriod(autoReconnectPeriod);
+ }
String localSource = config.getLocalSourceAddr();
String connectionTypeString = config.getType();
int port = config.getPortNumber().intValue();
@@ -91,9 +99,9 @@ public void initialize() {
}
updateStatus(ThingStatus.UNKNOWN);
- client = new IPClient(ipConnectionType, ip, localSource, port, localEndPoint, useNAT,
- config.getAutoReconnectPeriod().intValue(), thing.getUID(), config.getResponseTimeout().intValue(),
- config.getReadingPause().intValue(), config.getReadRetriesLimit().intValue(), getScheduler(), this);
+ client = new IPClient(ipConnectionType, ip, localSource, port, localEndPoint, useNAT, autoReconnectPeriod,
+ thing.getUID(), config.getResponseTimeout().intValue(), config.getReadingPause().intValue(),
+ config.getReadRetriesLimit().intValue(), getScheduler(), this);
client.initialize();
}
diff --git a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/SerialBridgeThingHandler.java b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/SerialBridgeThingHandler.java
index 7bf87845c9200..a8a8156e90949 100644
--- a/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/SerialBridgeThingHandler.java
+++ b/bundles/org.openhab.binding.knx/src/main/java/org/openhab/binding/knx/internal/handler/SerialBridgeThingHandler.java
@@ -36,7 +36,7 @@ public class SerialBridgeThingHandler extends KNXBridgeBaseThingHandler {
public SerialBridgeThingHandler(Bridge bridge) {
super(bridge);
SerialBridgeConfiguration config = getConfigAs(SerialBridgeConfiguration.class);
- client = new SerialClient(config.getAutoReconnectPeriod().intValue(), thing.getUID(),
+ client = new SerialClient(config.getAutoReconnectPeriod(), thing.getUID(),
config.getResponseTimeout().intValue(), config.getReadingPause().intValue(),
config.getReadRetriesLimit().intValue(), getScheduler(), config.getSerialPort(), this);
}
diff --git a/bundles/org.openhab.binding.knx/src/main/resources/ESH-INF/thing/ip.xml b/bundles/org.openhab.binding.knx/src/main/resources/ESH-INF/thing/ip.xml
index 9d78057509c40..3a0932b8768fe 100644
--- a/bundles/org.openhab.binding.knx/src/main/resources/ESH-INF/thing/ip.xml
+++ b/bundles/org.openhab.binding.knx/src/main/resources/ESH-INF/thing/ip.xml
@@ -60,9 +60,9 @@
Limits the read retries while initialization from the KNX bus3
-
+
- Seconds between connection retries when KNX link has been lost, 0 means never retry
+ Seconds between connection retries when KNX link has been lost, 0 means never retry, minimum 30s60
diff --git a/bundles/org.openhab.binding.kodi/src/main/java/org/openhab/binding/kodi/internal/protocol/KodiClientSocket.java b/bundles/org.openhab.binding.kodi/src/main/java/org/openhab/binding/kodi/internal/protocol/KodiClientSocket.java
index ef063ba0a70b3..0f4e37086779f 100644
--- a/bundles/org.openhab.binding.kodi/src/main/java/org/openhab/binding/kodi/internal/protocol/KodiClientSocket.java
+++ b/bundles/org.openhab.binding.kodi/src/main/java/org/openhab/binding/kodi/internal/protocol/KodiClientSocket.java
@@ -21,6 +21,7 @@
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
+import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
@@ -160,6 +161,12 @@ public void onClose(int statusCode, String reason) {
});
}
}
+
+ @OnWebSocketError
+ public void onError(Throwable error) {
+ onClose(0, error.getMessage());
+ }
+
}
private void sendMessage(String str) throws IOException {
diff --git a/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/KonnectedHandlerFactory.java b/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/KonnectedHandlerFactory.java
index 4306699d187da..7b4cdc2d7da1c 100644
--- a/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/KonnectedHandlerFactory.java
+++ b/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/KonnectedHandlerFactory.java
@@ -18,6 +18,8 @@
import java.util.Dictionary;
import java.util.Set;
+import javax.servlet.ServletException;
+
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.net.HttpServiceUtil;
import org.eclipse.smarthome.core.net.NetworkAddressService;
@@ -33,6 +35,7 @@
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,6 +49,8 @@
public class KonnectedHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(KonnectedHandlerFactory.class);
private static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_MODULE);
+ private static final String alias = "/" + BINDING_ID;
+
private HttpService httpService;
private String callbackUrl = null;
private NetworkAddressService networkAddressService;
@@ -61,25 +66,26 @@ protected void activate(ComponentContext componentContext) {
super.activate(componentContext);
Dictionary properties = componentContext.getProperties();
callbackUrl = (String) properties.get("callbackUrl");
- KonnectedHTTPServlet servlet = registerWebHookServlet();
- this.servlet = servlet;
+ try {
+ this.servlet = registerWebHookServlet();
+ } catch (KonnectedWebHookFail e) {
+ logger.error("Failed registering Konnected servlet - binding is not functional!", e);
+ }
}
@Override
protected void deactivate(ComponentContext componentContext) {
super.deactivate(componentContext);
- servlet.deactivate();
+ httpService.unregister(alias);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
KonnectedHandler thingHandler = new KonnectedHandler(thing, '/' + BINDING_ID, createCallbackUrl(),
createCallbackPort());
- logger.debug("Adding thinghandler for thing {} to webhook.", thing.getUID().getId());
- try {
+ if (servlet != null) {
+ logger.debug("Adding thinghandler for thing {} to webhook.", thing.getUID().getId());
servlet.add(thingHandler);
- } catch (KonnectedWebHookFail e) {
- logger.trace("there was an error adding the thing handler to the servlet: {}", e.getMessage());
}
return thingHandler;
}
@@ -94,11 +100,14 @@ protected void removeHandler(ThingHandler thingHandler) {
super.removeHandler(thingHandler);
}
- private KonnectedHTTPServlet registerWebHookServlet() {
- KonnectedHTTPServlet servlet = null;
- String configCallBack = '/' + BINDING_ID;
- servlet = new KonnectedHTTPServlet(httpService, configCallBack);
- return servlet;
+ private KonnectedHTTPServlet registerWebHookServlet() throws KonnectedWebHookFail {
+ KonnectedHTTPServlet servlet = new KonnectedHTTPServlet();
+ try {
+ httpService.registerServlet(alias, servlet, null, httpService.createDefaultHttpContext());
+ return servlet;
+ } catch (ServletException | NamespaceException e) {
+ throw new KonnectedWebHookFail("Could not start Konnected Webhook servlet: " + e.getMessage(), e);
+ }
}
@Reference
diff --git a/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/servlet/KonnectedHTTPServlet.java b/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/servlet/KonnectedHTTPServlet.java
index a183d97c17b90..966cfc52a2cb3 100644
--- a/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/servlet/KonnectedHTTPServlet.java
+++ b/bundles/org.openhab.binding.konnected/src/main/java/org/openhab/binding/konnected/internal/servlet/KonnectedHTTPServlet.java
@@ -16,15 +16,12 @@
import java.util.HashMap;
import java.util.Scanner;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openhab.binding.konnected.internal.gson.KonnectedModuleGson;
import org.openhab.binding.konnected.internal.handler.KonnectedHandler;
-import org.osgi.service.http.HttpService;
-import org.osgi.service.http.NamespaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,57 +41,20 @@ public class KonnectedHTTPServlet extends HttpServlet {
private static final String CHARSET = "utf-8";
private final Gson gson = new Gson();
- private final HttpService httpService;
-
- private final String path;
private HashMap konnectedThingHandlers = new HashMap<>();
- public KonnectedHTTPServlet(HttpService httpService, String id) {
- this.httpService = httpService;
- this.path = id;
+ public KonnectedHTTPServlet() {
}
- public void add(KonnectedHandler thingHandler) throws KonnectedWebHookFail {
+ public void add(KonnectedHandler thingHandler) {
logger.trace("Adding KonnectedHandler[{}] to KonnectedHTTPServlet.", thingHandler.getThing().getUID());
-
- if (konnectedThingHandlers.size() == 0) {
- this.activate();
- }
-
konnectedThingHandlers.put(thingHandler.getThing().getUID().getAsString(), thingHandler);
}
public void remove(KonnectedHandler thingHandler) {
- logger.trace("Removing KonnectedHandler [{}] from KonnectedHTTP Servlet. ", thingHandler.getThing().getUID());
+ logger.trace("Removing KonnectedHandler [{}] from KonnectedHTTPServlet. ", thingHandler.getThing().getUID());
konnectedThingHandlers.remove(thingHandler.getThing().getUID().getAsString());
-
- if (konnectedThingHandlers.size() == 0) {
- this.deactivate();
- }
- }
-
- /**
- * Activation callback.
- *
- * @param config Service config.
- **/
- public void activate() throws KonnectedWebHookFail {
- try {
- logger.debug("Trying to Start Webhook at {}.", path);
- httpService.registerServlet(path, this, null, httpService.createDefaultHttpContext());
- logger.debug("Started Konnected Webhook servlet at {}", path);
- } catch (ServletException | NamespaceException e) {
- throw new KonnectedWebHookFail("Could not start Konnected Webhook servlet: " + e.getMessage(), e);
- }
- }
-
- /**
- * Webhook Deactivation callback.
- */
- public void deactivate() {
- httpService.unregister(path);
- logger.debug("Konnected webhook servlet stopped");
}
@Override
@@ -140,7 +100,4 @@ private void setHeaders(HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
}
- public String getPath() {
- return path;
- }
}
diff --git a/bundles/org.openhab.binding.lgwebos/README.md b/bundles/org.openhab.binding.lgwebos/README.md
index e7e1819371d2f..74a52303ce2fe 100644
--- a/bundles/org.openhab.binding.lgwebos/README.md
+++ b/bundles/org.openhab.binding.lgwebos/README.md
@@ -47,7 +47,7 @@ Please note that at least one channel must be bound to an item before the bindin
| power | Switch | Current power setting. TV can only be powered off, not on. | RW |
| mute | Switch | Current mute setting. | RW |
| volume | Dimmer | Current volume setting. Setting and reporting absolute percent values only works when using internal speakers. When connected to an external amp, the volume should be controlled using increase and decrease commands. | RW |
-| channel | Number | Current channel number. | RW |
+| channel | String | Current channel number. | RW |
| channelName | String | Current channel name. | R |
| toast | String | Displays a short message on the TV screen. See also rules section. | W |
| mediaPlayer | Player | Media control player | W |
@@ -76,9 +76,9 @@ Switch LG_TV0_Power "TV Power" { autoupdate="false", channel="lgwe
Switch LG_TV0_Mute "TV Mute" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:mute"}
Dimmer LG_TV0_Volume "Volume [%S]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:volume" }
Number LG_TV0_VolDummy "VolumeUpDown"
-Number LG_TV0_ChannelNo "Channel [%d]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:channel" }
+String LG_TV0_Channel "Channel [%d]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:channel" }
Number LG_TV0_ChannelDummy "ChannelUpDown"
-String LG_TV0_Channel "Channel [%S]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:channelName"}
+String LG_TV0_ChannelName "Channel [%S]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:channelName"}
String LG_TV0_Toast { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:toast"}
Switch LG_TV0_Stop "Stop" { autoupdate="false", channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:mediaStop" }
String LG_TV0_Application "Application [%s]" { channel="lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46:appLauncher"}
@@ -98,9 +98,9 @@ sitemap demo label="Main Menu"
Switch item=LG_TV0_Mute
Text item=LG_TV0_Volume
Switch item=LG_TV0_VolDummy icon="soundvolume" label="Volume" mappings=[1="â–²", 0="â–¼"]
- Text item=LG_TV0_ChannelNo
- Switch item=LG_TV0_ChannelDummy icon="television" label="Channel" mappings=[1="â–²", 0="â–¼"]
Text item=LG_TV0_Channel
+ Switch item=LG_TV0_ChannelDummy icon="television" label="Channel" mappings=[1="â–²", 0="â–¼"]
+ Text item=LG_TV0_ChannelName
Default item=LG_TV0_Player
Text item=LG_TV0_Application
Selection item=LG_TV0_Application mappings=[
@@ -147,10 +147,15 @@ end
rule "ChannelUpDown"
when Item LG_TV0_ChannelDummy received command
then
- var currentChannel = LG_TV0_ChannelNo.state as DecimalType
+ val actions = getActions("lgwebos","lgwebos:WebOSTV:3aab9eea-953b-4272-bdbd-f0cd0ecf4a46")
+ if(null === actions) {
+ logInfo("actions", "Actions not found, check thing ID")
+ return
+ }
+
switch receivedCommand{
- case 0: LG_TV0_ChannelNo.sendCommand(currentChannel - 1)
- case 1: LG_TV0_ChannelNo.sendCommand(currentChannel + 1)
+ case 0: actions.decreaseChannel()
+ case 1: actions.increaseChannel()
}
end
```
diff --git a/bundles/org.openhab.binding.lgwebos/pom.xml b/bundles/org.openhab.binding.lgwebos/pom.xml
index 59e6a34519d6a..0611a0341a039 100644
--- a/bundles/org.openhab.binding.lgwebos/pom.xml
+++ b/bundles/org.openhab.binding.lgwebos/pom.xml
@@ -27,8 +27,8 @@
provided
- org.java-websocket
- java-websocket
+ org.openhab.osgiify
+ org.java-websocket.java-websocket1.3.2provided
diff --git a/bundles/org.openhab.binding.lgwebos/src/main/feature/feature.xml b/bundles/org.openhab.binding.lgwebos/src/main/feature/feature.xml
index c4a5bf5bc85f6..b38e6a708ae15 100644
--- a/bundles/org.openhab.binding.lgwebos/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.lgwebos/src/main/feature/feature.xml
@@ -4,12 +4,11 @@
openhab-runtime-base
- wrapmvn:org.apache.httpcomponents/httpcore-osgi/4.4.4mvn:org.apache.httpcomponents/httpclient-osgi/4.5.2mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xpp3/1.1.4c_7mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.json/20140107_1
- wrap:mvn:org.java-websocket/java-websocket/1.3.2$Bundle-Name=Java%20Websocket%20Client&Bundle-SymbolicName=org.java-websocket.java-websocket&Bundle-Version=1.3.2
+ mvn:org.openhab.osgiify/org.java-websocket.java-websocket/1.3.2mvn:org.openhab.addons.bundles/org.openhab.binding.lgwebos/${project.version}
diff --git a/bundles/org.openhab.binding.lgwebos/src/main/java/org/openhab/binding/lgwebos/internal/TVControlChannel.java b/bundles/org.openhab.binding.lgwebos/src/main/java/org/openhab/binding/lgwebos/internal/TVControlChannel.java
index a106f3cef2b23..2972702ba3837 100644
--- a/bundles/org.openhab.binding.lgwebos/src/main/java/org/openhab/binding/lgwebos/internal/TVControlChannel.java
+++ b/bundles/org.openhab.binding.lgwebos/src/main/java/org/openhab/binding/lgwebos/internal/TVControlChannel.java
@@ -20,7 +20,7 @@
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.smarthome.core.library.types.DecimalType;
+import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.lgwebos.internal.handler.LGWebOSHandler;
import org.slf4j.Logger;
@@ -121,7 +121,7 @@ public void onSuccess(@Nullable ChannelInfo channelInfo) {
if (channelInfo == null) {
return;
}
- handler.postUpdate(channelId, new DecimalType(channelInfo.getNumber()));
+ handler.postUpdate(channelId, new StringType(channelInfo.getNumber()));
}
}));
} else {
diff --git a/bundles/org.openhab.binding.lgwebos/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.lgwebos/src/main/resources/ESH-INF/thing/thing-types.xml
index 82a51ca67a5d5..2aa85d71c9e63 100644
--- a/bundles/org.openhab.binding.lgwebos/src/main/resources/ESH-INF/thing/thing-types.xml
+++ b/bundles/org.openhab.binding.lgwebos/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -44,10 +44,9 @@
- Number
+ StringCurrent Channel
- String
diff --git a/bundles/org.openhab.binding.mcp23017/pom.xml b/bundles/org.openhab.binding.mcp23017/pom.xml
index d5e92972a6605..16e031aa3ece0 100644
--- a/bundles/org.openhab.binding.mcp23017/pom.xml
+++ b/bundles/org.openhab.binding.mcp23017/pom.xml
@@ -21,8 +21,8 @@
provided
- com.pi4j
- pi4j-gpio-extension
+ org.openhab.osgiify
+ com.pi4j.pi4j-gpio-extension1.2provided
diff --git a/bundles/org.openhab.binding.mcp23017/src/main/feature/feature.xml b/bundles/org.openhab.binding.mcp23017/src/main/feature/feature.xml
index f643940b10590..f4c2ad6f8a390 100644
--- a/bundles/org.openhab.binding.mcp23017/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.mcp23017/src/main/feature/feature.xml
@@ -4,9 +4,8 @@
openhab-runtime-base
- wrapmvn:com.pi4j/pi4j-core/1.2
- wrap:mvn:com.pi4j/pi4j-gpio-extension/1.2$Bundle-Name=Pi4J%20::%20Java%20Library%20(Extension)&Bundle-SymbolicName=com.pi4j.pi4j-gpio-extension&Bundle-Version=1.2
+ mvn:org.openhab.osgiify/com.pi4j.pi4j-gpio-extension/1.2mvn:org.openhab.addons.bundles/org.openhab.binding.mcp23017/${project.version}
diff --git a/bundles/org.openhab.binding.milight/README.md b/bundles/org.openhab.binding.milight/README.md
index 953bd3d201262..284ee01333d89 100644
--- a/bundles/org.openhab.binding.milight/README.md
+++ b/bundles/org.openhab.binding.milight/README.md
@@ -19,7 +19,7 @@ RGB/White from 2014 and the new generation RGB/White from 2016 as well as RGB/Co
| RGB/Cold,Warmwhite | | ✓ | ✓ |
Please note that LD382, LD382A, LD686 RGB stripes and bulbs are supported by the
-[WifiLed Binding](https://github.com/openhab/openhab2-addons/blob/master/addons/binding/org.openhab.binding.wifiled/README.md).
+[WifiLed Binding](https://www.openhab.org/addons/bindings/wifiled/).
## Discovery
diff --git a/bundles/org.openhab.binding.minecraft/pom.xml b/bundles/org.openhab.binding.minecraft/pom.xml
index cce7fe4d9cdd3..4f422e5cc82ac 100644
--- a/bundles/org.openhab.binding.minecraft/pom.xml
+++ b/bundles/org.openhab.binding.minecraft/pom.xml
@@ -21,8 +21,8 @@
provided
- com.firebase
- tubesock
+ org.openhab.osgiify
+ com.firebase.tubesock0.0.1provided
diff --git a/bundles/org.openhab.binding.minecraft/src/main/feature/feature.xml b/bundles/org.openhab.binding.minecraft/src/main/feature/feature.xml
index 111ab213f2320..2349095af24ad 100644
--- a/bundles/org.openhab.binding.minecraft/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.minecraft/src/main/feature/feature.xml
@@ -5,9 +5,8 @@
openhab-runtime-baseopenhab-transport-mdns
- wrapmvn:io.reactivex/rxjava/1.1.7
- wrap:mvn:com.firebase/tubesock/0.0.1$Bundle-Name=TubeSock&Bundle-SymbolicName=com.firebase.tubesock&Bundle-Version=0.0.1
+ mvn:org.openhab.osgiify/com.firebase.tubesock/0.0.1mvn:org.openhab.addons.bundles/org.openhab.binding.minecraft/${project.version}
diff --git a/bundles/org.openhab.binding.netatmo/pom.xml b/bundles/org.openhab.binding.netatmo/pom.xml
index 88a5e4d90e147..956261f9ff3a8 100644
--- a/bundles/org.openhab.binding.netatmo/pom.xml
+++ b/bundles/org.openhab.binding.netatmo/pom.xml
@@ -15,26 +15,26 @@
- org.json
- json
+ org.openhab.osgiify
+ org.json.json20131018provided
- com.squareup.okhttp
- okhttp
+ org.openhab.osgiify
+ com.squareup.okhttp.okhttp2.3.0provided
- com.squareup.okio
- okio
+ org.openhab.osgiify
+ com.squareup.okio.okio-1.3.01.3.0provided
- com.squareup.retrofit
- retrofit
+ org.openhab.osgiify
+ com.squareup.retrofit.retrofit1.9.0provided
diff --git a/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml b/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml
index 515469ba1b68b..e13aba74cc1a2 100644
--- a/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.netatmo/src/main/feature/feature.xml
@@ -4,11 +4,10 @@
openhab-runtime-base
- wrap
- wrap:mvn:org.json/json/20131018$Bundle-Name=JSON%20in%20Java&Bundle-SymbolicName=org.json.json&Bundle-Version=20131018
- wrap:mvn:com.squareup.okhttp/okhttp/2.3.0$Bundle-Name=OkHttp&Bundle-SymbolicName=com.squareup.okhttp&Bundle-Version=2.3.0
- wrap:mvn:com.squareup.okio/okio/1.3.0$Bundle-Name=Okio&Bundle-SymbolicName=com.squareup.okio&Bundle-Version=1.3.0
- wrap:mvn:com.squareup.retrofit/retrofit/1.9.0$Bundle-Name=Retrofit&Bundle-SymbolicName=com.squareup.retrofit&Bundle-Version=1.9.0
+ mvn:org.openhab.osgiify/org.json.json/20131018
+ mvn:org.openhab.osgiify/com.squareup.okhttp.okhttp/2.3.0
+ mvn:org.openhab.osgiify/com.squareup.okio.okio-1.3.0/1.3.0
+ mvn:org.openhab.osgiify/com.squareup.retrofit.retrofit/1.9.0mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.client/1.0.0mvn:org.apache.oltu.oauth2/org.apache.oltu.oauth2.common/1.0.0mvn:org.openhab.addons.bundles/org.openhab.binding.netatmo/${project.version}
diff --git a/bundles/org.openhab.binding.network/pom.xml b/bundles/org.openhab.binding.network/pom.xml
index e64e7ce53955c..464429cd866d9 100644
--- a/bundles/org.openhab.binding.network/pom.xml
+++ b/bundles/org.openhab.binding.network/pom.xml
@@ -15,14 +15,14 @@
- fr.bmartel
- jspeedtest
+ org.openhab.osgiify
+ fr.bmartel.jspeedtest1.32.1provided
- fr.bmartel
- http-endec
+ org.openhab.osgiify
+ fr.bmartel.http-endec1.04provided
diff --git a/bundles/org.openhab.binding.network/src/main/feature/feature.xml b/bundles/org.openhab.binding.network/src/main/feature/feature.xml
index a54db3044e819..9e59c06a301f0 100644
--- a/bundles/org.openhab.binding.network/src/main/feature/feature.xml
+++ b/bundles/org.openhab.binding.network/src/main/feature/feature.xml
@@ -5,10 +5,9 @@
openhab-runtime-baseopenhab-core-model-script
- wrap
- mvn:commons-net/commons-net/3.6
- wrap:mvn:fr.bmartel/jspeedtest/1.32.1$Bundle-Name=Speed%20Test%20library%20for%20Java&Bundle-SymbolicName=fr.bmartel.jspeedtest&Bundle-Version=1.32.1
- wrap:mvn:fr.bmartel/http-endec/1.04$Bundle-Name=http-endec&Bundle-SymbolicName=fr.bmartel.http-endec&Bundle-Version=1.04
+ mvn:commons-net/commons-net/3.6
+ mvn:org.openhab.osgiify/fr.bmartel.jspeedtest/1.32.1
+ mvn:org.openhab.osgiify/fr.bmartel.http-endec/1.04mvn:org.openhab.addons.bundles/org.openhab.binding.network/${project.version}
diff --git a/bundles/org.openhab.binding.network/src/test/java/org/openhab/binding/network/internal/dhcp/DHCPTest.java b/bundles/org.openhab.binding.network/src/test/java/org/openhab/binding/network/internal/dhcp/DHCPTest.java
index 64ae230462a34..19b4d802e61fb 100644
--- a/bundles/org.openhab.binding.network/src/test/java/org/openhab/binding/network/internal/dhcp/DHCPTest.java
+++ b/bundles/org.openhab.binding.network/src/test/java/org/openhab/binding/network/internal/dhcp/DHCPTest.java
@@ -14,6 +14,7 @@
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
@@ -34,7 +35,9 @@ public class DHCPTest {
public void testService() throws SocketException {
String testIP = "10.1.2.3";
IPRequestReceivedCallback dhcpListener = mock(IPRequestReceivedCallback.class);
- assertThat(DHCPListenService.instance, is(nullValue()));
+
+ // if this is not the case this test is not very useful, we don't always have the static field under control.
+ assumeTrue(DHCPListenService.instance == null);
DHCPListenService.register(testIP, dhcpListener);
assertThat(DHCPListenService.instance, is(notNullValue()));
DHCPListenService.unregister(testIP);
diff --git a/bundles/org.openhab.binding.onkyo/README.md b/bundles/org.openhab.binding.onkyo/README.md
index d085a1fc4712d..e9d409d85b4cb 100644
--- a/bundles/org.openhab.binding.onkyo/README.md
+++ b/bundles/org.openhab.binding.onkyo/README.md
@@ -42,6 +42,7 @@ At the moment only the following models are supported:
- TX-NR818
- TX-NR828
- TX-NR838
+- TX-NR3007
## Binding Configuration
diff --git a/bundles/org.openhab.binding.onkyo/src/main/java/org/openhab/binding/onkyo/internal/OnkyoBindingConstants.java b/bundles/org.openhab.binding.onkyo/src/main/java/org/openhab/binding/onkyo/internal/OnkyoBindingConstants.java
index 36c6d285f172a..d59376366931e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/java/org/openhab/binding/onkyo/internal/OnkyoBindingConstants.java
+++ b/bundles/org.openhab.binding.onkyo/src/main/java/org/openhab/binding/onkyo/internal/OnkyoBindingConstants.java
@@ -59,6 +59,7 @@ public class OnkyoBindingConstants {
public static final String ONKYO_TYPE_TXNR818 = "TX-NR818";
public static final String ONKYO_TYPE_TXNR828 = "TX-NR828";
public static final String ONKYO_TYPE_TXNR838 = "TX-NR838";
+ public static final String ONKYO_TYPE_TXNR3007 = "TX-NR3007";
// Extend this set with all successfully tested models
public static final Set SUPPORTED_DEVICE_MODELS = Stream
@@ -66,7 +67,8 @@ public class OnkyoBindingConstants {
ONKYO_TYPE_TXNR535, ONKYO_TYPE_TXNR555, ONKYO_TYPE_TXNR575, ONKYO_TYPE_TXNR575E, ONKYO_TYPE_TXNR616,
ONKYO_TYPE_TXNR626, ONKYO_TYPE_TXNR636, ONKYO_TYPE_TXNR646, ONKYO_TYPE_TXNR656, ONKYO_TYPE_TXNR676,
ONKYO_TYPE_TXNR686, ONKYO_TYPE_TXNR708, ONKYO_TYPE_TXNR717, ONKYO_TYPE_TXNR727, ONKYO_TYPE_TXNR737,
- ONKYO_TYPE_TXNR747, ONKYO_TYPE_TXNR757, ONKYO_TYPE_TXNR818, ONKYO_TYPE_TXNR828, ONKYO_TYPE_TXNR838)
+ ONKYO_TYPE_TXNR747, ONKYO_TYPE_TXNR757, ONKYO_TYPE_TXNR818, ONKYO_TYPE_TXNR828, ONKYO_TYPE_TXNR838,
+ ONKYO_TYPE_TXNR3007)
.collect(Collectors.toSet());
// List of all Thing Type UIDs
@@ -99,6 +101,7 @@ public class OnkyoBindingConstants {
public static final ThingTypeUID THING_TYPE_TXNR818 = new ThingTypeUID(BINDING_ID, ONKYO_TYPE_TXNR818);
public static final ThingTypeUID THING_TYPE_TXNR828 = new ThingTypeUID(BINDING_ID, ONKYO_TYPE_TXNR828);
public static final ThingTypeUID THING_TYPE_TXNR838 = new ThingTypeUID(BINDING_ID, ONKYO_TYPE_TXNR838);
+ public static final ThingTypeUID THING_TYPE_TXNR3007 = new ThingTypeUID(BINDING_ID, ONKYO_TYPE_TXNR3007);
public static final Set SUPPORTED_THING_TYPES_UIDS = Stream
.of(THING_TYPE_ONKYOAV, THING_TYPE_ONKYO_UNSUPPORTED, THING_TYPE_HTRC560, THING_TYPE_TXNR414, THING_TYPE_TXNR474,
@@ -106,7 +109,7 @@ public class OnkyoBindingConstants {
THING_TYPE_TXNR575E, THING_TYPE_TXNR616, THING_TYPE_TXNR626, THING_TYPE_TXNR636, THING_TYPE_TXNR646,
THING_TYPE_TXNR656, THING_TYPE_TXNR676, THING_TYPE_TXNR686, THING_TYPE_TXNR708, THING_TYPE_TXNR717,
THING_TYPE_TXNR727, THING_TYPE_TXNR737, THING_TYPE_TXNR747, THING_TYPE_TXNR757, THING_TYPE_TXNR818,
- THING_TYPE_TXNR828, THING_TYPE_TXNR838)
+ THING_TYPE_TXNR828, THING_TYPE_TXNR838, THING_TYPE_TXNR3007)
.collect(Collectors.toSet());
// List of thing parameters names
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/ht-rc560.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/ht-rc560.xml
index 3fe73bb4b94d9..fb74846def4ca 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/ht-rc560.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/ht-rc560.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/onkyoAVR.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/onkyoAVR.xml
index 9ba8731f82f9c..711136acfba98 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/onkyoAVR.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/onkyoAVR.xml
@@ -6,7 +6,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr3007.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr3007.xml
new file mode 100644
index 0000000000000..624190a219219
--- /dev/null
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr3007.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Network enabled Onkyo AV Receiver
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr414.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr414.xml
index ab665c0664396..480fc1a2fc210 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr414.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr414.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr474.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr474.xml
index 2bd79cb618b8b..cb1f5d2b57d6c 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr474.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr474.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr509.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr509.xml
index 0bab81f5fcdf5..b573c4ed36f4e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr509.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr509.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr515.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr515.xml
index f0bbe10f9d324..5e42e4ea03fe4 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr515.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr515.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr525.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr525.xml
index e58f788156359..1902e8b787642 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr525.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr525.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr535.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr535.xml
index eabd6fd0d7602..1894b6d3cb0f4 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr535.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr535.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr545.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr545.xml
index de968774158c8..271dad2781909 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr545.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr545.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr555.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr555.xml
index cba6625e9ea35..8071b87451b5d 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr555.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr555.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575.xml
index 12d44b95248a2..f17ca0ff264a3 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575e.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575e.xml
index 19e1193032ede..c24b3ef17964e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575e.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr575e.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr616.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr616.xml
index 5fb6d183f95e8..4ddca4779a923 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr616.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr616.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr626.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr626.xml
index 85cb05989a60a..254551da3fa42 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr626.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr626.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr636.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr636.xml
index 494d937009727..af65f7a1ca0a7 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr636.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr636.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr646.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr646.xml
index 95290d658ed74..aacc14266186b 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr646.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr646.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr656.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr656.xml
index 82b83089b0ea6..9d05b5dad9ffa 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr656.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr656.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr676.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr676.xml
index 06ac5e4674a45..9f36ee2c5784e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr676.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr676.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr686.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr686.xml
index 3c5060a8364ad..25208ddb0e74f 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr686.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr686.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr708.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr708.xml
index a7c55d6841852..11a4303a63ad5 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr708.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr708.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr717.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr717.xml
index 2ba2cf9953113..89da3644832b6 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr717.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr717.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr727.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr727.xml
index 7966d64b9d921..e51c3b6603a86 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr727.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr727.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr737.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr737.xml
index 2cb73dd602abe..edbf382442e3e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr737.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr737.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr747.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr747.xml
index 9bc44b17d958c..7561a9427ff34 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr747.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr747.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr818.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr818.xml
index bbf544a80087f..dcb1e889fe000 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr818.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr818.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr828.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr828.xml
index 3fb2bf53df5f6..ef5323e048ab3 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr828.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr828.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr838.xml b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr838.xml
index 438d2d82cbeda..77a56cbc1ec5e 100644
--- a/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr838.xml
+++ b/bundles/org.openhab.binding.onkyo/src/main/resources/ESH-INF/thing/tx-nr838.xml
@@ -5,7 +5,7 @@
- Network enabled Onkyo AV Receivers
+ Network enabled Onkyo AV Receiver
diff --git a/bundles/org.openhab.binding.pushbullet/.classpath b/bundles/org.openhab.binding.pushbullet/.classpath
new file mode 100644
index 0000000000000..a5d95095ccaaf
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bundles/.project b/bundles/org.openhab.binding.pushbullet/.project
similarity index 62%
rename from bundles/.project
rename to bundles/org.openhab.binding.pushbullet/.project
index b4bb9f9000def..89f11546d5550 100644
--- a/bundles/.project
+++ b/bundles/org.openhab.binding.pushbullet/.project
@@ -1,10 +1,15 @@
- org.openhab.addons.reactor.bundles
+ org.openhab.binding.pushbullet
+
+ org.eclipse.jdt.core.javabuilder
+
+
+ org.eclipse.m2e.core.maven2Builder
@@ -12,6 +17,7 @@
+ org.eclipse.jdt.core.javanatureorg.eclipse.m2e.core.maven2Nature
diff --git a/bundles/org.openhab.binding.pushbullet/NOTICE b/bundles/org.openhab.binding.pushbullet/NOTICE
new file mode 100644
index 0000000000000..4c20ef446c1e4
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/NOTICE
@@ -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/openhab2-addons
diff --git a/bundles/org.openhab.binding.pushbullet/README.md b/bundles/org.openhab.binding.pushbullet/README.md
new file mode 100644
index 0000000000000..57799d9593021
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/README.md
@@ -0,0 +1,158 @@
+# Pushbullet Binding
+
+The Pushbullet binding allows you to notify iOS, Android & Windows 10 Phone & Desktop devices of a message using the Pushbullet API web service.
+
+## Supported Things
+
+This binding supports a generic "bot" which is a representation of the client.
+
+## Discovery
+
+This binding provides no discovery.
+The desired bots must be configured manually or via a things file.
+
+## Binding Configuration
+
+The binding has no configuration options itself, all configuration is done at 'Things' level.
+
+## Thing Configuration
+
+### Bot (`bot`)
+
+The bot thing is used to send messages to other recipients.
+It has the following parameters:
+
+| Config | Description | Required | Advanced |
+|------------|------------------------------------------------------------------|----------|----------|
+| token | Pushbullet [API token](#obtaining-an-api-key) to send to devices | Yes | False |
+| name | Explicit Name, for later use when the bot can receive messages | No | True |
+| apiUrlBase | Address of own Pushbullet server, for testing purposes | No | True |
+
+```java
+Thing pushbullet:bot:r2d2 "R2D2" @ "Somewhere" [ token = "verysecretwonttellyou" ]
+
+```
+
+## Channels
+
+| Channel ID | Channel Description | Supported item type | Advanced |
+|------------|-------------------------------------------------|----------------------|----------|
+| recipient | for later use when the bot can receive messages | String | False |
+| title | for later use when the bot can receive messages | String | False |
+| message | for later use when the bot can receive messages | String | False |
+
+## Rule Action
+
+This binding includes rule actions for sending notes.
+Two different actions available:
+
+* `sendPushbulletNote(String recipient, String messsage)`
+* `sendPushbulletNote(String recipient, String title, String messsage)`
+
+Since there is a separate rule action instance for each `bot` thing, this needs to be retrieved through `getActions(scope, thingUID)`.
+The first parameter always has to be `pushbullet` and the second is the full Thing UID of the bot that should be used.
+Once this action instance is retrieved, you can invoke the action method on it.
+
+Examples:
+
+```
+val actions = getActions("pushbullet", "pushbullet:bot:r2d2")
+val result = actions.sendPushbulletNote("someone@example.com", "R2D2 talks here...", "This is the pushed note.")
+```
+
+## Full Example
+
+_Provide a full usage example based on textual configuration files (*.things, *.items, *.sitemap)._
+
+pushbullet.things:
+
+```java
+Thing pushbullet:bot:r2d2 "R2D2" @ "Somewhere" [ token = "verysecretwonttellyou" ]
+
+```
+
+pushbullet.items
+
+```java
+Switch Pushbullet_R2D2_Button "Pushbullet Action bot R2D2"
+```
+
+pushbullet.sitemap
+
+```java
+sitemap pushbullet label="Pushbullet"
+{
+ Switch item=Pushbullet_R2D2_Button
+}
+```
+
+pushbullet.rules
+
+```java
+rule "Pushbullet R2D2 changed"
+when
+ Item Pushbullet_R2D2_Button changed
+then
+ logInfo(filename, "Button R2D2 changed - OH2...")
+
+ if (Pushbullet_R2D2_Button.state == ON)
+ {
+ sendCommand(Pushbullet_R2D2_Button, OFF)
+
+ val actions = getActions("pushbullet", "pushbullet:bot:r2d2")
+ logInfo(filename, "Actions for 'R2D2' are: " + actions)
+
+ if (actions != null)
+ {
+ val result = actions.sendPushbulletNote("someone@example.com", "Title R2D2 OH2", "This has been sent by the new R2D2 bot")
+ logInfo(filename, "Result of send action is: " + result)
+ }
+ }
+end
+```
+
+## Creating an account for your bot(s)
+
+The pushbullet accounts are bound to either Google or Facebook accounts.
+
+- Create a bot account with either Facebook or Google
+- Go to ""
+- Chose to either "Sign up with Google" or "Sign up with Facebook".
+- Complete the signup process as guided by the pushbullet web site.
+- Continue with "Obtaining an API key".
+
+## Obtaining an API key
+
+The API keys are bound to the pushbullet account.
+
+- Go to the pushbullet site.
+- Log in with either your personal account or the one you created for your bot.
+- Go to ""
+- Click on "Create Access Token".
+- Copy the token created on the site.
+
+You must at least provide an API token (Private or Alias Key from Pushbullet.com) and a message in some manner before a message can be pushed.
+All other parameters are optional.
+If you use an alias key, the parameters (device, icon, sound, vibration) are overwritten by the alias setting on pushbullet.
+
+## Rate limits
+
+As of 2019, free accounts have a limit of 100 pushes per month.
+This action does not evaluate the rate limiting headers though.
+
+## Translation
+
+This project is being translated on transifex.
+If you want to help, please join the project at the URL:
+
+- https://www.transifex.com/hakan42/openhab-binding-pushbullet/dashboard/
+
+## Libraries
+
+This action has been written without using libraries as jpushbullet or jpushbullet2.
+Both of those libraries use various libraries themselves which makes integrating them into openHAB a challenge.
+
+## pushbullet API
+
+-
+-
diff --git a/bundles/org.openhab.binding.pushbullet/pom.xml b/bundles/org.openhab.binding.pushbullet/pom.xml
new file mode 100644
index 0000000000000..f7d2623e8c3f2
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/pom.xml
@@ -0,0 +1,25 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 2.5.0-SNAPSHOT
+
+
+ org.openhab.binding.pushbullet
+
+ openHAB Add-ons :: Bundles :: Pushbullet Binding
+
+
+
+ javax.mail
+ mail
+ 1.4.7
+ provided
+
+
+
+
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/feature/feature.xml b/bundles/org.openhab.binding.pushbullet/src/main/feature/feature.xml
new file mode 100644
index 0000000000000..f0dfc37f14ad8
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/feature/feature.xml
@@ -0,0 +1,9 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${project.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.binding.pushbullet/${project.version}
+
+
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletBindingConstants.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletBindingConstants.java
new file mode 100644
index 0000000000000..d60d350de3423
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletBindingConstants.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * The {@link PushbulletBindingConstants} class defines common constants, which are
+ * used across the whole binding.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ */
+@NonNullByDefault
+public class PushbulletBindingConstants {
+
+ private static final String BINDING_ID = "pushbullet";
+
+ // List of all Thing Type UIDs
+ public static final ThingTypeUID THING_TYPE_BOT = new ThingTypeUID(BINDING_ID, "bot");
+
+ public static final Set SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_BOT);
+
+ // List of all Channel ids
+ public static final String RECIPIENT = "recipient";
+ public static final String TITLE = "title";
+ public static final String MESSAGE = "message";
+
+ // Binding logic constants
+ public static final String API_METHOD_PUSHES = "pushes";
+
+ public static final int TIMEOUT = 30 * 1000; // 30 seconds
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletConfiguration.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletConfiguration.java
new file mode 100644
index 0000000000000..784e4553b99fa
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletConfiguration.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * The {@link PushbulletConfiguration} class contains fields mapping thing configuration parameters.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ */
+@NonNullByDefault
+public class PushbulletConfiguration {
+
+ private @Nullable String name;
+
+ private String token = "invalid";
+
+ private String apiUrlBase = "invalid";
+
+ public @Nullable String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public String getApiUrlBase() {
+ return apiUrlBase;
+ }
+
+ public void setApiUrlBase(String apiUrlBase) {
+ this.apiUrlBase = apiUrlBase;
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletHandlerFactory.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletHandlerFactory.java
new file mode 100644
index 0000000000000..4b73f6c093613
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/PushbulletHandlerFactory.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal;
+
+import static org.openhab.binding.pushbullet.internal.PushbulletBindingConstants.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
+import org.eclipse.smarthome.core.thing.binding.ThingHandler;
+import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
+import org.openhab.binding.pushbullet.internal.handler.PushbulletHandler;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * The {@link PushbulletHandlerFactory} is responsible for creating things and thing
+ * handlers.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ */
+@NonNullByDefault
+@Component(configurationPid = "binding.pushbullet", service = ThingHandlerFactory.class)
+public class PushbulletHandlerFactory extends BaseThingHandlerFactory {
+
+ @Override
+ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
+ return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
+ }
+
+ @Override
+ protected @Nullable ThingHandler createHandler(Thing thing) {
+ ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+
+ if (THING_TYPE_BOT.equals(thingTypeUID)) {
+ return new PushbulletHandler(thing);
+ }
+
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/action/PushbulletActions.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/action/PushbulletActions.java
new file mode 100644
index 0000000000000..c8716bae1cdf1
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/action/PushbulletActions.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal.action;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.thing.binding.ThingActions;
+import org.eclipse.smarthome.core.thing.binding.ThingActionsScope;
+import org.eclipse.smarthome.core.thing.binding.ThingHandler;
+import org.openhab.binding.pushbullet.internal.handler.PushbulletHandler;
+import org.openhab.core.automation.annotation.ActionInput;
+import org.openhab.core.automation.annotation.ActionOutput;
+import org.openhab.core.automation.annotation.RuleAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link PushbulletActions} class defines rule actions for sending notifications
+ *
+ * @author Hakan Tandogan - Initial contribution
+ */
+@ThingActionsScope(name = "pushbullet")
+@NonNullByDefault
+public class PushbulletActions implements ThingActions {
+
+ private final Logger logger = LoggerFactory.getLogger(PushbulletActions.class);
+
+ private @Nullable PushbulletHandler handler;
+
+ @Override public void setThingHandler(@Nullable ThingHandler handler) {
+ this.handler = (PushbulletHandler) handler;
+ }
+
+ @Override public @Nullable ThingHandler getThingHandler() {
+ return this.handler;
+ }
+
+ @RuleAction(label = "@text/actionSendPushbulletNoteLabel", description = "@text/actionSendPushbulletNoteDesc")
+ public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendPushbulletNote(
+ @ActionInput(name = "recipient", label = "@text/actionSendPushbulletNoteInputRecipientLabel", description = "@text/actionSendPushbulletNoteInputRecipientDesc") @Nullable String recipient,
+ @ActionInput(name = "title", label = "@text/actionSendPushbulletNoteInputTitleLabel", description = "@text/actionSendPushbulletNoteInputTitleDesc") @Nullable String title,
+ @ActionInput(name = "message", label = "@text/actionSendPushbulletNoteInputMessageLabel", description = "@text/actionSendPushbulletNoteInputMessageDesc") @Nullable String message) {
+ logger.trace("sendPushbulletNote '{}', '{}', '{}'", recipient, title, message);
+
+ // Use local variable so the SAT check can do proper flow analysis
+ PushbulletHandler localHandler = handler;
+
+ if (localHandler == null) {
+ logger.warn("Pushbullet service Handler is null!");
+ return false;
+ }
+
+ return localHandler.sendPush(recipient, title, message, "note");
+ }
+
+ public static boolean sendPushbulletNote(@Nullable ThingActions actions, @Nullable String recipient,
+ @Nullable String title, @Nullable String message) {
+ if (actions instanceof PushbulletActions) {
+ return ((PushbulletActions) actions).sendPushbulletNote(recipient, title, message);
+ } else {
+ throw new IllegalArgumentException("Instance is not a PushbulletActions class ( " + actions + " )");
+ }
+ }
+
+ @RuleAction(label = "@text/actionSendPushbulletNoteLabel", description = "@text/actionSendPushbulletNoteDesc")
+ public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendPushbulletNote(
+ @ActionInput(name = "recipient", label = "@text/actionSendPushbulletNoteInputRecipientLabel", description = "@text/actionSendPushbulletNoteInputRecipientDesc") @Nullable String recipient,
+ @ActionInput(name = "message", label = "@text/actionSendPushbulletNoteInputMessageLabel", description = "@text/actionSendPushbulletNoteInputMessageDesc") @Nullable String message) {
+ logger.trace("sendPushbulletNote '{}', '{}'", recipient, message);
+
+ // Use local variable so the SAT check can do proper flow analysis
+ PushbulletHandler localHandler = handler;
+
+ if (localHandler == null) {
+ logger.warn("Pushbullet service Handler is null!");
+ return false;
+ }
+
+ return localHandler.sendPush(recipient, message, "note");
+ }
+
+ public static boolean sendPushbulletNote(@Nullable ThingActions actions, @Nullable String recipient,
+ @Nullable String message) {
+ if (actions instanceof PushbulletActions) {
+ return ((PushbulletActions) actions).sendPushbulletNote(recipient, message);
+ } else {
+ throw new IllegalArgumentException("Instance is not a PushbulletActions class ( " + actions + " )");
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/handler/PushbulletHandler.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/handler/PushbulletHandler.java
new file mode 100644
index 0000000000000..45120307b7e64
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/handler/PushbulletHandler.java
@@ -0,0 +1,229 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal.handler;
+
+import static org.openhab.binding.pushbullet.internal.PushbulletBindingConstants.*;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
+import org.eclipse.smarthome.io.net.http.HttpUtil;
+import org.openhab.binding.pushbullet.internal.action.PushbulletActions;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.Thing;
+import org.eclipse.smarthome.core.thing.ThingStatus;
+import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
+import org.eclipse.smarthome.core.types.Command;
+import org.openhab.binding.pushbullet.internal.PushbulletConfiguration;
+import org.openhab.binding.pushbullet.internal.model.Push;
+import org.openhab.binding.pushbullet.internal.model.PushResponse;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+
+/**
+ * The {@link PushbulletHandler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ */
+@NonNullByDefault
+public class PushbulletHandler extends BaseThingHandler {
+
+ private final Logger logger = LoggerFactory.getLogger(PushbulletHandler.class);
+
+ private final Gson gson = new GsonBuilder().create();
+
+ private static final Version VERSION = FrameworkUtil.getBundle(PushbulletHandler.class).getVersion();
+
+ private static final Pattern CHANNEL_PATTERN = Pattern.compile("^[a-zA-Z0-9_-]+$");
+
+ private @Nullable PushbulletConfiguration config;
+
+ public PushbulletHandler(Thing thing) {
+ super(thing);
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ logger.debug("About to handle {} on {}", command, channelUID);
+
+ // Future improvement: If recipient is already set, send a push on a command channel change
+ // check reconnect channel of the unifi binding for that
+
+ logger.debug("The Pushbullet binding is a read-only binding and cannot handle command '{}'.", command);
+ }
+
+ @Override
+ public void initialize() {
+ logger.debug("Start initializing!");
+ config = getConfigAs(PushbulletConfiguration.class);
+
+ // Name and Token are both "required", so set the Thing immediately ONLINE.
+ updateStatus(ThingStatus.ONLINE);
+
+ logger.debug("Finished initializing!");
+ }
+
+ @Override
+ public Collection> getServices() {
+ return Collections.singleton(PushbulletActions.class);
+ }
+
+ public boolean sendPush(@Nullable String recipient, @Nullable String message, String type) {
+ return sendPush(recipient, "", message, type);
+ }
+
+ public boolean sendPush(@Nullable String recipient, @Nullable String title, @Nullable String message, String type) {
+ boolean result = false;
+
+ logger.debug("sendPush is called for ");
+ logger.debug("Thing {}", thing);
+ logger.debug("Thing Label: '{}'", thing.getLabel());
+
+ PushbulletConfiguration configuration = getConfigAs(PushbulletConfiguration.class);
+ logger.debug("CFG {}", configuration);
+
+ Properties headers = prepareRequestHeaders(configuration);
+
+ String request = prepareMessageBody(recipient, title, message, type);
+
+ try (InputStream stream = new ByteArrayInputStream(request.getBytes(StandardCharsets.UTF_8))) {
+
+ String pushAPI = configuration.getApiUrlBase() + "/" + API_METHOD_PUSHES;
+
+ String responseString = HttpUtil.executeUrl(HttpMethod.POST.asString(), pushAPI, headers, stream,
+ MimeTypes.Type.APPLICATION_JSON.asString(), TIMEOUT);
+
+ logger.debug("Got Response: {}", responseString);
+ PushResponse response = gson.fromJson(responseString, PushResponse.class);
+
+ logger.debug("Unpacked Response: {}", response);
+
+ stream.close();
+
+ if ((null != response) && (null == response.getPushError())) {
+ result = true;
+ }
+ }
+ catch (IOException e) {
+ logger.warn("IO problems pushing note: {}", e.getMessage());
+ }
+
+ return result;
+ }
+
+ /**
+ * helper method to populate the request headers
+ *
+ * @param configuration
+ * @return
+ */
+ private Properties prepareRequestHeaders(PushbulletConfiguration configuration) {
+ Properties headers = new Properties();
+ headers.put(HttpHeader.USER_AGENT, "openHAB / Pushbullet binding " + VERSION);
+ headers.put(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON.asString());
+ headers.put("Access-Token", configuration.getToken());
+
+ logger.debug("Headers: {}", headers);
+
+ return headers;
+ }
+
+ /**
+ * helper method to create a message body from data to be transferred.
+ *
+ * @param recipient
+ * @param title
+ * @param message
+ * @param type
+ *
+ * @return the message as a String to be posted
+ */
+ private String prepareMessageBody(@Nullable String recipient, @Nullable String title, @Nullable String message,
+ String type) {
+ logger.debug("Recipient is '{}'", recipient);
+ logger.debug("Title is '{}'", title);
+ logger.debug("Message is '{}'", message);
+
+ Push push = new Push();
+ push.setTitle(title);
+ push.setBody(message);
+ push.setType(type);
+
+ if (recipient != null) {
+ if (isValidEmail(recipient)) {
+ logger.debug("Recipient is an email address");
+ push.setEmail(recipient);
+ } else if (isValidChannel(recipient)) {
+ logger.debug("Recipient is a channel tag");
+ push.setChannel(recipient);
+ } else {
+ logger.warn("Invalid recipient: {}", recipient);
+ logger.warn("Message will be broadcast to all user's devices.");
+ }
+ }
+
+ logger.debug("Push: {}", push);
+
+ String request = gson.toJson(push);
+ logger.debug("Packed Request: {}", request);
+
+ return request;
+ }
+
+ /**
+ * helper method checking if channel tag is valid.
+ *
+ * @param channel
+ * @return
+ */
+ private static boolean isValidChannel(String channel) {
+ Matcher m = CHANNEL_PATTERN.matcher(channel);
+ return m.matches();
+ }
+
+ /**
+ * helper method checking if email address is valid.
+ *
+ * @param email
+ * @return
+ */
+ private static boolean isValidEmail(String email) {
+ try {
+ InternetAddress emailAddr = new InternetAddress(email);
+ emailAddr.validate();
+ return true;
+ } catch (AddressException e) {
+ return false;
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/Push.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/Push.java
new file mode 100644
index 0000000000000..e32ca0c711359
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/Push.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal.model;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * This class represents the push request sent to the API.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ * @author Hakan Tandogan - Migrated from openHAB 1 action with the same name
+ */
+public class Push {
+
+ @SerializedName("title")
+ private String title;
+
+ @SerializedName("body")
+ private String body;
+
+ @SerializedName("type")
+ private String type;
+
+ @SerializedName("email")
+ private String email;
+
+ @SerializedName("channel_tag")
+ private String channelTag;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getChannel() {
+ return channelTag;
+ }
+
+ public void setChannel(String channelTag) {
+ this.channelTag = channelTag;
+ }
+
+ @Override
+ public String toString() {
+ return "Push {" + "title='" + title + '\'' + ", body='" + body + '\'' + ", type='" + type + '\'' + ", email='"
+ + email + '\'' + ", channelTag='" + channelTag + '\'' + '}';
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushError.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushError.java
new file mode 100644
index 0000000000000..85f963d62daa7
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushError.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal.model;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * This class represents errors in the response fetched from the API.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ * @author Hakan Tandogan - Migrated from openHAB 1 action with the same name
+ */
+public class PushError {
+
+ @SerializedName("type")
+ private String type;
+
+ @SerializedName("message")
+ private String message;
+
+ @SerializedName("param")
+ private String param;
+
+ @SerializedName("cat")
+ private String cat;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getParam() {
+ return param;
+ }
+
+ public void setParam(String param) {
+ this.param = param;
+ }
+
+ public String getCat() {
+ return cat;
+ }
+
+ public void setCat(String cat) {
+ this.cat = cat;
+ }
+
+ @Override
+ public String toString() {
+ return "PushError {" + "type='" + type + '\'' + ", message='" + message + '\'' + ", param='" + param + '\''
+ + ", cat='" + cat + '\'' + '}';
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushResponse.java b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushResponse.java
new file mode 100644
index 0000000000000..7183d3b66f26f
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/java/org/openhab/binding/pushbullet/internal/model/PushResponse.java
@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2010-2019 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.pushbullet.internal.model;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * This class represents the answer to pushes provided by the API.
+ *
+ * @author Hakan Tandogan - Initial contribution
+ * @author Hakan Tandogan - Migrated from openHAB 1 action with the same name
+ */
+public class PushResponse {
+
+ @SerializedName("active")
+ private String active;
+
+ @SerializedName("iden")
+ private String iden;
+
+ @SerializedName("type")
+ private String type;
+
+ @SerializedName("dismissed")
+ private Boolean dismissed;
+
+ @SerializedName("direction")
+ private String direction;
+
+ @SerializedName("sender_iden")
+ private String senderIdentifier;
+
+ @SerializedName("sender_email")
+ private String senderEmail;
+
+ @SerializedName("sender_email_normalized")
+ private String senderEmailNormalized;
+
+ @SerializedName("sender_name")
+ private String senderName;
+
+ @SerializedName("receiver_iden")
+ private String receiverIdentifier;
+
+ @SerializedName("receiver_email")
+ private String receiverEmail;
+
+ @SerializedName("receiver_email_normalized")
+ private String receiverEmailNormalized;
+
+ @SerializedName("title")
+ private String title;
+
+ @SerializedName("body")
+ private String body;
+
+ @SerializedName("error_code")
+ private String errorCode;
+
+ @SerializedName("error")
+ private PushError pushError;
+
+ public String getActive() {
+ return active;
+ }
+
+ public void setActive(String active) {
+ this.active = active;
+ }
+
+ public String getIden() {
+ return iden;
+ }
+
+ public void setIden(String iden) {
+ this.iden = iden;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Boolean getDismissed() {
+ return dismissed;
+ }
+
+ public void setDismissed(Boolean dismissed) {
+ this.dismissed = dismissed;
+ }
+
+ public String getDirection() {
+ return direction;
+ }
+
+ public void setDirection(String direction) {
+ this.direction = direction;
+ }
+
+ public String getSenderIdentifier() {
+ return senderIdentifier;
+ }
+
+ public void setSenderIdentifier(String senderIdentifier) {
+ this.senderIdentifier = senderIdentifier;
+ }
+
+ public String getSenderEmail() {
+ return senderEmail;
+ }
+
+ public void setSenderEmail(String senderEmail) {
+ this.senderEmail = senderEmail;
+ }
+
+ public String getSenderEmailNormalized() {
+ return senderEmailNormalized;
+ }
+
+ public void setSenderEmailNormalized(String senderEmailNormalized) {
+ this.senderEmailNormalized = senderEmailNormalized;
+ }
+
+ public String getSenderName() {
+ return senderName;
+ }
+
+ public void setSenderName(String senderName) {
+ this.senderName = senderName;
+ }
+
+ public String getReceiverIdentifier() {
+ return receiverIdentifier;
+ }
+
+ public void setReceiverIdentifier(String receiverIdentifier) {
+ this.receiverIdentifier = receiverIdentifier;
+ }
+
+ public String getReceiverEmail() {
+ return receiverEmail;
+ }
+
+ public void setReceiverEmail(String receiverEmail) {
+ this.receiverEmail = receiverEmail;
+ }
+
+ public String getReceiverEmailNormalized() {
+ return receiverEmailNormalized;
+ }
+
+ public void setReceiverEmailNormalized(String receiverEmailNormalized) {
+ this.receiverEmailNormalized = receiverEmailNormalized;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public void setBody(String body) {
+ this.body = body;
+ }
+
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(String errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public PushError getPushError() {
+ return pushError;
+ }
+
+ public void setPushError(PushError pushError) {
+ this.pushError = pushError;
+ }
+
+ @Override
+ public String toString() {
+ return "PushResponse {" + "active='" + active + '\'' + ", iden='" + iden + '\'' + ", type='" + type + '\''
+ + ", dismissed=" + dismissed + ", direction='" + direction + '\'' + ", senderIdentifier='"
+ + senderIdentifier + '\'' + ", senderEmail='" + senderEmail + '\'' + ", senderEmailNormalized='"
+ + senderEmailNormalized + '\'' + ", senderName='" + senderName + '\'' + ", receiverIdentifier='"
+ + receiverIdentifier + '\'' + ", receiverEmail='" + receiverEmail + '\'' + ", receiverEmailNormalized='"
+ + receiverEmailNormalized + '\'' + ", title='" + title + '\'' + ", body='" + body + '\''
+ + ", errorCode='" + errorCode + '\'' + ", pushError=" + pushError + '}';
+ }
+}
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/binding/binding.xml b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/binding/binding.xml
new file mode 100644
index 0000000000000..18f0f94dfce51
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/binding/binding.xml
@@ -0,0 +1,9 @@
+
+
+
+ @text/binding.pushbullet.name
+ @text/binding.pushbullet.description
+ Hakan TandoÄŸan
+
+
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/i18n/pushbullet_en.properties b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/i18n/pushbullet_en.properties
new file mode 100644
index 0000000000000..df79c02a7897b
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/i18n/pushbullet_en.properties
@@ -0,0 +1,17 @@
+# binding
+binding.pushbullet.name = Pushbullet Binding
+binding.pushbullet.description = The Pushbullet binding allows you to send messages to other users of the Pushbullet service.
+
+# action
+actionSendPushbulletNoteLabel = publish an Pushbullet message
+actionSendPushbulletNoteDesc = Publishes a Title to the given Pushbullet Recipient.
+
+actionSendPushbulletNoteInputRecipientLabel = Pushbullet Recipient
+actionSendPushbulletNoteInputRecipientDesc = The Recipient to publish a Title to.
+actionSendPushbulletNoteInputTitleLabel = Title
+actionSendPushbulletNoteInputTitleDesc = The Title to publish
+actionSendPushbulletNoteInputMessageLabel = Message
+actionSendPushbulletNoteInputMessageDesc = The Message to publish
+
+# error texts
+offline.conf-error-httpresponseexception = The pushbullet server reported an error, possibly an expired token. Check on web site
diff --git a/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/thing/thing-types.xml
new file mode 100644
index 0000000000000..ba9c559eecfb7
--- /dev/null
+++ b/bundles/org.openhab.binding.pushbullet/src/main/resources/ESH-INF/thing/thing-types.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+ Bot to send messages with.
+
+
+
+
+
+
+
+
+
+
+ Explicit Name of Bot, if wanted
+ true
+
+
+
+
+ Token as obtained from the server
+
+
+
+
+ The Pushbullet API Server to use, for local testing
+ https://api.pushbullet.com/v2
+ true
+
+
+
+
+
+
+
+ String
+
+ Mail address or Channel Name
+
+
+
+ String
+
+ Title of the message
+
+
+
+ String
+
+ The text that is to be sent
+
+
+
diff --git a/bundles/org.openhab.binding.rfxcom/README.md b/bundles/org.openhab.binding.rfxcom/README.md
index 8bb2a990a7b60..49d0043be4231 100644
--- a/bundles/org.openhab.binding.rfxcom/README.md
+++ b/bundles/org.openhab.binding.rfxcom/README.md
@@ -154,11 +154,13 @@ This binding currently supports following channel types:
|-----------------|---------------|------------------------------------------------------------------------------------|
| chimesound | Number | Id of the chime sound |
| command | Switch | Command channel. |
-| commandId | String | Id of the command. |
+ | commandId | Number | Id of the command (between 0 and 255). |
+| commandString | String | Id of the command. |
| contact | Contact | Contact channel. |
| datetime | DateTime | DateTime channel. |
| dimminglevel | Dimmer | Dimming level channel. |
| forecast | String | Weather forecast from device: NO\_INFO\_AVAILABLE/SUNNY/PARTLY\_CLOUDY/CLOUDY/RAIN |
+| tempcontrol | Rollershutter | Global control for temperature also setting ON, OFF, UP, DOWN |
| humidity | Number | Relative humidity level in percentages. |
| humiditystatus | String | Current humidity status: NORMAL/COMFORT/DRY/WET |
| instantamp | Number | Instant current in Amperes. |
@@ -964,10 +966,31 @@ A Thermostat3 device.
#### Channels
-| Name | Channel Type | Item Type | Remarks |
-|-------------|-------------------------------------|-----------|----------|
-| command | [command](#channels) | Switch | |
-| signalLevel | [system.signal-strength](#channels) | Number | |
+| Name | Channel Type | Item Type | Remarks |
+|-------------------|-------------------------------------|---------------|----------|
+| command | [command](#channels) | Switch | |
+| command2nd | [command](#channels) | Switch | |
+| control\* | [tempcontrol](#channels) | Rollershutter | |
+| commandString\*\* | [commandString](#channels) | String | |
+| signalLevel | [system.signal-strength](#channels) | Number | |
+
+\* `control` supports:
+
+* UP
+* DOWN
+* STOP
+
+\*\* `commandString` supports:
+
+* OFF
+* ON
+* UP
+* DOWN
+* RUN_UP
+* RUN_DOWN
+* SECOND_ON
+* SECOND_OFF
+* STOP
#### Configuration Options
@@ -982,6 +1005,8 @@ A Thermostat3 device.
* MERTIK\_\_G6R\_H4TD\_\_G6R\_H4T16 - Mertik (G6R H4TD or G6R H4T16)
* MERTIK\_\_G6R\_H4S\_TRANSMIT\_ONLY - Mertik (G6R H4S \- transmit only)
+#### Examples
+
### undecoded - RFXCOM Undecoded RF Messages
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/DeviceMessageListener.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/DeviceMessageListener.java
index d5a0f44e0af06..abf7577124c3b 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/DeviceMessageListener.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/DeviceMessageListener.java
@@ -28,9 +28,9 @@ public interface DeviceMessageListener {
* This method is called whenever the message is received from the bridge.
*
* @param bridge
- * The RFXCom bridge where message is received.
+ * The RFXCom bridge where message is received.
* @param message
- * The message which received.
+ * The message which received.
*/
void onDeviceMessageReceived(ThingUID bridge, RFXComDeviceMessage message) throws RFXComException;
}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComBindingConstants.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComBindingConstants.java
index 558eeceb85573..8a323630875d5 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComBindingConstants.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/RFXComBindingConstants.java
@@ -67,8 +67,11 @@ public class RFXComBindingConstants {
public static final String CHANNEL_VENETIAN_BLIND = "venetianBlind";
public static final String CHANNEL_SUN_WIND_DETECTOR = "sunWindDetector";
public static final String CHANNEL_COMMAND = "command";
+ public static final String CHANNEL_COMMAND_SECOND = "command2nd";
+ public static final String CHANNEL_CONTROL = "control";
public static final String CHANNEL_PROGRAM = "program";
public static final String CHANNEL_COMMAND_ID = "commandId";
+ public static final String CHANNEL_COMMAND_STRING = "commandString";
public static final String CHANNEL_MOOD = "mood";
public static final String CHANNEL_SIGNAL_LEVEL = "signalLevel";
public static final String CHANNEL_DIMMING_LEVEL = "dimmingLevel";
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComConnectorInterface.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComConnectorInterface.java
index f9c28f3194f2e..1550aff9bbad1 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComConnectorInterface.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComConnectorInterface.java
@@ -27,8 +27,8 @@ public interface RFXComConnectorInterface {
* Procedure for connecting to RFXCOM controller.
*
* @param device
- * Controller connection parameters (e.g. serial port name or IP
- * address).
+ * Controller connection parameters (e.g. serial port name or IP
+ * address).
*/
public void connect(RFXComBridgeConfiguration device) throws Exception;
@@ -42,7 +42,7 @@ public interface RFXComConnectorInterface {
* Procedure for send raw data to RFXCOM controller.
*
* @param data
- * raw bytes.
+ * raw bytes.
*/
public void sendMessage(byte[] data) throws IOException;
@@ -50,7 +50,7 @@ public interface RFXComConnectorInterface {
* Procedure for register event listener.
*
* @param listener
- * Event listener instance to handle events.
+ * Event listener instance to handle events.
*/
public void addEventListener(RFXComEventListener listener);
@@ -58,7 +58,7 @@ public interface RFXComConnectorInterface {
* Procedure for remove event listener.
*
* @param listener
- * Event listener instance to remove.
+ * Event listener instance to remove.
*/
public void removeEventListener(RFXComEventListener listener);
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComEventListener.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComEventListener.java
index d27092328465f..abf1f9b305298 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComEventListener.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/connector/RFXComEventListener.java
@@ -23,7 +23,7 @@ public interface RFXComEventListener {
* Procedure for receive raw data from RFXCOM controller.
*
* @param data
- * Received raw data.
+ * Received raw data.
*/
void packetReceived(byte[] data);
@@ -31,7 +31,7 @@ public interface RFXComEventListener {
* Procedure for receiving information fatal error.
*
* @param error
- * Error occurred.
+ * Error occurred.
*/
void errorOccurred(String error);
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandler.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandler.java
index 16a7f75ce23ee..772b072e535ad 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandler.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/handler/RFXComHandler.java
@@ -141,13 +141,17 @@ public void onDeviceMessageReceived(ThingUID bridge, RFXComDeviceMessage message
updateStatus(ThingStatus.ONLINE);
for (Channel channel : getThing().getChannels()) {
- String channelId = channel.getUID().getId();
+ ChannelUID uid = channel.getUID();
+ String channelId = uid.getId();
try {
if (channelId.equals(CHANNEL_LOW_BATTERY)) {
- updateState(channelId, isLowBattery(message.convertToState(CHANNEL_BATTERY_LEVEL)));
+ updateState(uid, isLowBattery(message.convertToState(CHANNEL_BATTERY_LEVEL)));
} else {
- updateState(channelId, message.convertToState(channelId));
+ State state = message.convertToState(channelId);
+ if (state != null) {
+ updateState(uid, state);
+ }
}
} catch (RFXComException e) {
logger.trace("{} does not handle {}", channelId, message);
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting2Message.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting2Message.java
index 317c0abec96c3..0ddfcb9b8c0e4 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting2Message.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting2Message.java
@@ -152,7 +152,7 @@ public String getDeviceId() {
* Convert a 0-15 scale value to a percent type.
*
* @param pt
- * percent type to convert
+ * percent type to convert
* @return converted value 0-15
*/
public static int getDimLevelFromPercentType(PercentType pt) {
@@ -164,7 +164,7 @@ public static int getDimLevelFromPercentType(PercentType pt) {
* Convert a 0-15 scale value to a percent type.
*
* @param value
- * percent type to convert
+ * percent type to convert
* @return converted value 0-15
*/
public static PercentType getPercentTypeFromDimLevel(int value) {
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting5Message.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting5Message.java
index f7c5e6f41d7a5..4cd72438128ae 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting5Message.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting5Message.java
@@ -73,10 +73,10 @@ public byte toByte() {
/**
* Note: for the lighting5 commands, some command are only supported for certain sub types and
* command-bytes might even have a different meaning for another sub type.
- *
+ *
* If no sub types are specified for a command, its supported by all sub types.
* An example is the command OFF which is represented by the byte 0x00 for all subtypes.
- *
+ *
* Otherwise the list of sub types after the command-bytes indicates the sub types
* which support this command with this byte.
* Example byte value 0x03 means GROUP_ON for IT and some others while it means MOOD1 for LIGHTWAVERF
@@ -206,7 +206,7 @@ public String getDeviceId() {
* Convert a 0-31 scale value to a percent type.
*
* @param pt
- * percent type to convert
+ * percent type to convert
* @return converted value 0-31
*/
public static int getDimLevelFromPercentType(PercentType pt) {
@@ -218,7 +218,7 @@ public static int getDimLevelFromPercentType(PercentType pt) {
* Convert a 0-31 scale value to a percent type.
*
* @param value
- * percent type to convert
+ * percent type to convert
* @return converted value 0-31
*/
public static PercentType getPercentTypeFromDimLevel(int value) {
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessage.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessage.java
index c0a1b50145eeb..727875d7b030f 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessage.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComMessage.java
@@ -28,7 +28,7 @@ public interface RFXComMessage {
* Procedure for encode raw data.
*
* @param data
- * Raw data.
+ * Raw data.
*/
void encodeMessage(byte[] data) throws RFXComException;
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3Message.java b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3Message.java
index a8a92fff5c157..fba3b2f7dcb21 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3Message.java
+++ b/bundles/org.openhab.binding.rfxcom/src/main/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3Message.java
@@ -12,7 +12,7 @@
*/
package org.openhab.binding.rfxcom.internal.messages;
-import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.CHANNEL_COMMAND;
+import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
import static org.openhab.binding.rfxcom.internal.messages.ByteEnumUtil.fromByte;
import static org.openhab.binding.rfxcom.internal.messages.RFXComThermostat3Message.SubType.*;
@@ -20,10 +20,13 @@
import java.util.List;
import org.eclipse.smarthome.core.library.types.OnOffType;
-import org.eclipse.smarthome.core.library.types.OpenClosedType;
+import org.eclipse.smarthome.core.library.types.PercentType;
+import org.eclipse.smarthome.core.library.types.StopMoveType;
+import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.library.types.UpDownType;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.Type;
+import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedValueException;
@@ -98,7 +101,6 @@ public static Commands fromByte(int input, SubType subType) throws RFXComUnsuppo
public SubType subType;
private int unitId;
public Commands command;
- private byte commandId;
public RFXComThermostat3Message() {
super(PacketType.THERMOSTAT3);
@@ -115,7 +117,7 @@ public String toString() {
str += super.toString();
str += ", Sub type = " + subType;
str += ", Device Id = " + getDeviceId();
- str += ", Command = " + command + "(" + commandId + ")";
+ str += ", Command = " + command;
str += ", Signal level = " + signalLevel;
return str;
@@ -132,8 +134,7 @@ public void encodeMessage(byte[] data) throws RFXComException {
subType = fromByte(SubType.class, super.subType);
unitId = (data[4] & 0xFF) << 16 | (data[5] & 0xFF) << 8 | (data[6] & 0xFF);
- commandId = data[7];
- command = Commands.fromByte(commandId, subType);
+ command = Commands.fromByte(data[7], subType);
signalLevel = (byte) ((data[8] & 0xF0) >> 4);
}
@@ -159,19 +160,51 @@ public State convertToState(String channelId) throws RFXComUnsupportedChannelExc
switch (channelId) {
case CHANNEL_COMMAND:
switch (command) {
+ case RUN_DOWN:
case OFF:
- case SECOND_OFF:
return OnOffType.OFF;
case ON:
+ case RUN_UP:
+ case UP:
+ return OnOffType.ON;
case SECOND_ON:
+ case SECOND_OFF:
+ return null;
+ default:
+ return UnDefType.UNDEF;
+
+ }
+ case CHANNEL_CONTROL:
+ switch (command) {
+ case ON:
return OnOffType.ON;
case UP:
+ case RUN_UP:
return UpDownType.UP;
+ case OFF:
+ return OnOffType.OFF;
case DOWN:
+ case RUN_DOWN:
return UpDownType.DOWN;
+ case SECOND_ON:
+ case SECOND_OFF:
+ case STOP:
+ return null;
default:
throw new RFXComUnsupportedChannelException("Can't convert " + command + " for " + channelId);
}
+ case CHANNEL_COMMAND_SECOND:
+ switch (command) {
+ case SECOND_OFF:
+ return OnOffType.OFF;
+ case SECOND_ON:
+ return OnOffType.ON;
+ default:
+ return null;
+ }
+ case CHANNEL_COMMAND_STRING:
+ return command == null ? UnDefType.UNDEF : StringType.valueOf(command.toString());
+
default:
return super.convertToState(channelId);
}
@@ -183,15 +216,35 @@ public void convertFromState(String channelId, Type type) throws RFXComUnsupport
case CHANNEL_COMMAND:
if (type instanceof OnOffType) {
command = (type == OnOffType.ON ? Commands.ON : Commands.OFF);
- } else if (type instanceof UpDownType) {
+ } else {
+ throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
+ }
+ break;
+
+ case CHANNEL_COMMAND_SECOND:
+ if (type instanceof OnOffType) {
+ command = (type == OnOffType.ON ? Commands.SECOND_ON : Commands.SECOND_OFF);
+ } else {
+ throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
+ }
+ break;
+
+ case CHANNEL_CONTROL:
+ if (type instanceof UpDownType) {
command = (type == UpDownType.UP ? Commands.UP : Commands.DOWN);
- } else if (type instanceof OpenClosedType) {
- command = (type == OpenClosedType.CLOSED ? Commands.ON : Commands.OFF);
+ } else if (type == StopMoveType.STOP) {
+ command = Commands.STOP;
+ } else if (type instanceof PercentType) {
+ command = ((PercentType) type).as(UpDownType.class) == UpDownType.UP ? Commands.UP : Commands.DOWN;
} else {
throw new RFXComUnsupportedChannelException("Channel " + channelId + " does not accept " + type);
}
break;
+ case CHANNEL_COMMAND_STRING:
+ command = Commands.valueOf(type.toString().toUpperCase());
+ break;
+
default:
throw new RFXComUnsupportedChannelException("Channel " + channelId + " is not relevant here");
}
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/channels.xml b/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/channels.xml
index 69bb04bcb93ed..4f0d943d90dd0 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/channels.xml
+++ b/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/channels.xml
@@ -26,10 +26,16 @@
Number
- Command channel, ID of the channel
+ Command channel, ID of the command
+
+ String
+
+ Command channel, Name of the command
+
+
Contact
@@ -70,6 +76,12 @@
+
+ Rollershutter
+
+ Requested temperature setting, UP, DOWN, STOP
+
+
Switch
diff --git a/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/thermostat3.xml b/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/thermostat3.xml
index bd7d32eb0e6a5..0f7a1b1204054 100644
--- a/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/thermostat3.xml
+++ b/bundles/org.openhab.binding.rfxcom/src/main/resources/ESH-INF/thing/thermostat3.xml
@@ -16,6 +16,9 @@
+
+
+
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComChimeMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComChimeMessageTest.java
index b7be8e059cec5..4b4d93d88651d 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComChimeMessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComChimeMessageTest.java
@@ -19,7 +19,6 @@
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
import org.openhab.binding.rfxcom.internal.messages.RFXComChimeMessage.SubType;
-
/**
* Test for RFXCom-binding
*
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComDateTimeMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComDateTimeMessageTest.java
index b05e3c8a9390b..41f7e4ea2aeaf 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComDateTimeMessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComDateTimeMessageTest.java
@@ -37,7 +37,8 @@ public void testSomeMessages() throws RFXComException {
assertEquals("Date time", "2003-04-29T13:21:10", msg.dateTime);
assertEquals("Signal Level", 2, RFXComTestHelper.getActualIntValue(msg, CHANNEL_SIGNAL_LEVEL));
- assertEquals("Converted value", DateTimeType.valueOf("2003-04-29T13:21:10"), msg.convertToState(CHANNEL_DATE_TIME));
+ assertEquals("Converted value", DateTimeType.valueOf("2003-04-29T13:21:10"),
+ msg.convertToState(CHANNEL_DATE_TIME));
byte[] decoded = msg.decodeMessage();
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHomeConfortTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHomeConfortTest.java
index ef37065da798d..fe0cc721f8bc6 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHomeConfortTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComHomeConfortTest.java
@@ -21,7 +21,6 @@
import org.openhab.binding.rfxcom.internal.messages.RFXComHomeConfortMessage.Commands;
import org.openhab.binding.rfxcom.internal.messages.RFXComHomeConfortMessage.SubType;
-
/**
* Test for RFXCom-binding
*
@@ -29,12 +28,11 @@
* @author Mike Jagdis - added message handling and real test
*/
public class RFXComHomeConfortTest {
- private void testMessage(SubType subType, Commands command, String deviceId, String data)
- throws RFXComException {
+ private void testMessage(SubType subType, Commands command, String deviceId, String data) throws RFXComException {
RFXComHomeConfortMessage message = (RFXComHomeConfortMessage) RFXComMessageFactory.createMessage(HOME_CONFORT);
message.setSubType(subType);
- message.command = command;
+ message.command = command;
message.setDeviceId(deviceId);
assertArrayEquals(HexUtils.hexToBytes(data), message.decodeMessage());
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessageTest.java
index 990afef1d5911..8be29f545d45a 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComInterfaceControlMessageTest.java
@@ -44,7 +44,7 @@ public void resetConfig() {
configuration.enableBlindsT1T2T3T4 = false;
configuration.enableBlindsT0 = false;
configuration.enableProGuard = false;
-// configuration.enableFS20Packets = false;
+ // configuration.enableFS20Packets = false;
configuration.enableLaCrosse = false;
configuration.enableHidekiUPM = false;
configuration.enableADLightwaveRF = false;
@@ -60,11 +60,11 @@ public void resetConfig() {
configuration.enableX10 = false;
}
- private void testMessage(RFXComInterfaceMessage.TransceiverType transceiverType, RFXComBridgeConfiguration configuration, String data)
- throws RFXComException {
+ private void testMessage(RFXComInterfaceMessage.TransceiverType transceiverType,
+ RFXComBridgeConfiguration configuration, String data) throws RFXComException {
assertArrayEquals(HexUtils.hexToBytes(data),
- new RFXComInterfaceControlMessage(transceiverType, configuration).decodeMessage());
+ new RFXComInterfaceControlMessage(transceiverType, configuration).decodeMessage());
}
@Test
@@ -133,11 +133,11 @@ public void testProGuardMessage() throws RFXComException {
testMessage(_433_92MHZ_TRANSCEIVER, configuration, "0D00000203530000200000000000");
}
-// @Test
-// public void testFS20PacketsMessage() throws RFXComException {
-// configuration.enableFS20Packets = true;
-// testMessage(_433_92MHZ_TRANSCEIVER, configuration, "0D00000203530000100000000000");
-// }
+ // @Test
+ // public void testFS20PacketsMessage() throws RFXComException {
+ // configuration.enableFS20Packets = true;
+ // testMessage(_433_92MHZ_TRANSCEIVER, configuration, "0D00000203530000100000000000");
+ // }
@Test
public void testLaCrosseMessage() throws RFXComException {
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4MessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4MessageTest.java
index 719ea1a93195c..e230dcac38051 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4MessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComLighting4MessageTest.java
@@ -57,8 +57,7 @@ private void testMessage(String hexMsg, RFXComLighting4Message.SubType subType,
}
private void testMessage(String hexMsg, RFXComLighting4Message.SubType subType, String deviceId, Integer pulse,
- byte commandByte, Integer seqNbr, int signalLevel, int offCommand, int onCommand)
- throws RFXComException {
+ byte commandByte, Integer seqNbr, int signalLevel, int offCommand, int onCommand) throws RFXComException {
RFXComLighting4Message msg = (RFXComLighting4Message) RFXComMessageFactory
.createMessage(HexUtils.hexToBytes(hexMsg));
assertEquals("Sensor Id", deviceId, msg.getDeviceId());
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRfyMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRfyMessageTest.java
index df89917c2858e..04cf080e36c8f 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRfyMessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComRfyMessageTest.java
@@ -38,12 +38,11 @@ public void basicBoundaryCheck() throws RFXComException {
RFXComTestHelper.basicBoundaryCheck(RFY, message);
}
- private void testMessage(SubType subType, Commands command, String deviceId, String data)
- throws RFXComException {
+ private void testMessage(SubType subType, Commands command, String deviceId, String data) throws RFXComException {
RFXComRfyMessage message = (RFXComRfyMessage) RFXComMessageFactory.createMessage(RFY);
message.setSubType(subType);
- message.command = command;
+ message.command = command;
message.setDeviceId(deviceId);
assertArrayEquals(HexUtils.hexToBytes(data), message.decodeMessage());
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3MessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3MessageTest.java
index ebc8a1445c517..8ef24a8770a28 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3MessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComThermostat3MessageTest.java
@@ -12,13 +12,21 @@
*/
package org.openhab.binding.rfxcom.internal.messages;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
+import static org.openhab.binding.rfxcom.internal.RFXComBindingConstants.*;
import static org.openhab.binding.rfxcom.internal.messages.RFXComBaseMessage.PacketType.THERMOSTAT3;
-import static org.openhab.binding.rfxcom.internal.messages.RFXComThermostat3Message.SubType.MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22;
+import static org.openhab.binding.rfxcom.internal.messages.RFXComThermostat3Message.SubType.*;
+import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.library.types.StopMoveType;
+import org.eclipse.smarthome.core.library.types.StringType;
+import org.eclipse.smarthome.core.library.types.UpDownType;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
import org.eclipse.smarthome.core.util.HexUtils;
import org.junit.Test;
import org.openhab.binding.rfxcom.internal.exceptions.RFXComException;
+import org.openhab.binding.rfxcom.internal.exceptions.RFXComUnsupportedChannelException;
/**
* Test for RFXCom-binding
@@ -43,18 +51,231 @@ public void basicBoundaryCheck() throws RFXComException {
@Test
public void testSomeMessages() throws RFXComException {
- String hexMessage = "08420101019FAB0280";
+ testMessage("08420101019FAB0280", MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22, 1, "106411",
+ RFXComThermostat3Message.Commands.UP, (byte) 8, OnOffType.ON, null, UpDownType.UP,
+ StringType.valueOf("UP"));
+ testMessage("084200000000410500", MERTIK__G6R_H4T1, 0, "65", RFXComThermostat3Message.Commands.RUN_DOWN,
+ (byte) 0, OnOffType.OFF, null, UpDownType.DOWN, StringType.valueOf("RUN_DOWN"));
+ }
+
+ private void testMessage(String hexMessage, RFXComThermostat3Message.SubType subtype, int sequenceNumber,
+ String sensorId, RFXComThermostat3Message.Commands command, byte signalLevel, State commandChannel,
+ State secondCommandChannel, State controlChannel, State commandStringChannel) throws RFXComException {
byte[] message = HexUtils.hexToBytes(hexMessage);
RFXComThermostat3Message msg = (RFXComThermostat3Message) RFXComMessageFactory.createMessage(message);
- assertEquals("SubType", MERTIK__G6R_H4TB__G6R_H4T__G6R_H4T21_Z22, msg.subType);
- assertEquals("Seq Number", 1, (short) (msg.seqNbr & 0xFF));
- assertEquals("Sensor Id", "106411", msg.getDeviceId());
- assertEquals("Command", RFXComThermostat3Message.Commands.UP, msg.command);
- assertEquals("Signal Level", (byte) 8, msg.signalLevel);
+ assertEquals("SubType", subtype, msg.subType);
+ assertEquals("Seq Number", sequenceNumber, (short) (msg.seqNbr & 0xFF));
+ assertEquals("Sensor Id", sensorId, msg.getDeviceId());
+ assertEquals(CHANNEL_COMMAND, command, msg.command);
+ assertEquals("Signal Level", signalLevel, msg.signalLevel);
+
+ assertEquals(commandChannel, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(secondCommandChannel, msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertEquals(controlChannel, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(commandStringChannel, msg.convertToState(CHANNEL_COMMAND_STRING));
byte[] decoded = msg.decodeMessage();
assertEquals("Message converted back", hexMessage, HexUtils.bytesToHex(decoded));
}
// TODO please add tests for real messages
+
+ @Test
+ public void testCommandChannelOn() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND, OnOffType.ON);
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("ON"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testCommandChannelOff() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND, OnOffType.OFF);
+
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_CONTROL));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertEquals(StringType.valueOf("OFF"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ }
+
+ @Test
+ public void testSecondCommandChannelOn() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_SECOND, OnOffType.ON);
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("SECOND_ON"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ }
+
+ @Test
+ public void testSecondCommandChannelOff() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_SECOND, OnOffType.OFF);
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("SECOND_OFF"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ }
+
+ @Test
+ public void testControlUp() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_CONTROL, UpDownType.UP);
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.UP, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("UP"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testControlDown() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_CONTROL, UpDownType.DOWN);
+
+ assertEquals(UnDefType.UNDEF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.DOWN, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("DOWN"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testControlStop() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_CONTROL, StopMoveType.STOP);
+
+ assertEquals(UnDefType.UNDEF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(StringType.valueOf("STOP"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusOff() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("OFF"));
+
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("OFF"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusOn() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("On"));
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("ON"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusUp() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("UP"));
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.UP, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("UP"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusDown() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("down"));
+
+ assertEquals(UnDefType.UNDEF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.DOWN, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("DOWN"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusRunUp() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("RUN_UP"));
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.UP, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("RUN_UP"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusRunDown() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("RUN_DOWN"));
+
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(UpDownType.DOWN, msg.convertToState(CHANNEL_CONTROL));
+ assertEquals(StringType.valueOf("RUN_DOWN"), msg.convertToState(CHANNEL_COMMAND_STRING));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusStop() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("STOP"));
+
+ assertEquals(UnDefType.UNDEF, msg.convertToState(CHANNEL_COMMAND));
+ assertEquals(StringType.valueOf("STOP"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ assertNull(msg.convertToState(CHANNEL_COMMAND_SECOND));
+ }
+
+ @Test
+ public void testStatusSecondOn() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("SECOND_ON"));
+
+ assertEquals(OnOffType.ON, msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertEquals(StringType.valueOf("SECOND_ON"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND));
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ }
+
+ @Test
+ public void testStatusSecondOff() throws RFXComUnsupportedChannelException {
+ RFXComThermostat3Message msg = new RFXComThermostat3Message();
+
+ msg.convertFromState(CHANNEL_COMMAND_STRING, StringType.valueOf("SECOND_OFF"));
+
+ assertEquals(OnOffType.OFF, msg.convertToState(CHANNEL_COMMAND_SECOND));
+ assertEquals(StringType.valueOf("SECOND_OFF"), msg.convertToState(CHANNEL_COMMAND_STRING));
+
+ assertNull(msg.convertToState(CHANNEL_COMMAND));
+ assertNull(msg.convertToState(CHANNEL_CONTROL));
+ }
}
diff --git a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUndecodedRFMessageTest.java b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUndecodedRFMessageTest.java
index 9d3ef1e3b9f57..7ef7efcdcd2ac 100644
--- a/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUndecodedRFMessageTest.java
+++ b/bundles/org.openhab.binding.rfxcom/src/test/java/org/openhab/binding/rfxcom/internal/messages/RFXComUndecodedRFMessageTest.java
@@ -53,8 +53,7 @@ public void testLongMessage() throws RFXComException {
.createMessage(PacketType.UNDECODED_RF_MESSAGE);
msg.subType = RFXComUndecodedRFMessage.SubType.ARC;
msg.seqNbr = 1;
- msg.rawPayload = HexUtils
- .hexToBytes("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021");
+ msg.rawPayload = HexUtils.hexToBytes("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021");
msg.decodeMessage();
}
}
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/SamsungTvTlsTrustManagerProvider.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/SamsungTvTlsTrustManagerProvider.java
index 1d35d69e6e373..2599c071edac7 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/SamsungTvTlsTrustManagerProvider.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/SamsungTvTlsTrustManagerProvider.java
@@ -18,20 +18,26 @@
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedTrustManager;
+import javax.security.auth.x500.X500Principal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.io.net.http.TlsTrustManagerProvider;
import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Provides a TrustManager to allow secure websocket connections to any TV (=server)
+ * TODO: convert to using TrustAllTrustMananger (not supported in OH2.4 yet)
*
* @author Arjan Mels - Initial Contribution
*/
@Component
@NonNullByDefault
public class SamsungTvTlsTrustManagerProvider implements TlsTrustManagerProvider {
+ private final Logger logger = LoggerFactory.getLogger(WakeOnLanUtility.class);
+
@Override
public String getHostName() {
return "SmartViewSDK";
@@ -39,14 +45,25 @@ public String getHostName() {
private final X509ExtendedTrustManager trustAllCerts = new X509ExtendedTrustManager() {
+ private void logCertificateCN(String function, X509Certificate @Nullable [] x509Certificates) {
+ if (x509Certificates != null && logger.isTraceEnabled()) {
+ for (X509Certificate certificate : x509Certificates) {
+ logger.trace("TrustManager {} CN: {}", function,
+ certificate.getSubjectX500Principal().getName(X500Principal.RFC2253));
+ }
+ }
+ }
+
@Override
public void checkClientTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s)
throws CertificateException {
+ logCertificateCN("checkClientTrusted", x509Certificates);
}
@Override
public void checkServerTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s)
throws CertificateException {
+ logCertificateCN("checkServerTrusted", x509Certificates);
}
@Override
@@ -57,26 +74,31 @@ public void checkServerTrusted(X509Certificate @Nullable [] x509Certificates, @N
@Override
public void checkClientTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s,
@Nullable Socket socket) throws CertificateException {
+ logCertificateCN("checkClientTrustedSocket", x509Certificates);
}
@Override
public void checkServerTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s,
@Nullable Socket socket) throws CertificateException {
+ logCertificateCN("checkServerTrustedSocket", x509Certificates);
}
@Override
public void checkClientTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s,
@Nullable SSLEngine sslEngine) throws CertificateException {
+ logCertificateCN("checkClientTrustedEngine", x509Certificates);
}
@Override
public void checkServerTrusted(X509Certificate @Nullable [] x509Certificates, @Nullable String s,
@Nullable SSLEngine sslEngine) throws CertificateException {
+ logCertificateCN("checkServerTrustedEngine", x509Certificates);
}
};
@Override
public X509ExtendedTrustManager getTrustManager() {
return trustAllCerts;
+ // return TrustAllTrustMananger.getInstance();
}
}
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/WakeOnLanUtility.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/WakeOnLanUtility.java
index 5e40210562cf6..672b0efe40c7b 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/WakeOnLanUtility.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/WakeOnLanUtility.java
@@ -36,7 +36,7 @@
@NonNullByDefault
public class WakeOnLanUtility {
- private static Logger logger = LoggerFactory.getLogger(WakeOnLanUtility.class);
+ private static final Logger logger = LoggerFactory.getLogger(WakeOnLanUtility.class);
/**
* Get MAC address for host
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/discovery/SamsungTvDiscoveryParticipant.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/discovery/SamsungTvDiscoveryParticipant.java
index eb29611db1cc0..7ff267e45ee9c 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/discovery/SamsungTvDiscoveryParticipant.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/discovery/SamsungTvDiscoveryParticipant.java
@@ -28,7 +28,6 @@
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.ThingUID;
import org.jupnp.model.meta.RemoteDevice;
-import org.openhab.binding.samsungtv.internal.service.RemoteControllerService;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,8 +56,6 @@ public Set getSupportedThingTypeUIDs() {
Map properties = new HashMap<>();
properties.put(HOST_NAME, device.getIdentity().getDescriptorURL().getHost());
- properties.putAll(RemoteControllerService.discover(device.getIdentity().getDescriptorURL().getHost()));
-
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
.withLabel(getLabel(device)).build();
@@ -98,8 +95,8 @@ private String getLabel(RemoteDevice device) {
if (logger.isDebugEnabled()) {
String modelName = device.getDetails().getModelDetails().getModelName();
String friendlyName = device.getDetails().getFriendlyName();
- logger.debug("Discovered a Samsung TV '{}' model '{}' thing with UDN '{}'", friendlyName,
- modelName, udn);
+ logger.debug("Retrieved Thing UID for a Samsung TV '{}' model '{}' thing with UDN '{}'",
+ friendlyName, modelName, udn);
}
return new ThingUID(SAMSUNG_TV_THING_TYPE, udn);
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/handler/SamsungTvHandler.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/handler/SamsungTvHandler.java
index e9c2ff233b4ba..41bbcd46755bb 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/handler/SamsungTvHandler.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/handler/SamsungTvHandler.java
@@ -16,6 +16,7 @@
import java.util.Collection;
import java.util.Collections;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
@@ -67,7 +68,7 @@ public class SamsungTvHandler extends BaseThingHandler implements DiscoveryListe
private static final int WOL_PACKET_RETRY_COUNT = 10;
private static final int WOL_SERVICE_CHECK_COUNT = 30;
- private Logger logger = LoggerFactory.getLogger(SamsungTvHandler.class);
+ private final Logger logger = LoggerFactory.getLogger(SamsungTvHandler.class);
private UpnpIOService upnpIOService;
private DiscoveryServiceRegistry discoveryServiceRegistry;
@@ -149,14 +150,6 @@ public void initialize() {
discoveryServiceRegistry.addDiscoveryListener(this);
checkAndCreateServices();
-
- SamsungTvConfiguration configuration = getConfigAs(SamsungTvConfiguration.class);
- if (StringUtils.isEmpty(configuration.macAddress) && configuration.hostName != null) {
- String macAddress = WakeOnLanUtility.getMACAddress(configuration.hostName);
- if (macAddress != null) {
- getConfig().put(SamsungTvConfiguration.MAC_ADDRESS, macAddress);
- }
- }
}
@Override
@@ -277,14 +270,12 @@ private synchronized void checkCreateManualConnection() {
RemoteControllerService service = (RemoteControllerService) findServiceInstance(
RemoteControllerService.SERVICE_NAME);
if (service == null) {
- putOffline();
SamsungTvConfiguration configuration = getConfigAs(SamsungTvConfiguration.class);
service = RemoteControllerService.createNonUpnpService(configuration.hostName, configuration.port);
startService(service);
} else {
// open connection again if needed
if (!service.checkConnection()) {
- putOffline();
service.start();
}
}
@@ -309,9 +300,27 @@ private synchronized void stopService(SamsungTvService service) {
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
SamsungTvConfiguration configuration = getConfigAs(SamsungTvConfiguration.class);
- if (configuration.hostName.equals(result.getProperties().get(SamsungTvConfiguration.HOST_NAME))) {
+ if (configuration.hostName != null
+ && configuration.hostName.equals(result.getProperties().get(SamsungTvConfiguration.HOST_NAME))) {
logger.debug("thingDiscovered: {}, {}", result.getProperties().get(SamsungTvConfiguration.HOST_NAME),
result);
+
+ /* Check if configuration should be updated */
+ if (StringUtils.isEmpty(configuration.macAddress)) {
+ String macAddress = WakeOnLanUtility.getMACAddress(configuration.hostName);
+ if (macAddress != null) {
+ getConfig().put(SamsungTvConfiguration.MAC_ADDRESS, macAddress);
+ logger.debug("thingDiscovered, macAddress: {}", macAddress);
+ }
+ }
+ if (SamsungTvConfiguration.PROTOCOL_NONE.equals(configuration.protocol)) {
+ Map properties = RemoteControllerService.discover(configuration.hostName);
+ for (Map.Entry property : properties.entrySet()) {
+ getConfig().put(property.getKey(), property.getValue());
+ logger.debug("thingDiscovered, {}: {}", property.getKey(), property.getValue());
+ }
+ }
+
/*
* SamsungTV discovery services creates thing UID from UPnP UDN.
* When thing is generated manually, thing UID may not match UPnP UDN, so store it for later use (e.g.
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/RemoteControllerWebSocket.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/RemoteControllerWebSocket.java
index e9f61f042189b..7266cb5be47cf 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/RemoteControllerWebSocket.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/RemoteControllerWebSocket.java
@@ -293,7 +293,7 @@ public void sendKeys(List keys) throws RemoteControllerException {
* @throws RemoteControllerException
*/
public void sendKeys(List keys, int sleepInMs) throws RemoteControllerException {
- logger.debug("Try to send sequnce of commands: {}", keys);
+ logger.debug("Try to send sequence of commands: {}", keys);
if (!isConnected()) {
openConnection();
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketBase.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketBase.java
index 1ad26a8342d11..44ce3102bf031 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketBase.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketBase.java
@@ -53,8 +53,11 @@ public void onWebSocketClose(int statusCode, @Nullable String reason) {
@Override
public void onWebSocketError(@Nullable Throwable error) {
- logger.debug("{} connection error: {}", this.getClass().getSimpleName(),
- error != null ? error.toString() : null);
+ if (logger.isTraceEnabled()) {
+ logger.trace("{} connection error", this.getClass().getSimpleName(), error);
+ } else {
+ logger.debug("{} connection error", this.getClass().getSimpleName());
+ }
super.onWebSocketError(error);
isConnecting = false;
}
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketRemote.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketRemote.java
index f1c8708bbc887..e1a3ebddb2c4f 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketRemote.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/protocol/WebSocketRemote.java
@@ -98,6 +98,12 @@ public void onWebSocketText(@Nullable String msgarg) {
if (jsonMsg.data.token != null) {
this.remoteControllerWebSocket.callback.putConfig(SamsungTvConfiguration.WEBSOCKET_TOKEN,
jsonMsg.data.token);
+ // try opening additional websockets
+ try {
+ this.remoteControllerWebSocket.openConnection();
+ } catch (RemoteControllerException e) {
+ logger.warn("{}: Error ({})", this.getClass().getSimpleName(), e.getMessage());
+ }
}
getApps();
break;
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MainTVServerService.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MainTVServerService.java
index c9945efccc592..3f7311ce750af 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MainTVServerService.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MainTVServerService.java
@@ -55,7 +55,7 @@ public class MainTVServerService implements UpnpIOParticipant, SamsungTvService
public static final String SERVICE_NAME = "MainTVServer2";
private static final List SUPPORTEDCOMMANDS = Arrays.asList(SOURCE_NAME, BROWSER_URL, STOP_BROWSER);
- private Logger logger = LoggerFactory.getLogger(MainTVServerService.class);
+ private final Logger logger = LoggerFactory.getLogger(MainTVServerService.class);
private UpnpIOService service;
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MediaRendererService.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MediaRendererService.java
index 98ae36f4cb7a0..1fa0f5c3c4a1b 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MediaRendererService.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/MediaRendererService.java
@@ -55,7 +55,7 @@ public class MediaRendererService implements UpnpIOParticipant, SamsungTvService
private final List supportedCommands = Arrays.asList(VOLUME, MUTE, BRIGHTNESS, CONTRAST, SHARPNESS,
COLOR_TEMPERATURE);
- private Logger logger = LoggerFactory.getLogger(MediaRendererService.class);
+ private final Logger logger = LoggerFactory.getLogger(MediaRendererService.class);
private @Nullable UpnpIOService service;
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/RemoteControllerService.java b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/RemoteControllerService.java
index 48652a03d4b84..f65082b7ca5c7 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/RemoteControllerService.java
+++ b/bundles/org.openhab.binding.samsungtv/src/main/java/org/openhab/binding/samsungtv/internal/service/RemoteControllerService.java
@@ -60,7 +60,7 @@
@NonNullByDefault
public class RemoteControllerService implements SamsungTvService, RemoteControllerWebsocketCallback {
- private Logger logger = LoggerFactory.getLogger(RemoteControllerService.class);
+ private final Logger logger = LoggerFactory.getLogger(RemoteControllerService.class);
public static final String SERVICE_NAME = "RemoteControlReceiver";
@@ -209,17 +209,18 @@ public void start() {
String protocol = (String) getConfig(SamsungTvConfiguration.PROTOCOL);
logger.info("Using {} interface", protocol);
- if (SamsungTvConfiguration.PROTOCOL_NONE.equals(protocol)) {
- remoteController = null;
- return;
- } else if (SamsungTvConfiguration.PROTOCOL_LEGACY.equals(protocol)) {
+ if (SamsungTvConfiguration.PROTOCOL_LEGACY.equals(protocol)) {
remoteController = new RemoteControllerLegacy(host, port, "openHAB", "openHAB");
- } else {
+ } else if (SamsungTvConfiguration.PROTOCOL_WEBSOCKET.equals(protocol)
+ || SamsungTvConfiguration.PROTOCOL_SECUREWEBSOCKET.equals(protocol)) {
try {
remoteController = new RemoteControllerWebSocket(host, port, "openHAB", "openHAB", this);
} catch (RemoteControllerException e) {
reportError("Cannot connect to remote control service", e);
}
+ } else {
+ remoteController = null;
+ return;
}
if (remoteController != null) {
diff --git a/bundles/org.openhab.binding.samsungtv/src/main/resources/ESH-INF/config/config.xml b/bundles/org.openhab.binding.samsungtv/src/main/resources/ESH-INF/config/config.xml
index 459739cc0149b..2d4d5afe78390 100644
--- a/bundles/org.openhab.binding.samsungtv/src/main/resources/ESH-INF/config/config.xml
+++ b/bundles/org.openhab.binding.samsungtv/src/main/resources/ESH-INF/config/config.xml
@@ -25,6 +25,22 @@
1000
+
+
+ The type of remote control protocol. This depends on the age of the TV.
+
+
+
+
+
+
+ None
+
+
+
+ Security token for secure websocket connection
+ true
+
diff --git a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/SatelHandlerFactory.java b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/SatelHandlerFactory.java
index 4f32fb0ee69d8..874f250847665 100644
--- a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/SatelHandlerFactory.java
+++ b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/SatelHandlerFactory.java
@@ -30,6 +30,7 @@
import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
+import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.openhab.binding.satel.internal.config.SatelThingConfig;
import org.openhab.binding.satel.internal.discovery.SatelDeviceDiscoveryService;
import org.openhab.binding.satel.internal.handler.Ethm1BridgeHandler;
@@ -43,6 +44,7 @@
import org.openhab.binding.satel.internal.handler.SatelZoneHandler;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
/**
* The {@link SatelHandlerFactory} is responsible for creating things and thing
@@ -59,6 +61,8 @@ public class SatelHandlerFactory extends BaseThingHandlerFactory {
private Map> discoveryServiceRegistrations = new ConcurrentHashMap<>();
+ private SerialPortManager serialPortManager;
+
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
@@ -87,7 +91,7 @@ protected ThingHandler createHandler(Thing thing) {
registerDiscoveryService(bridgeHandler);
return bridgeHandler;
} else if (IntRSBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
- SatelBridgeHandler bridgeHandler = new IntRSBridgeHandler((Bridge) thing);
+ SatelBridgeHandler bridgeHandler = new IntRSBridgeHandler((Bridge) thing, serialPortManager);
registerDiscoveryService(bridgeHandler);
return bridgeHandler;
} else if (SatelZoneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
@@ -118,6 +122,15 @@ protected void removeHandler(ThingHandler thingHandler) {
}
}
+ @Reference
+ protected void setSerialPortManager(final SerialPortManager serialPortManager) {
+ this.serialPortManager = serialPortManager;
+ }
+
+ protected void unsetSerialPortManager(final SerialPortManager serialPortManager) {
+ this.serialPortManager = null;
+ }
+
private void registerDiscoveryService(SatelBridgeHandler bridgeHandler) {
SatelDeviceDiscoveryService discoveryService = new SatelDeviceDiscoveryService(bridgeHandler,
(thingTypeUID) -> getThingTypeByUID(thingTypeUID));
diff --git a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/handler/IntRSBridgeHandler.java b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/handler/IntRSBridgeHandler.java
index f92ab07814eaf..c25b766527017 100644
--- a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/handler/IntRSBridgeHandler.java
+++ b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/handler/IntRSBridgeHandler.java
@@ -20,11 +20,13 @@
import java.util.Set;
import org.apache.commons.lang.StringUtils;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.config.core.status.ConfigStatusMessage;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
+import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.openhab.binding.satel.internal.config.IntRSConfig;
import org.openhab.binding.satel.internal.protocol.IntRSModule;
import org.openhab.binding.satel.internal.protocol.SatelModule;
@@ -37,14 +39,18 @@
*
* @author Krzysztof Goworek - Initial contribution
*/
+@NonNullByDefault
public class IntRSBridgeHandler extends SatelBridgeHandler {
public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_INTRS);
private final Logger logger = LoggerFactory.getLogger(IntRSBridgeHandler.class);
- public IntRSBridgeHandler(Bridge bridge) {
+ private final SerialPortManager serialPortManager;
+
+ public IntRSBridgeHandler(Bridge bridge, SerialPortManager serialPortManager) {
super(bridge);
+ this.serialPortManager = serialPortManager;
}
@Override
@@ -53,7 +59,7 @@ public void initialize() {
IntRSConfig config = getConfigAs(IntRSConfig.class);
if (StringUtils.isNotBlank(config.getPort())) {
- SatelModule satelModule = new IntRSModule(config.getPort(), config.getTimeout());
+ SatelModule satelModule = new IntRSModule(config.getPort(), serialPortManager, config.getTimeout());
super.initialize(satelModule);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
diff --git a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/IntRSModule.java b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/IntRSModule.java
index 6aba8de091dcd..b63a96fa3ad89 100644
--- a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/IntRSModule.java
+++ b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/IntRSModule.java
@@ -17,47 +17,49 @@
import java.io.OutputStream;
import java.util.TooManyListenersException;
-import javax.naming.ConfigurationException;
-
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.io.transport.serial.PortInUseException;
+import org.eclipse.smarthome.io.transport.serial.SerialPort;
+import org.eclipse.smarthome.io.transport.serial.SerialPortEvent;
+import org.eclipse.smarthome.io.transport.serial.SerialPortEventListener;
+import org.eclipse.smarthome.io.transport.serial.SerialPortIdentifier;
+import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
+import org.eclipse.smarthome.io.transport.serial.UnsupportedCommOperationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import gnu.io.CommPortIdentifier;
-import gnu.io.NoSuchPortException;
-import gnu.io.PortInUseException;
-import gnu.io.SerialPort;
-import gnu.io.SerialPortEvent;
-import gnu.io.SerialPortEventListener;
-import gnu.io.UnsupportedCommOperationException;
-
/**
* Represents Satel INT-RS module. Implements methods required to connect and
* communicate with that module over serial protocol.
*
* @author Krzysztof Goworek - Initial contribution
*/
+@NonNullByDefault
public class IntRSModule extends SatelModule {
private final Logger logger = LoggerFactory.getLogger(IntRSModule.class);
- private String port;
+ private final String port;
+
+ private final SerialPortManager serialPortManager;
/**
* Creates new instance with port and timeout set to specified values.
*
* @param port
- * serial port the module is connected to
+ * serial port the module is connected to
+ * @param serialPortManager
+ * serial port manager object
* @param timeout
- * timeout value in milliseconds for connect/read/write
- * operations
- * @throws ConfigurationException
- * unconditionally throws this exception as it is not
- * implemented yet
+ * timeout value in milliseconds for connect/read/write
+ * operations
*/
- public IntRSModule(String port, int timeout) {
+ public IntRSModule(String port, SerialPortManager serialPortManager, int timeout) {
super(timeout);
this.port = port;
+ this.serialPortManager = serialPortManager;
}
@Override
@@ -65,7 +67,10 @@ protected CommunicationChannel connect() throws ConnectionFailureException {
logger.info("Connecting to INT-RS module at {}", this.port);
try {
- CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(this.port);
+ SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(this.port);
+ if (portIdentifier == null) {
+ throw new ConnectionFailureException(String.format("Port %s does not exist", this.port));
+ }
SerialPort serialPort = portIdentifier.open("org.openhab.binding.satel", 2000);
serialPort.setSerialPortParams(19200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialPort.enableReceiveTimeout(this.getTimeout());
@@ -86,8 +91,6 @@ public void serialEvent(SerialPortEvent ev) {
logger.info("INT-RS module connected successfuly");
return new SerialCommunicationChannel(serialPort);
- } catch (NoSuchPortException e) {
- throw new ConnectionFailureException(String.format("Port %s does not exist", this.port), e);
} catch (PortInUseException e) {
throw new ConnectionFailureException(String.format("Port %s in use", this.port), e);
} catch (UnsupportedCommOperationException e) {
@@ -106,11 +109,13 @@ public SerialCommunicationChannel(SerialPort serialPort) {
}
@Override
+ @Nullable
public InputStream getInputStream() throws IOException {
return this.serialPort.getInputStream();
}
@Override
+ @Nullable
public OutputStream getOutputStream() throws IOException {
return this.serialPort.getOutputStream();
}
diff --git a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/SatelModule.java b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/SatelModule.java
index 46165b9649ebf..d02e043cc8483 100644
--- a/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/SatelModule.java
+++ b/bundles/org.openhab.binding.satel/src/main/java/org/openhab/binding/satel/internal/protocol/SatelModule.java
@@ -88,7 +88,11 @@ protected interface TimeoutTimer {
*/
protected static class ConnectionFailureException extends Exception {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
+
+ public ConnectionFailureException(String message) {
+ super(message);
+ }
public ConnectionFailureException(String message, Throwable cause) {
super(message, cause);
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java
index 4b48b6f01000c..7c945f6e4725b 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java
@@ -193,6 +193,8 @@ public class SomfyTahomaBindingConstants {
public static final String STATUS_STATE = "core:StatusState";
public static final String UNAVAILABLE = "unavailable";
public static final String AUTHENTICATION_CHALLENGE = "HTTP protocol violation: Authentication challenge without WWW-Authenticate header";
+ public static final String TOO_MANY_REQUESTS = "Too many requests, try again later";
+ public static final int SUSPEND_TIME = 120;
// supported uiClasses
public static final String ROLLERSHUTTER = "RollerShutter";
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/config/SomfyTahomaConfig.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/config/SomfyTahomaConfig.java
index c3a2abbecee49..61ca7bc8275e8 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/config/SomfyTahomaConfig.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/config/SomfyTahomaConfig.java
@@ -23,8 +23,7 @@
@NonNullByDefault
public class SomfyTahomaConfig {
private String email = "";
- private String password = "";
- private String thingUid = "";
+ private String password = "";
private int refresh = 30;
private int statusTimeout = 300;
@@ -36,14 +35,6 @@ public String getPassword() {
return password;
}
- public String getThingUid() {
- return thingUid;
- }
-
- public void setThingUid(String thingUid) {
- this.thingUid = thingUid;
- }
-
public int getRefresh() {
return refresh;
}
@@ -51,4 +42,12 @@ public int getRefresh() {
public int getStatusTimeout() {
return statusTimeout;
}
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
}
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/discovery/SomfyTahomaItemDiscoveryService.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/discovery/SomfyTahomaItemDiscoveryService.java
index 16f8535a5ecf0..429cc8505b06c 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/discovery/SomfyTahomaItemDiscoveryService.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/discovery/SomfyTahomaItemDiscoveryService.java
@@ -47,11 +47,9 @@ public class SomfyTahomaItemDiscoveryService extends AbstractDiscoveryService im
private SomfyTahomaBridgeHandler bridge;
- @Nullable
- private DiscoveryServiceCallback discoveryServiceCallback;
- @Nullable
- private ScheduledFuture> discoveryJob;
+ private @Nullable DiscoveryServiceCallback discoveryServiceCallback;
+ private @Nullable ScheduledFuture> discoveryJob;
private static final int DISCOVERY_TIMEOUT_SEC = 10;
private static final int DISCOVERY_REFRESH_SEC = 1800;
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBaseThingHandler.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBaseThingHandler.java
index c9c28b69ea129..036d91374debf 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBaseThingHandler.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBaseThingHandler.java
@@ -44,8 +44,7 @@ public abstract class SomfyTahomaBaseThingHandler extends BaseThingHandler {
protected HashMap stateNames = new HashMap<>();
//cache
- @Nullable
- private ExpiringCache> thingStates;
+ private @Nullable ExpiringCache> thingStates;
public SomfyTahomaBaseThingHandler(Thing thing) {
super(thing);
@@ -59,8 +58,12 @@ public HashMap getStateNames() {
public void initialize() {
thingStates = new ExpiringCache<>(CACHE_EXPIRY, () -> getThingStates());
- SomfyTahomaState state = getCachedThingState(STATUS_STATE);
- updateThingStatus(state);
+ if (ThingStatus.ONLINE == getBridge().getStatus()) {
+ SomfyTahomaState state = getCachedThingState(STATUS_STATE);
+ updateThingStatus(state);
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+ }
}
private synchronized @Nullable SomfyTahomaState getCachedThingState(String state) {
@@ -94,13 +97,13 @@ private String getURL() {
}
private void setAvailable() {
- if (!ThingStatus.ONLINE.equals(thing.getStatus())) {
+ if (ThingStatus.ONLINE != thing.getStatus()) {
updateStatus(ThingStatus.ONLINE);
}
}
private void setUnavailable() {
- if (!ThingStatus.OFFLINE.equals(thing.getStatus()) && !isAlwaysOnline()) {
+ if (ThingStatus.OFFLINE != thing.getStatus() && !isAlwaysOnline()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, UNAVAILABLE);
}
}
@@ -313,7 +316,7 @@ public void updateThingChannels(ArrayList states) {
if (isChannelLinked(channel)) {
State channelState = getChannelState(channel, states);
if (channelState != null) {
- logger.trace("Updating channel: {} with state: {}", channel.getUID(), channelState.toString());
+ logger.trace("Updating channel: {} with state: {}", channel.getUID(), channelState);
updateState(channel.getUID(), channelState);
} else {
logger.debug("Cannot find state for channel {}", channel.getUID());
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java
index 9145eb169bc50..9a8baad9c2345 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java
@@ -36,6 +36,9 @@
import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.*;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
@@ -62,15 +65,15 @@ public class SomfyTahomaBridgeHandler extends ConfigStatusBridgeHandler {
/**
* Future to poll for updates
*/
- @Nullable
- private ScheduledFuture> pollFuture;
+ private @Nullable ScheduledFuture> pollFuture;
/**
* Future to poll for status
*/
- @Nullable
- private ScheduledFuture> statusFuture;
+ private @Nullable ScheduledFuture> statusFuture;
+ // Too many request flag
+ private boolean tooManyRequests = false;
/**
* Our configuration
@@ -90,9 +93,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
@Override
public void initialize() {
- String thingUid = getThing().getUID().toString();
thingConfig = getConfigAs(SomfyTahomaConfig.class);
- thingConfig.setThingUid(thingUid);
httpClient.setFollowRedirects(false);
@@ -127,6 +128,10 @@ public synchronized void login() {
return;
}
+ if (tooManyRequests || ThingStatus.ONLINE == thing.getStatus()) {
+ return;
+ }
+
try {
if (httpClient.isStarted()) {
httpClient.stop();
@@ -134,27 +139,31 @@ public synchronized void login() {
httpClient.start();
url = TAHOMA_URL + "login";
- String urlParameters = "userId=" + thingConfig.getEmail() + "&userPassword=" + thingConfig.getPassword();
+ String urlParameters = "userId=" + urlEncode(thingConfig.getEmail()) + "&userPassword=" + urlEncode(thingConfig.getPassword());
ContentResponse response = sendRequestBuilder(url, HttpMethod.POST)
.content(new StringContentProvider(urlParameters), "application/x-www-form-urlencoded; charset=UTF-8")
.send();
- logger.trace("Login response: {}", response.getContentAsString());
+ if (logger.isTraceEnabled()) {
+ logger.trace("Login response: {}", response.getContentAsString());
+ }
+
SomfyTahomaLoginResponse data = gson.fromJson(response.getContentAsString(), SomfyTahomaLoginResponse.class);
if (data.isSuccess()) {
logger.debug("SomfyTahoma version: {}", data.getVersion());
updateStatus(ThingStatus.ONLINE);
} else {
- logger.debug("Login response: {}", response.getContentAsString());
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error logging in");
- throw new SomfyTahomaException(response.getContentAsString());
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error logging in: " + data.getError());
+ if (data.getError().startsWith(TOO_MANY_REQUESTS)) {
+ logger.debug("Too many requests error, suspending activity for {} seconds", SUSPEND_TIME);
+ tooManyRequests = true;
+ scheduler.schedule(this::enableLogin, SUSPEND_TIME, TimeUnit.SECONDS);
+ }
}
} catch (JsonSyntaxException e) {
logger.debug("Received invalid data", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Received invalid data");
- } catch (SomfyTahomaException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Unauthorized. Please check credentials");
} catch (InterruptedException | ExecutionException | TimeoutException e) {
logger.debug("Cannot get login cookie!", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Cannot get login cookie");
@@ -165,7 +174,15 @@ public synchronized void login() {
}
- private ArrayList getEvents() {
+ private String urlEncode(String text) throws UnsupportedEncodingException {
+ return URLEncoder.encode(text, StandardCharsets.UTF_8.toString());
+ }
+
+ private void enableLogin() {
+ tooManyRequests = false;
+ }
+
+ private List getEvents() {
String url;
String line = "";
@@ -319,12 +336,12 @@ private String getFormattedParameters(Collection stateNames) {
sb.append(',');
sb.append("{\"name\": \"").append(name).append("\"}");
}
- logger.debug("Formatted parameters: {}", sb.toString());
+ logger.trace("Formatted parameters: {}", sb);
return sb.toString();
}
- public @Nullable List getAllStates(Collection stateNames, String deviceUrl) {
+ public @Nullable synchronized List getAllStates(Collection stateNames, String deviceUrl) {
String url;
String line = "";
@@ -364,12 +381,11 @@ private String getFormattedParameters(Collection stateNames) {
private void getTahomaUpdates() {
logger.debug("Getting Tahoma Updates...");
- if (ThingStatus.OFFLINE.equals(thing.getStatus())) {
- logger.debug("Doing relogin");
- login();
+ if (ThingStatus.OFFLINE == thing.getStatus() && !reLogin()) {
+ return;
}
- ArrayList events = getEvents();
+ List events = getEvents();
logger.debug("Got total of {} events", events.size());
for (SomfyTahomaEvent event : events) {
processEvent(event);
@@ -415,7 +431,7 @@ private synchronized void updateAllStates() {
private void processStateChangedEvent(SomfyTahomaEvent event) {
String deviceUrl = event.getDeviceUrl();
ArrayList states = event.getDeviceStates();
- logger.debug("States for device {} : {}", deviceUrl, states.toString());
+ logger.debug("States for device {} : {}", deviceUrl, states);
Thing thing = getThingByDeviceUrl(deviceUrl);
if (thing != null) {
@@ -434,9 +450,8 @@ private void processStateChangedEvent(SomfyTahomaEvent event) {
private void refreshTahomaStates() {
logger.debug("Refreshing Tahoma states...");
- if (ThingStatus.OFFLINE.equals(thing.getStatus())) {
- logger.debug("Doing relogin");
- login();
+ if (ThingStatus.OFFLINE == thing.getStatus() && !reLogin()) {
+ return;
}
//force Tahoma to ask for actual states
@@ -467,7 +482,10 @@ private String sendDataToTahomaWithCookie(String url, String urlParameters) thro
.content(new StringContentProvider(urlParameters), "application/json;charset=UTF-8")
.send();
- logger.trace("Response: {}", response.getContentAsString());
+ if (logger.isTraceEnabled()) {
+ logger.trace("Response: {}", response.getContentAsString());
+ }
+
if (response.getStatus() < 200 || response.getStatus() >= 300) {
logger.error("Received error code: {}", response.getStatus());
if (response.getStatus() == 404) {
@@ -493,7 +511,10 @@ private String sendMethodToTahomaWithCookie(String url, HttpMethod method) throw
logger.trace("Sending {} to Tahoma to url: {}", method.asString(), url);
ContentResponse response = sendRequestBuilder(url, method).send();
- logger.trace("Response: {}", response.getContentAsString());
+ if (logger.isTraceEnabled()) {
+ logger.trace("Response: {}", response.getContentAsString());
+ }
+
if (response.getStatus() < 200 || response.getStatus() >= 300) {
logger.error("Received error code: {}", response.getStatus());
if (response.getStatus() == 404) {
@@ -514,6 +535,10 @@ private Request sendRequestBuilder(String url, HttpMethod method) {
}
public void sendCommand(String io, String command, String params) {
+ if (ThingStatus.OFFLINE == thing.getStatus() && !reLogin()) {
+ return;
+ }
+
Boolean result = sendCommandInternal(io, command, params);
if (result != null && !result) {
sendCommandInternal(io, command, params);
@@ -689,12 +714,21 @@ public void cancelExecution(String executionId) {
}
public void executeActionGroup(String id) {
+ if (ThingStatus.OFFLINE == thing.getStatus() && !reLogin()) {
+ return;
+ }
String execId = executeActionGroupInternal(id);
if (UNAUTHORIZED.equals(execId)) {
executeActionGroupInternal(id);
}
}
+ private boolean reLogin() {
+ logger.debug("Doing relogin");
+ login();
+ return ThingStatus.OFFLINE != thing.getStatus();
+ }
+
public @Nullable String executeActionGroupInternal(String id) {
String line = "";
try {
@@ -777,4 +811,15 @@ public void refreshDeviceStates() {
private boolean isAuthenticationChallenge(Exception ex) {
return ex.getMessage().contains(AUTHENTICATION_CHALLENGE);
}
+
+ @Override
+ public void handleConfigurationUpdate(Map configurationParameters) {
+ super.handleConfigurationUpdate(configurationParameters);
+ if (configurationParameters.containsKey("email")) {
+ thingConfig.setEmail(configurationParameters.get("email").toString());
+ }
+ if (configurationParameters.containsKey("password")) {
+ thingConfig.setPassword(configurationParameters.get("password").toString());
+ }
+ }
}
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaWindowHandler.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaWindowHandler.java
index 27ff3e4487800..6f3180b6d72e9 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaWindowHandler.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaWindowHandler.java
@@ -12,8 +12,6 @@
*/
package org.openhab.binding.somfytahoma.internal.handler;
-import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.*;
-
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
@@ -22,6 +20,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.*;
+
/**
* The {@link SomfyTahomaWindowHandler} is responsible for handling commands,
* which are sent to one of the channels of the window thing.
@@ -48,19 +48,17 @@ public void handleCommand(ChannelUID channelUID, Command command) {
updateChannelState(channelUID);
} else {
String cmd = getTahomaCommand(command.toString());
- //Check if the rollershutter is not moving
- String executionId = getCurrentExecutions();
- if (executionId != null) {
- //STOP command should be interpreted if rollershutter is moving
- //otherwise do nothing
- if (COMMAND_STOP.equals(cmd)) {
+ if (COMMAND_STOP.equals(cmd)) {
+ //Check if the window is not moving
+ String executionId = getCurrentExecutions();
+ if (executionId != null) {
+ //STOP command should be interpreted if window is moving
+ //otherwise do nothing
cancelExecution(executionId);
}
} else {
- if (!cmd.equals(COMMAND_STOP)) {
- String param = COMMAND_SET_CLOSURE.equals(cmd) ? "[" + command.toString() + "]" : "[]";
- sendCommand(cmd, param);
- }
+ String param = COMMAND_SET_CLOSURE.equals(cmd) ? "[" + command.toString() + "]" : "[]";
+ sendCommand(cmd, param);
}
}
}
diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/model/SomfyTahomaLoginResponse.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/model/SomfyTahomaLoginResponse.java
index a55a9f0a53e65..d7772046d223d 100644
--- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/model/SomfyTahomaLoginResponse.java
+++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/model/SomfyTahomaLoginResponse.java
@@ -25,6 +25,7 @@ public class SomfyTahomaLoginResponse {
private boolean success;
private String version = "";
+ private String error = "";
public boolean isSuccess() {
return success;
@@ -33,4 +34,8 @@ public boolean isSuccess() {
public String getVersion() {
return version;
}
+
+ public String getError() {
+ return error;
+ }
}
diff --git a/bundles/org.openhab.binding.sonyaudio/src/main/java/org/openhab/binding/sonyaudio/internal/protocol/SonyAudioClientSocket.java b/bundles/org.openhab.binding.sonyaudio/src/main/java/org/openhab/binding/sonyaudio/internal/protocol/SonyAudioClientSocket.java
index 8e26f37111bb8..4143593af2d1c 100644
--- a/bundles/org.openhab.binding.sonyaudio/src/main/java/org/openhab/binding/sonyaudio/internal/protocol/SonyAudioClientSocket.java
+++ b/bundles/org.openhab.binding.sonyaudio/src/main/java/org/openhab/binding/sonyaudio/internal/protocol/SonyAudioClientSocket.java
@@ -24,6 +24,7 @@
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
+import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
@@ -191,6 +192,11 @@ public void onClose(int statusCode, String reason) {
}
});
}
+
+ @OnWebSocketError
+ public void onError(Throwable error) {
+ onClose(0, error.getMessage());
+ }
}
private void sendMessage(String str) throws IOException {
diff --git a/bundles/org.openhab.binding.tellstick/pom.xml b/bundles/org.openhab.binding.tellstick/pom.xml
index 35695560ce5e7..b86b2d782036f 100644
--- a/bundles/org.openhab.binding.tellstick/pom.xml
+++ b/bundles/org.openhab.binding.tellstick/pom.xml
@@ -38,9 +38,9 @@
provided
- javax.activation
- activation
- 1.1.1
+ org.apache.servicemix.specs
+ org.apache.servicemix.specs.activation-api-1.1
+ 2.9.0provided
diff --git a/bundles/org.openhab.binding.tplinksmarthome/.classpath b/bundles/org.openhab.binding.tplinksmarthome/.classpath
index a5d95095ccaaf..7737f39c03922 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/.classpath
+++ b/bundles/org.openhab.binding.tplinksmarthome/.classpath
@@ -13,11 +13,12 @@
+
-
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/README.md b/bundles/org.openhab.binding.tplinksmarthome/README.md
index 7050ee6fb8a03..51d2a96c441c7 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/README.md
+++ b/bundles/org.openhab.binding.tplinksmarthome/README.md
@@ -26,7 +26,10 @@ The following TP-Link Smart Devices are supported:
### HS107 Smart Wi-Fi Plug, 2-Outlets
-Not supported yet.
+* Switch On/Off Group
+* Switch On/Off Outlets
+* Led On/Off
+* Wi-Fi signal strength (rssi)
### HS110 Smart Wi-Fi Plug
@@ -64,7 +67,11 @@ Switching via openHAB activates the switch directly.
### HS300 Smart Wi-Fi Power Strip
-Not supported yet.
+* Switch On/Off Group
+* Switch On/Off Outlets
+* Energy readings Outlets
+* Led On/Off
+* Wi-Fi signal strength (rssi)
### KB100 Kasa Smart Light Bulb
@@ -94,11 +101,17 @@ Switching, Brightness and Color is done using the `color` channel.
### KP200 Smart Wi-Fi Power Outlet, 2-Sockets
-Not supported yet.
+* Switch On/Off Group
+* Switch On/Off Outlets
+* Led On/Off
+* Wi-Fi signal strength (rssi)
### KP400 Smart Outdoor Plug
-Not supported yet.
+* Switch On/Off Group
+* Switch On/Off Outlets
+* Led On/Off
+* Wi-Fi signal strength (rssi)
### LB100 Smart Wi-Fi LED Bulb with Dimmable Light
@@ -241,33 +254,44 @@ Either `deviceId` or `ipAddress` must be set.
All devices support some of the following channels:
-| Channel Type ID | Item Type | Description | Thing types supporting this channel |
-|------------------|-----------|----------------------------------------------------|-----------------------------------------------------------------|
-| switch | Switch | Switch the Smart Home device on or off. | HS100, HS103, HS105, HS110, HS200, HS210, KP100, RE270K, RE370K |
-| brightness | Dimmer | Set the brightness of Smart Home device or dimmer. | HS220, KB100, KL110, KL120, LB100, LB110, LB120, LB200 |
-| colorTemperature | Dimmer | Set the color temperature of Smart Home light. | KB130, KL120, KL130, LB120, LB130, LB230 |
-| color | Color | Set the color of the Smart Home light. | KB130, KL130, LB130, LB230 |
-| power | Number | Actual energy usage in Watt. | HS110, KLxxx, LBxxx |
-| eneryUsage | Number | Energy Usage in kWh. | HS110 |
-| current | Number | Actual current usage in Ampere. | HS110 |
-| voltage | Number | Actual voltage usage in Volt. | HS110 |
-| led | Switch | Switch the status led on the device on or off. | HS100, HS103, HS105, HS110, HS200, HS210, HS220, KP100 |
-| rssi | Number | Wi-Fi signal strength indicator in dBm. | All |
+| Channel Type ID | Item Type | Description | Thing types supporting this channel |
+|------------------|-----------|----------------------------------------------------|---------------------------------------------------------------------------------------------|
+| switch | Switch | Switch the Smart Home device on or off. | HS100, HS103, HS105, HS107, HS110, HS200, HS210, HS300, KP100, KP200, KP400, RE270K, RE370K |
+| brightness | Dimmer | Set the brightness of Smart Home device or dimmer. | HS220, KB100, KL110, KL120, LB100, LB110, LB120, LB200 |
+| colorTemperature | Dimmer | Set the color temperature of Smart Home light. | KB130, KL120, KL130, LB120, LB130, LB230 |
+| color | Color | Set the color of the Smart Home light. | KB130, KL130, LB130, LB230 |
+| power | Number | Actual energy usage in Watt. | HS110, HS300, KLxxx, LBxxx |
+| eneryUsage | Number | Energy Usage in kWh. | HS110, HS300 |
+| current | Number | Actual current usage in Ampere. | HS110, HS300 |
+| voltage | Number | Actual voltage usage in Volt. | HS110, HS300 |
+| led | Switch | Switch the status led on the device on or off. | HS100, HS103, HS105, HS107, HS110, HS200, HS210, HS220, HS300, KP100, KP200, KP400 |
+| rssi | Number | Wi-Fi signal strength indicator in dBm. | All |
+
+The outlet devices (HS107, HS300, KP200, KP400) have group channels.
+This means the channel is prefixed with the group id.
+The following group ids are available:
+
+| Group ID | Description |
+|-------------------|-------------------------------------------------------------------------------------------------------|
+| groupSwitch | General channels. e.g. `groupSwitch#switch` |
+| outlet<number> | The outlet to control. <number> is the number of the outlet (starts with 1). e.g. `outlet1#switch` |
## Full Example
### tplinksmarthome.things:
```
-tplinksmarthome:hs100:tv "Living Room" [ deviceId="00000000000000000000000000000001", refresh=60 ]
-tplinksmarthome:lb110:bulb1 "Living Room Bulb 1" [ deviceId="00000000000000000000000000000002", refresh=60, transitionPeriod=2500 ]
-tplinksmarthome:lb130:bulb2 "Living Room Bulb 2" [ deviceId="00000000000000000000000000000003", refresh=60, transitionPeriod=2500 ]
+tplinksmarthome:hs100:tv "TV" [ deviceId="00000000000000000000000000000001", refresh=60 ]
+tplinksmarthome:hs300:laptop "Laptop" [ deviceId="00000000000000000000000000000004", refresh=60 ]
+tplinksmarthome:lb110:bulb1 "Living Room Bulb 1" [ deviceId="00000000000000000000000000000002", refresh=60, transitionPeriod=2500 ]
+tplinksmarthome:lb130:bulb2 "Living Room Bulb 2" [ deviceId="00000000000000000000000000000003", refresh=60, transitionPeriod=2500 ]
```
### tplinksmarthome.items:
```
-Switch TP_L_Switch "Switch" { channel="tplinksmarthome:hs100:tv:switch" }
+Switch TP_L_TV "TV" { channel="tplinksmarthome:hs100:tv:switch" }
+Switch TP_L_Laptop "Laptop" { channel="tplinksmarthome:hs300:laptop:outlet1#switch" }
Number TP_L_RSSI "Signal [%d] dB" { channel="tplinksmarthome:hs100:tv:rssi" }
Dimmer TP_LB_Bulb "Dimmer [%d %%]" { channel="tplinksmarthome:lb110:bulb1:brightness" }
Dimmer TP_LB_ColorT "Color Temperature [%d] %%" { channel="tplinksmarthome:lb130:bulb2:colorTemperature" }
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Commands.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Commands.java
index 16037e3e2b250..59594c3b437f1 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Commands.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Commands.java
@@ -13,6 +13,7 @@
package org.openhab.binding.tplinksmarthome.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.openhab.binding.tplinksmarthome.internal.model.GetRealtime;
@@ -43,10 +44,11 @@
@NonNullByDefault
public class Commands {
+ private static final String CONTEXT = "{\"context\":{\"child_ids\":[\"%s\"]},";
private static final String SYSTEM_GET_SYSINFO = "\"system\":{\"get_sysinfo\":{}}";
private static final String GET_SYSINFO = "{" + SYSTEM_GET_SYSINFO + "}";
- private static final String GET_REALTIME_AND_SYSINFO = "{" + SYSTEM_GET_SYSINFO
- + ", \"emeter\":{\"get_realtime\":{}}}";
+ private static final String REALTIME = "\"emeter\":{\"get_realtime\":{}}";
+ private static final String GET_REALTIME_AND_SYSINFO = "{" + SYSTEM_GET_SYSINFO + ", " + REALTIME + "}";
private static final String GET_REALTIME_BULB_AND_SYSINFO = "{" + SYSTEM_GET_SYSINFO
+ ", \"smartlife.iot.common.emeter\":{\"get_realtime\":{}}}";
@@ -71,6 +73,16 @@ public static String getRealtimeBulbAndSysinfo() {
return GET_REALTIME_BULB_AND_SYSINFO;
}
+ /**
+ * Returns the json to get the energy and sys info data from an outlet device.
+ *
+ * @param id optional id of the device
+ * @return The json string of the command to send to the device
+ */
+ public static String getRealtimeWithContext(String id) {
+ return String.format(CONTEXT, id) + REALTIME + "}";
+ }
+
/**
* Returns the json response of the get_realtime command to the data object.
*
@@ -108,11 +120,15 @@ public Sysinfo getSysinfoReponse(String getSysinfoReponse) {
* Returns the json for the set_relay_state command to switch on or off.
*
* @param onOff the switch state to set
+ * @param childId optional child id if multiple children are supported by a single device
* @return The json string of the command to send to the device
*/
- public String setRelayState(OnOffType onOff) {
+ public String setRelayState(OnOffType onOff, @Nullable String childId) {
SetRelayState relayState = new SetRelayState();
relayState.setRelayState(onOff);
+ if (childId != null) {
+ relayState.setChildId(childId);
+ }
return gsonWithExpose.toJson(relayState);
}
@@ -122,7 +138,7 @@ public String setRelayState(OnOffType onOff) {
* @param relayStateResponse the json string
* @return The data object containing the state data from the json string
*/
- public SetRelayState setRelayStateResponse(String relayStateResponse) {
+ public @Nullable SetRelayState setRelayStateResponse(String relayStateResponse) {
return gsonWithExpose.fromJson(relayStateResponse, SetRelayState.class);
}
@@ -144,7 +160,7 @@ public String setSwitchState(OnOffType onOff) {
* @param switchStateResponse the json string
* @return The data object containing the state data from the json string
*/
- public SetSwitchState setSwitchStateResponse(String switchStateResponse) {
+ public @Nullable SetSwitchState setSwitchStateResponse(String switchStateResponse) {
return gsonWithExpose.fromJson(switchStateResponse, SetSwitchState.class);
}
@@ -166,7 +182,7 @@ public String setDimmerBrightness(int brightness) {
* @param dimmerBrightnessResponse the json string
* @return The data object containing the state data from the json string
*/
- public HasErrorResponse setDimmerBrightnessResponse(String dimmerBrightnessResponse) {
+ public @Nullable HasErrorResponse setDimmerBrightnessResponse(String dimmerBrightnessResponse) {
return gsonWithExpose.fromJson(dimmerBrightnessResponse, SetBrightness.class);
}
@@ -190,11 +206,15 @@ public String setLightState(OnOffType onOff, int transitionPeriod) {
* Returns the json for the set_led_off command to switch the led of the device on or off.
*
* @param onOff the led state to set
+ * @param childId optional child id if multiple children are supported by a single device
* @return The json string of the command to send to the device
*/
- public String setLedOn(OnOffType onOff) {
+ public String setLedOn(OnOffType onOff, @Nullable String childId) {
SetLedOff sLOff = new SetLedOff();
sLOff.setLed(onOff);
+ if (childId != null) {
+ sLOff.setChildId(childId);
+ }
return gsonWithExpose.toJson(sLOff);
}
@@ -204,7 +224,7 @@ public String setLedOn(OnOffType onOff) {
* @param setLedOnResponse the json string
* @return The data object containing the data from the json string
*/
- public SetLedOff setLedOnResponse(String setLedOnResponse) {
+ public @Nullable SetLedOff setLedOnResponse(String setLedOnResponse) {
return gsonWithExpose.fromJson(setLedOnResponse, SetLedOff.class);
}
@@ -268,7 +288,7 @@ public String setColorTemperature(int colorTemperature, int transitionPeriod) {
* @param response the json string
* @return The data object containing the state data from the json string
*/
- public TransitionLightStateResponse setTransitionLightStateResponse(String response) {
+ public @Nullable TransitionLightStateResponse setTransitionLightStateResponse(String response) {
return gson.fromJson(response, TransitionLightStateResponse.class);
}
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Connection.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Connection.java
index a734c4e3afb1d..76076d84758c8 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Connection.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/Connection.java
@@ -67,7 +67,7 @@ public String sendCommand(String command) throws IOException {
logger.trace("Executing command: {}", command);
try (Socket socket = createSocket(); final OutputStream outputStream = socket.getOutputStream()) {
outputStream.write(CryptUtil.encryptWithLength(command));
- String response = readReturnValue(socket);
+ final String response = readReturnValue(socket);
logger.trace("Command response: {}", response);
return response;
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeBindingConstants.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeBindingConstants.java
index 728d3524ebe6f..7354234415488 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeBindingConstants.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeBindingConstants.java
@@ -29,7 +29,7 @@ public final class TPLinkSmartHomeBindingConstants {
public static final String BINDING_ID = "tplinksmarthome";
- // List of all channel ids
+ // List of all switch channel ids
public static final String CHANNEL_SWITCH = "switch";
// List of all plug channel ids
@@ -60,6 +60,10 @@ public final class TPLinkSmartHomeBindingConstants {
// List of all misc channel ids
public static final String CHANNEL_RSSI = "rssi";
+ // List of all group channel ids
+ public static final String CHANNEL_SWITCH_GROUP = "group";
+ public static final String CHANNEL_OUTLET_GROUP_PREFIX = "outlet";
+
// List of configuration keys
public static final String CONFIG_IP = "ipAddress";
public static final String CONFIG_DEVICE_ID = "deviceId";
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeDiscoveryService.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeDiscoveryService.java
index a7235a0a6efcb..e8656a7df83b6 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeDiscoveryService.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeDiscoveryService.java
@@ -48,7 +48,7 @@
* @author Hilbrand Bouwkamp - Complete make-over, reorganized code and code cleanup.
*/
@Component(service = { DiscoveryService.class,
- TPLinkIpAddressService.class }, immediate = true, configurationPid = "discovery.tplinksmarthome")
+TPLinkIpAddressService.class }, immediate = true, configurationPid = "discovery.tplinksmarthome")
@NonNullByDefault
public class TPLinkSmartHomeDiscoveryService extends AbstractDiscoveryService implements TPLinkIpAddressService {
@@ -69,7 +69,7 @@ public class TPLinkSmartHomeDiscoveryService extends AbstractDiscoveryService im
public TPLinkSmartHomeDiscoveryService() throws UnknownHostException {
super(SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT_SECONDS);
InetAddress broadcast = InetAddress.getByName(BROADCAST_IP);
- byte[] discoverbuffer = CryptUtil.encrypt(Commands.getSysinfo());
+ final byte[] discoverbuffer = CryptUtil.encrypt(Commands.getSysinfo());
discoverPacket = new DatagramPacket(discoverbuffer, discoverbuffer.length, broadcast,
Connection.TP_LINK_SMART_HOME_PORT);
}
@@ -106,7 +106,7 @@ protected void startScan() {
if (discoverSocket == null) {
break;
}
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+ final DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
discoverSocket.receive(packet);
logger.debug("TP-Link Smart device discovery returned package with length {}", packet.getLength());
@@ -139,7 +139,8 @@ protected void stopScan() {
* @throws IOException exception in case sending the packet failed
*/
protected DatagramSocket sendDiscoveryPacket() throws IOException {
- DatagramSocket ds = new DatagramSocket(null);
+ final DatagramSocket ds = new DatagramSocket(null);
+
ds.setBroadcast(true);
ds.setSoTimeout(UDP_PACKET_TIMEOUT_MS);
ds.send(discoverPacket);
@@ -165,24 +166,25 @@ private void closeDiscoverSocket() {
* @throws IOException in case decrypting of the data failed
*/
private void detectThing(DatagramPacket packet) throws IOException {
- String ipAddress = packet.getAddress().getHostAddress();
- String rawData = CryptUtil.decrypt(packet.getData(), packet.getLength());
- Sysinfo sysinfoRaw = commands.getSysinfoReponse(rawData);
- Sysinfo sysinfo = sysinfoRaw.getActualSysinfo();
+ final String ipAddress = packet.getAddress().getHostAddress();
+ final String rawData = CryptUtil.decrypt(packet.getData(), packet.getLength());
+ final Sysinfo sysinfoRaw = commands.getSysinfoReponse(rawData);
+ final Sysinfo sysinfo = sysinfoRaw.getActualSysinfo();
logger.trace("Detected TP-Link Smart Home device: {}", rawData);
- String deviceId = sysinfo.getDeviceId();
+ final String deviceId = sysinfo.getDeviceId();
logger.debug("TP-Link Smart Home device '{}' with id {} found on {} ", sysinfo.getAlias(), deviceId, ipAddress);
idInetAddressCache.put(deviceId, ipAddress);
- Optional thingTypeUID = getThingTypeUID(sysinfo.getModel());
+ final Optional thingTypeUID = getThingTypeUID(sysinfo.getModel());
if (thingTypeUID.isPresent()) {
- ThingUID thingUID = new ThingUID(thingTypeUID.get(),
+ final ThingUID thingUID = new ThingUID(thingTypeUID.get(),
deviceId.substring(deviceId.length() - 6, deviceId.length()));
- Map properties = PropertiesCollector.collectProperties(thingTypeUID.get(), ipAddress,
+ final Map properties = PropertiesCollector.collectProperties(thingTypeUID.get(), ipAddress,
sysinfoRaw);
- DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(sysinfo.getAlias())
- .withRepresentationProperty(deviceId).withProperties(properties).build();
+ final DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
+ .withLabel(sysinfo.getAlias()).withRepresentationProperty(deviceId).withProperties(properties)
+ .build();
thingDiscovered(discoveryResult);
} else {
logger.debug("Detected, but ignoring unsupported TP-Link Smart Home device model '{}'", sysinfo.getModel());
@@ -196,7 +198,7 @@ private void detectThing(DatagramPacket packet) throws IOException {
* @return {@link ThingTypeUID} or null if device not recognized
*/
private Optional getThingTypeUID(String model) {
- String modelLC = model.toLowerCase(Locale.ENGLISH);
+ final String modelLC = model.toLowerCase(Locale.ENGLISH);
return SUPPORTED_THING_TYPES.stream().filter(suid -> modelLC.startsWith(suid.getId())).findFirst();
}
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeHandlerFactory.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeHandlerFactory.java
index e25ebe580e3fb..5bb9eecfebea4 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeHandlerFactory.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeHandlerFactory.java
@@ -25,6 +25,7 @@
import org.openhab.binding.tplinksmarthome.internal.device.BulbDevice;
import org.openhab.binding.tplinksmarthome.internal.device.DimmerDevice;
import org.openhab.binding.tplinksmarthome.internal.device.EnergySwitchDevice;
+import org.openhab.binding.tplinksmarthome.internal.device.PowerStripDevice;
import org.openhab.binding.tplinksmarthome.internal.device.RangeExtenderDevice;
import org.openhab.binding.tplinksmarthome.internal.device.SmartHomeDevice;
import org.openhab.binding.tplinksmarthome.internal.device.SwitchDevice;
@@ -52,8 +53,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@Nullable
@Override
protected ThingHandler createHandler(Thing thing) {
- ThingTypeUID thingTypeUID = thing.getThingTypeUID();
- SmartHomeDevice device;
+ final ThingTypeUID thingTypeUID = thing.getThingTypeUID();
+ final SmartHomeDevice device;
if (HS110.is(thingTypeUID)) {
device = new EnergySwitchDevice();
@@ -63,6 +64,8 @@ protected ThingHandler createHandler(Thing thing) {
device = new BulbDevice(thingTypeUID, COLOR_TEMPERATURE_LB130_MIN, COLOR_TEMPERATURE_LB130_MAX);
} else if (LB120.is(thingTypeUID) || KL120.is(thingTypeUID)) {
device = new BulbDevice(thingTypeUID, COLOR_TEMPERATURE_LB120_MIN, COLOR_TEMPERATURE_LB120_MAX);
+ } else if (TPLinkSmartHomeThingType.isStripDevice(thingTypeUID)) {
+ device = new PowerStripDevice(thingTypeUID);
} else if (TPLinkSmartHomeThingType.isSwitchingDevice(thingTypeUID)) {
device = new SwitchDevice();
} else if (TPLinkSmartHomeThingType.isBulbDevice(thingTypeUID)) {
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeThingType.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeThingType.java
index 354e94bd27c2d..5e9a807c131cb 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeThingType.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/TPLinkSmartHomeThingType.java
@@ -27,7 +27,7 @@
*
*/
@NonNullByDefault
-enum TPLinkSmartHomeThingType {
+public enum TPLinkSmartHomeThingType {
// Bulb Thing Type UIDs
KB100("kb100", DeviceType.BULB),
@@ -56,6 +56,12 @@ enum TPLinkSmartHomeThingType {
// Dimmer Thing Type UIDs
HS220("hs220", DeviceType.DIMMER),
+ // Power Strip Thing Type UIDs.
+ HS107("hs107", DeviceType.STRIP),
+ HS300("hs300", DeviceType.STRIP),
+ KP200("kp200", DeviceType.STRIP),
+ KP400("kp400", DeviceType.STRIP),
+
// Range Extender Thing Type UIDs
RE270K("re270", DeviceType.RANGE_EXTENDER),
RE370K("re370", DeviceType.RANGE_EXTENDER);
@@ -99,26 +105,38 @@ public static boolean isBulbDevice(ThingTypeUID thingTypeUID) {
}
/**
- * Returns true if the given {@link ThingTypeUID} matches a device that supports the switching communication
+ * Returns true if the given {@link ThingTypeUID} matches a device that is a range extender.
+ *
+ * @param thingTypeUID if the check
+ * @return true if it's a range extender
+ */
+ public static boolean isRangeExtenderDevice(ThingTypeUID thingTypeUID) {
+ return SUPPORTED_THING_TYPES_LIST.stream().filter(t -> t.is(thingTypeUID))
+ .anyMatch(t -> t.type == DeviceType.RANGE_EXTENDER);
+ }
+
+ /**
+ * Returns true if the given {@link ThingTypeUID} matches a device that supports the power strip communication
* protocol.
*
* @param thingTypeUID if the check
- * @return true if it's a switching supporting device
+ * @return true if it's a power strip supporting device
*/
- public static boolean isSwitchingDevice(ThingTypeUID thingTypeUID) {
+ public static boolean isStripDevice(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_LIST.stream().filter(t -> t.is(thingTypeUID))
- .anyMatch(t -> t.type == DeviceType.PLUG || t.type == DeviceType.SWITCH);
+ .anyMatch(t -> t.type == DeviceType.STRIP);
}
/**
- * Returns true if the given {@link ThingTypeUID} matches a device that is a range extender.
+ * Returns true if the given {@link ThingTypeUID} matches a device that supports the switching communication
+ * protocol.
*
* @param thingTypeUID if the check
- * @return true if it's a range extender
+ * @return true if it's a switching supporting device
*/
- public static boolean isRangeExtenderDevice(ThingTypeUID thingTypeUID) {
+ public static boolean isSwitchingDevice(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_LIST.stream().filter(t -> t.is(thingTypeUID))
- .anyMatch(t -> t.type == DeviceType.RANGE_EXTENDER);
+ .anyMatch(t -> t.type == DeviceType.PLUG || t.type == DeviceType.SWITCH);
}
/**
@@ -151,6 +169,10 @@ private enum DeviceType {
* Wi-Fi range extender device with plug.
*/
RANGE_EXTENDER,
+ /**
+ * Power strip device.
+ */
+ STRIP,
/**
* Switch device.
*/
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDevice.java
index 20b05acf52c4c..186999258a163 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDevice.java
@@ -22,13 +22,12 @@
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.tplinksmarthome.internal.Commands;
-import org.openhab.binding.tplinksmarthome.internal.Connection;
-import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
import org.openhab.binding.tplinksmarthome.internal.model.LightState;
import org.openhab.binding.tplinksmarthome.internal.model.TransitionLightStateResponse;
@@ -63,17 +62,17 @@ public String getUpdateCommand() {
}
@Override
- public boolean handleCommand(String channelID, Connection connection, Command command,
- TPLinkSmartHomeConfiguration configuration) throws IOException {
- int transitionPeriod = configuration.transitionPeriod;
- HasErrorResponse response;
+ public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
+ final String channelId = channelUid.getId();
+ final int transitionPeriod = configuration.transitionPeriod;
+ final HasErrorResponse response;
if (command instanceof OnOffType) {
- response = handleOnOffType(channelID, connection, (OnOffType) command, transitionPeriod);
+ response = handleOnOffType(channelId, (OnOffType) command, transitionPeriod);
} else if (command instanceof HSBType) {
- response = handleHSBType(channelID, connection, (HSBType) command, transitionPeriod);
+ response = handleHSBType(channelId, (HSBType) command, transitionPeriod);
} else if (command instanceof DecimalType) {
- response = handleDecimalType(channelID, connection, (DecimalType) command, transitionPeriod);
+ response = handleDecimalType(channelId, (DecimalType) command, transitionPeriod);
} else {
return false;
}
@@ -81,9 +80,8 @@ public boolean handleCommand(String channelID, Connection connection, Command co
return response != null;
}
- @Nullable
- private HasErrorResponse handleOnOffType(String channelID, Connection connection, OnOffType onOff,
- int transitionPeriod) throws IOException {
+ private @Nullable HasErrorResponse handleOnOffType(String channelID, OnOffType onOff, int transitionPeriod)
+ throws IOException {
if (CHANNELS_BULB_SWITCH.contains(channelID)) {
return commands.setTransitionLightStateResponse(
connection.sendCommand(commands.setLightState(onOff, transitionPeriod)));
@@ -91,27 +89,25 @@ private HasErrorResponse handleOnOffType(String channelID, Connection connection
return null;
}
- @Nullable
- private HasErrorResponse handleDecimalType(String channelID, Connection connection, DecimalType command,
- int transitionPeriod) throws IOException {
+ private @Nullable HasErrorResponse handleDecimalType(String channelID, DecimalType command, int transitionPeriod)
+ throws IOException {
if (CHANNEL_COLOR.equals(channelID) || CHANNEL_BRIGHTNESS.equals(channelID)) {
return commands.setTransitionLightStateResponse(
connection.sendCommand(commands.setBrightness(command.intValue(), transitionPeriod)));
} else if (CHANNEL_COLOR_TEMPERATURE.equals(channelID)) {
- return handleColorTemperature(connection, convertPercentageToKelvin(command.intValue()), transitionPeriod);
+ return handleColorTemperature(convertPercentageToKelvin(command.intValue()), transitionPeriod);
}
return null;
}
- private TransitionLightStateResponse handleColorTemperature(Connection connection, int colorTemperature,
- int transitionPeriod) throws IOException {
+ private @Nullable TransitionLightStateResponse handleColorTemperature(int colorTemperature, int transitionPeriod)
+ throws IOException {
return commands.setTransitionLightStateResponse(
connection.sendCommand(commands.setColorTemperature(colorTemperature, transitionPeriod)));
}
@Nullable
- private HasErrorResponse handleHSBType(String channelID, Connection connection, HSBType command,
- int transitionPeriod) throws IOException {
+ private HasErrorResponse handleHSBType(String channelID, HSBType command, int transitionPeriod) throws IOException {
if (CHANNEL_COLOR.equals(channelID)) {
return commands.setTransitionLightStateResponse(
connection.sendCommand(commands.setColor(command, transitionPeriod)));
@@ -120,11 +116,11 @@ private HasErrorResponse handleHSBType(String channelID, Connection connection,
}
@Override
- public State updateChannel(String channelId, DeviceState deviceState) {
- LightState lightState = deviceState.getSysinfo().getLightState();
+ public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
+ final LightState lightState = deviceState.getSysinfo().getLightState();
final State state;
- switch (channelId) {
+ switch (channelUid.getId()) {
case CHANNEL_BRIGHTNESS:
state = lightState.getBrightness();
break;
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDevice.java
index 3541366ad74f1..b2566119c30ce 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDevice.java
@@ -20,10 +20,9 @@
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
-import org.openhab.binding.tplinksmarthome.internal.Connection;
-import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
/**
@@ -35,33 +34,30 @@
public class DimmerDevice extends SwitchDevice {
@Override
- protected @Nullable HasErrorResponse setOnOffState(Connection connection, OnOffType onOff) throws IOException {
+ protected @Nullable HasErrorResponse setOnOffState(ChannelUID channelUid, OnOffType onOff) throws IOException {
return commands.setSwitchStateResponse(connection.sendCommand(commands.setSwitchState(onOff)));
}
@Override
- public boolean handleCommand(String channelId, Connection connection, Command command,
- TPLinkSmartHomeConfiguration configuration) throws IOException {
- return CHANNEL_BRIGHTNESS.equals(channelId)
- ? handleBrightnessChannel(channelId, connection, command, configuration)
- : super.handleCommand(channelId, connection, command, configuration);
+ public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
+ return CHANNEL_BRIGHTNESS.equals(channelUid.getId()) ? handleBrightnessChannel(channelUid, command)
+ : super.handleCommand(channelUid, command);
}
/**
* Handle the brightness channel. Because the device has different commands for setting the device on/off and
* setting the brightness the on/off command must be send to the device as well when the brightness.
*
- * @param connection Connection to use
+ * @param channelUid uid of the channel to handle
* @param command command to the send
* @return returns true if the command was handled
* @throws IOException throws an {@link IOException} if the command handling failed
*/
- private boolean handleBrightnessChannel(String channelId, Connection connection, Command command,
- TPLinkSmartHomeConfiguration configuration) throws IOException {
+ private boolean handleBrightnessChannel(ChannelUID channelUid, Command command) throws IOException {
HasErrorResponse response = null;
if (command instanceof OnOffType) {
- response = setOnOffState(connection, (OnOffType) command);
+ response = setOnOffState(channelUid, (OnOffType) command);
} else if (command instanceof PercentType) {
PercentType percentCommand = (PercentType) command;
@@ -70,7 +66,7 @@ private boolean handleBrightnessChannel(String channelId, Connection connection,
response = commands.setDimmerBrightnessResponse(
connection.sendCommand(commands.setDimmerBrightness(percentCommand.intValue())));
} else {
- response = setOnOffState(connection, OnOffType.OFF);
+ response = setOnOffState(channelUid, OnOffType.OFF);
}
}
checkErrors(response);
@@ -78,12 +74,12 @@ private boolean handleBrightnessChannel(String channelId, Connection connection,
}
@Override
- public State updateChannel(String channelId, DeviceState deviceState) {
- if (CHANNEL_BRIGHTNESS.equals(channelId)) {
+ public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
+ if (CHANNEL_BRIGHTNESS.equals(channelUid.getId())) {
return deviceState.getSysinfo().getRelayState() == OnOffType.OFF ? PercentType.ZERO
: new PercentType(deviceState.getSysinfo().getBrightness());
} else {
- return super.updateChannel(channelId, deviceState);
+ return super.updateChannel(channelUid, deviceState);
}
}
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDevice.java
index 33701d3cec2cd..8849b548acbe8 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDevice.java
@@ -16,6 +16,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.DecimalType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.tplinksmarthome.internal.Commands;
import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
@@ -34,18 +35,26 @@ public String getUpdateCommand() {
}
@Override
- public State updateChannel(String channelId, DeviceState deviceState) {
+ public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
final State state;
+ final String matchChannelId = channelUid.isInGroup() ? channelUid.getIdWithoutGroup() : channelUid.getId();
- if (CHANNELS_ENERGY.contains(channelId)) {
- state = updateEnergyChannel(channelId, deviceState.getRealtime());
+ if (CHANNELS_ENERGY.contains(matchChannelId)) {
+ state = updateEnergyChannel(matchChannelId, deviceState.getRealtime());
} else {
- state = super.updateChannel(channelId, deviceState);
+ state = super.updateChannel(channelUid, deviceState);
}
return state;
}
- private State updateEnergyChannel(String channelId, Realtime realtime) {
+ /**
+ * Gets the state for an energy channel.
+ *
+ * @param channelId Id of the energy channel to get the state
+ * @param realtime data object containing the data from the device
+ * @return state object for the given channel
+ */
+ protected State updateEnergyChannel(String channelId, Realtime realtime) {
final double value;
switch (channelId) {
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/PowerStripDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/PowerStripDevice.java
new file mode 100644
index 0000000000000..640991ebd639c
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/PowerStripDevice.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2010-2019 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.tplinksmarthome.internal.device;
+
+import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
+import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.HS300;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.ThingTypeUID;
+import org.eclipse.smarthome.core.types.State;
+import org.eclipse.smarthome.core.types.UnDefType;
+import org.openhab.binding.tplinksmarthome.internal.Commands;
+import org.openhab.binding.tplinksmarthome.internal.model.Realtime;
+import org.openhab.binding.tplinksmarthome.internal.model.Sysinfo.Outlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TP-Link Smart Home device with multiple sockets, like the HS107 and HS300.
+ *
+ * @author Hilbrand Bouwkamp - Initial contribution
+ */
+@NonNullByDefault
+public class PowerStripDevice extends EnergySwitchDevice {
+
+ private final Logger logger = LoggerFactory.getLogger(PowerStripDevice.class);
+
+ private final List<@Nullable Realtime> realTimeCacheList;
+ private final List<@Nullable String> childIds;
+
+ public PowerStripDevice(ThingTypeUID thingTypeUID) {
+ final int nrOfSockets;
+
+ if (HS300.is(thingTypeUID)) {
+ nrOfSockets = 6;
+ } else {
+ nrOfSockets = 2;
+ }
+ realTimeCacheList = new ArrayList<>(nrOfSockets);
+ childIds = new ArrayList<>(Collections.nCopies(nrOfSockets, ""));
+ }
+
+ @Override
+ public String getUpdateCommand() {
+ return Commands.getSysinfo();
+ }
+
+ @Override
+ public void refreshedDeviceState(@Nullable DeviceState deviceState) {
+ if (deviceState != null) {
+ for (int i = 0; i < childIds.size(); i++) {
+ childIds.set(i, deviceState.getSysinfo().getChildren().get(i).getId());
+ realTimeCacheList.add(i, refreshCache(i));
+ }
+ }
+ }
+
+ @Override
+ public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
+ final int idx = channelToIndex(channelUid);
+
+ if (idx >= 0 && idx < childIds.size()) {
+ final Outlet outlet = deviceState.getSysinfo().getChildren().get(idx);
+ final String baseChannel = channelUid.getIdWithoutGroup();
+
+ if (CHANNEL_SWITCH.equals(baseChannel)) {
+ return outlet.getState();
+ } else if (CHANNELS_ENERGY.contains(baseChannel)) {
+ final Realtime realTime = realTimeCacheList.get(idx);
+
+ return realTime == null ? UnDefType.UNDEF : updateEnergyChannel(baseChannel, realTime);
+ }
+ } else {
+ if (idx >= 0) {
+ logger.debug("For channel update the index '{}' could be mapped to a channel. passed channel: {}", idx,
+ channelUid);
+ }
+ }
+ return super.updateChannel(channelUid, deviceState);
+ }
+
+ @Override
+ protected @Nullable String getChildId(ChannelUID channelUid) {
+ final int idx = channelToIndex(channelUid);
+
+ return idx >= 0 && idx < childIds.size() ? childIds.get(idx) : null;
+ }
+
+ private int channelToIndex(final ChannelUID channelUid) {
+ final String groupId = channelUid.getGroupId();
+
+ return (groupId != null && groupId.startsWith(CHANNEL_OUTLET_GROUP_PREFIX)
+ ? Integer.parseInt(groupId.substring(CHANNEL_OUTLET_GROUP_PREFIX.length()))
+ : 0) - 1;
+ }
+
+ private @Nullable Realtime refreshCache(int idx) {
+ try {
+ final String childId = childIds.get(idx);
+
+ return childId == null ? null
+ : commands.getRealtimeResponse(connection.sendCommand(Commands.getRealtimeWithContext(childId)));
+ } catch (IOException e) {
+ return null;
+ } catch (RuntimeException e) {
+ logger.debug(
+ "Obtaining realtime data for channel-'{}' unexpectedly crashed. If this keeps happening please report: ",
+ idx, e);
+ return null;
+ }
+ }
+}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/RangeExtenderDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/RangeExtenderDevice.java
index be684e6335e77..7956067ea0f8c 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/RangeExtenderDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/RangeExtenderDevice.java
@@ -14,12 +14,11 @@
import java.io.IOException;
-import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.types.State;
-import org.openhab.binding.tplinksmarthome.internal.Connection;
import org.openhab.binding.tplinksmarthome.internal.model.SetRelayState;
/**
@@ -36,7 +35,7 @@ protected State getOnOffState(DeviceState deviceState) {
}
@Override
- protected @Nullable SetRelayState setOnOffState(@NonNull Connection connection, @NonNull OnOffType onOff)
+ protected @Nullable SetRelayState setOnOffState(ChannelUID channelUid, OnOffType onOff)
throws IOException {
// It's unknown what the command is to send to the device so it's not supported.
return null;
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SmartHomeDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SmartHomeDevice.java
index 9e663fb220675..10b55b24030f0 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SmartHomeDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SmartHomeDevice.java
@@ -16,6 +16,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.tplinksmarthome.internal.Commands;
@@ -32,7 +33,9 @@
@NonNullByDefault
public abstract class SmartHomeDevice {
- protected Commands commands = new Commands();
+ protected final Commands commands = new Commands();
+ protected @NonNullByDefault({}) Connection connection;
+ protected @NonNullByDefault({}) TPLinkSmartHomeConfiguration configuration;
/**
* Checks if the response object contains errors and if so throws an {@link IOException} when an error code was set.
@@ -41,13 +44,24 @@ public abstract class SmartHomeDevice {
* @throws IOException if an error code was set in the response object
*/
protected void checkErrors(@Nullable HasErrorResponse response) throws IOException {
- ErrorResponse errorResponse = response == null ? null : response.getErrorResponse();
+ final ErrorResponse errorResponse = response == null ? null : response.getErrorResponse();
if (errorResponse != null && errorResponse.getErrorCode() != 0) {
throw new IOException("Error (" + errorResponse.getErrorCode() + "): " + errorResponse.getErrorMessage());
}
}
+ /**
+ * Sets connection and configuration values.
+ *
+ * @param connection The connection to the device
+ * @param configuration The global configuration
+ */
+ public void initialize(Connection connection, TPLinkSmartHomeConfiguration configuration) {
+ this.connection = connection;
+ this.configuration = configuration;
+ }
+
/**
* @return the json string to send to the device to get the state of the device.
*/
@@ -56,23 +70,27 @@ protected void checkErrors(@Nullable HasErrorResponse response) throws IOExcepti
/**
* Handle the command for the given channel
*
- * @param channelID The channel the command is for
- * @param connection The connection to the device
+ * @param channelUID The channel the command is for
* @param command The command to be send to the device
- * @param configuration The global configuration
* @return Returns true if the commands successfully was send to the device
* @throws IOException In case of communications error or the device returned an error
*/
- public abstract boolean handleCommand(String channelID, Connection connection, Command command,
- TPLinkSmartHomeConfiguration configuration) throws IOException;
+ public abstract boolean handleCommand(ChannelUID channelUID, Command command) throws IOException;
/**
* Returns the {@link State} value for the given value extracted from the deviceState data.
*
- * @param channelId channel to get state for
+ * @param channelUid channel to get state for
* @param deviceState state object containing the state
* @return {@link State} value for the given channel
*/
- public abstract State updateChannel(String channelId, DeviceState deviceState);
+ public abstract State updateChannel(ChannelUID channelUid, DeviceState deviceState);
+ /**
+ * Called with the new device state after the new device state is retrieved from the device.
+ *
+ * @param deviceState new device state
+ */
+ public void refreshedDeviceState(@Nullable DeviceState deviceState) {
+ }
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SwitchDevice.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SwitchDevice.java
index ae5fe31d42264..bfcaa6e46d7a1 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SwitchDevice.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/device/SwitchDevice.java
@@ -19,12 +19,11 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.OnOffType;
+import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.tplinksmarthome.internal.Commands;
-import org.openhab.binding.tplinksmarthome.internal.Connection;
-import org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeConfiguration;
import org.openhab.binding.tplinksmarthome.internal.model.HasErrorResponse;
/**
@@ -41,9 +40,8 @@ public String getUpdateCommand() {
}
@Override
- public boolean handleCommand(String channelID, Connection connection, Command command,
- TPLinkSmartHomeConfiguration configuration) throws IOException {
- return command instanceof OnOffType && handleOnOffType(channelID, connection, (OnOffType) command);
+ public boolean handleCommand(ChannelUID channelUid, Command command) throws IOException {
+ return command instanceof OnOffType && handleOnOffType(channelUid, (OnOffType) command);
}
/**
@@ -56,13 +54,17 @@ protected State getOnOffState(DeviceState deviceState) {
return deviceState.getSysinfo().getRelayState();
}
- private boolean handleOnOffType(String channelID, Connection connection, OnOffType onOff) throws IOException {
- HasErrorResponse response = null;
+ private boolean handleOnOffType(ChannelUID channelUid, OnOffType onOff) throws IOException {
+ final HasErrorResponse response;
+ final String baseChannelId = getBaseChannel(channelUid);
- if (CHANNEL_SWITCH.equals(channelID)) {
- response = setOnOffState(connection, onOff);
- } else if (CHANNEL_LED.equals(channelID)) {
- response = commands.setLedOnResponse(connection.sendCommand(commands.setLedOn(onOff)));
+ if (CHANNEL_SWITCH.contentEquals(baseChannelId)) {
+ response = setOnOffState(channelUid, onOff);
+ } else if (CHANNEL_LED.contentEquals(baseChannelId)) {
+ response = commands
+ .setLedOnResponse(connection.sendCommand(commands.setLedOn(onOff, getChildId(channelUid))));
+ } else {
+ response = null;
}
checkErrors(response);
return response != null;
@@ -71,21 +73,40 @@ private boolean handleOnOffType(String channelID, Connection connection, OnOffTy
/**
* Sends the {@link OnOffType} command to the device and returns the returned answer.
*
- * @param connection Connection to use
+ * @param channelUid channel Id to use to determine child id
* @param onOff command to the send
* @return state returned by the device
+ * @throws IOException exception in case device not reachable
*/
- protected @Nullable HasErrorResponse setOnOffState(Connection connection, OnOffType onOff) throws IOException {
- return commands.setRelayStateResponse(connection.sendCommand(commands.setRelayState(onOff)));
+ protected @Nullable HasErrorResponse setOnOffState(ChannelUID channelUid, OnOffType onOff) throws IOException {
+ return commands
+ .setRelayStateResponse(connection.sendCommand(commands.setRelayState(onOff, getChildId(channelUid))));
}
@Override
- public State updateChannel(String channelId, DeviceState deviceState) {
- if (CHANNEL_SWITCH.equals(channelId)) {
+ public State updateChannel(ChannelUID channelUid, DeviceState deviceState) {
+ final String baseChannelId = getBaseChannel(channelUid);
+
+ if (CHANNEL_SWITCH.equals(baseChannelId)) {
return getOnOffState(deviceState);
- } else if (CHANNEL_LED.equals(channelId)) {
+ } else if (CHANNEL_LED.equals(baseChannelId)) {
return deviceState.getSysinfo().getLedOff();
}
return UnDefType.UNDEF;
}
+
+ /**
+ * Returns the child Id for the given channel if the device supports children and it's a channel for a specific
+ * child.
+ *
+ * @param channelUid channel Id to get the child id for
+ * @return null or child id
+ */
+ protected @Nullable String getChildId(ChannelUID channelUid) {
+ return null;
+ }
+
+ private String getBaseChannel(ChannelUID channelUid) {
+ return channelUid.isInGroup() ? channelUid.getIdWithoutGroup() : channelUid.getId();
+ }
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/handler/SmartHomeHandler.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/handler/SmartHomeHandler.java
index 67da055cd810f..70b51efd2d590 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/handler/SmartHomeHandler.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/handler/SmartHomeHandler.java
@@ -61,7 +61,7 @@ public class SmartHomeHandler extends BaseThingHandler {
private @NonNullByDefault({}) ExpiringCache<@Nullable DeviceState> cache;
/**
- * Constructor
+ * Constructor.
*
* @param thing The thing to handle
* @param smartHomeDevice Specific Smart Home device handler
@@ -74,12 +74,12 @@ public SmartHomeHandler(Thing thing, SmartHomeDevice smartHomeDevice, TPLinkIpAd
}
@Override
- public void handleCommand(ChannelUID channelUID, Command command) {
+ public void handleCommand(ChannelUID channelUid, Command command) {
try {
if (command instanceof RefreshType) {
- updateChannelState(channelUID, cache.getValue());
- } else if (!smartHomeDevice.handleCommand(channelUID.getId(), connection, command, configuration)) {
- logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
+ updateChannelState(channelUid, cache.getValue());
+ } else if (!smartHomeDevice.handleCommand(channelUid, command)) {
+ logger.debug("Command {} is not supported for channel: {}", command, channelUid.getId());
}
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
@@ -102,8 +102,10 @@ public void initialize() {
"No ip address or the device id configured.");
return;
}
- logger.debug("Initializing TP-Link Smart device on ip {}", configuration.ipAddress);
+ logger.debug("Initializing TP-Link Smart device on ip '{}' or deviceId '{}' ", configuration.ipAddress,
+ configuration.deviceId);
connection = createConnection(configuration);
+ smartHomeDevice.initialize(connection, configuration);
cache = new ExpiringCache<@Nullable DeviceState>(TimeUnit.SECONDS.toMillis(configuration.refresh),
this::refreshCache);
updateStatus(ThingStatus.UNKNOWN);
@@ -123,12 +125,12 @@ Connection createConnection(TPLinkSmartHomeConfiguration config) {
return new Connection(config.ipAddress);
}
- @Nullable
- private DeviceState refreshCache() {
+ private @Nullable DeviceState refreshCache() {
try {
updateIpAddress();
- DeviceState deviceState = new DeviceState(connection.sendCommand(smartHomeDevice.getUpdateCommand()));
+ final DeviceState deviceState = new DeviceState(connection.sendCommand(smartHomeDevice.getUpdateCommand()));
updateDeviceId(deviceState.getSysinfo().getDeviceId());
+ smartHomeDevice.refreshedDeviceState(deviceState);
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE);
}
@@ -197,8 +199,7 @@ private void startAutomaticRefresh(TPLinkSmartHomeConfiguration config) {
void refreshChannels() {
logger.trace("Update Channels for:{}", thing.getUID());
- DeviceState value = cache.getValue();
- getThing().getChannels().forEach(channel -> updateChannelState(channel.getUID(), value));
+ getThing().getChannels().forEach(channel -> updateChannelState(channel.getUID(), cache.getValue()));
}
/**
@@ -209,7 +210,10 @@ void refreshChannels() {
*
*/
private void updateChannelState(ChannelUID channelUID, @Nullable DeviceState deviceState) {
- String channelId = channelUID.getId();
+ if (!isLinked(channelUID)) {
+ return;
+ }
+ String channelId = channelUID.isInGroup() ? channelUID.getIdWithoutGroup() : channelUID.getId();
final State state;
if (deviceState == null) {
@@ -217,7 +221,7 @@ private void updateChannelState(ChannelUID channelUID, @Nullable DeviceState dev
} else if (CHANNEL_RSSI.equals(channelId)) {
state = new DecimalType(deviceState.getSysinfo().getRssi());
} else {
- state = smartHomeDevice.updateChannel(channelId, deviceState);
+ state = smartHomeDevice.updateChannel(channelUID, deviceState);
}
updateState(channelUID, state);
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/ContextState.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/ContextState.java
new file mode 100644
index 0000000000000..2505abf96a537
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/ContextState.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2010-2019 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.tplinksmarthome.internal.model;
+
+import com.google.gson.annotations.Expose;
+
+/**
+ * Class to be extended by state classes that support context. i.e. has multiple children that can be controlled.
+ *
+ * @author Hilbrand Bouwkamp - Initial contribution
+ */
+public class ContextState {
+
+ public static class Context {
+ @Expose
+ private String[] childIds = new String[1];
+
+ public void setChildId(String childId) {
+ this.childIds[0] = childId;
+ }
+
+ @Override
+ public String toString() {
+ return " child_ids:[" + childIds[0] + "]";
+ }
+ }
+
+ @Expose
+ private Context context;
+
+ public void setChildId(String childId) {
+ context = new Context();
+ context.setChildId(childId);
+ }
+
+ @Override
+ public String toString() {
+ return context == null ? "" : context.toString();
+ }
+}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/GetRealtime.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/GetRealtime.java
index 4343c1f743a90..e83640941fe55 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/GetRealtime.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/GetRealtime.java
@@ -23,7 +23,7 @@
* @author Hilbrand Bouwkamp - Initial contribution
*/
@NonNullByDefault
-public class GetRealtime {
+public class GetRealtime extends ContextState {
public static class EMeter {
private Realtime getRealtime = new Realtime();
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/HasErrorResponse.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/HasErrorResponse.java
index e219d804e72df..bb7724c86313b 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/HasErrorResponse.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/HasErrorResponse.java
@@ -17,6 +17,7 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
+@FunctionalInterface
public interface HasErrorResponse {
/**
* @return returns the object containing the error response
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetLedOff.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetLedOff.java
index 49e57b6754316..6093859d71a25 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetLedOff.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetLedOff.java
@@ -22,7 +22,7 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
-public class SetLedOff implements HasErrorResponse {
+public class SetLedOff extends ContextState implements HasErrorResponse {
public static class LedOff extends ErrorResponse {
@Expose
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetRelayState.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetRelayState.java
index 498ea8cd0c374..5033ccffe50d5 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetRelayState.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/SetRelayState.java
@@ -22,7 +22,7 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
-public class SetRelayState implements HasErrorResponse {
+public class SetRelayState extends ContextState implements HasErrorResponse {
public static class RelayState extends ErrorResponse {
@Expose(deserialize = false)
@@ -38,6 +38,10 @@ public static class System {
@Expose
private RelayState setRelayState = new RelayState();
+ public void setRelayState(OnOffType onOff) {
+ setRelayState.state = onOff == OnOffType.ON ? 1 : 0;
+ }
+
@Override
public String toString() {
return "set_relay_state:{" + setRelayState + "}";
@@ -53,7 +57,7 @@ public ErrorResponse getErrorResponse() {
}
public void setRelayState(OnOffType onOff) {
- system.setRelayState.state = onOff == OnOffType.ON ? 1 : 0;
+ system.setRelayState(onOff);
}
@Override
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/Sysinfo.java b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/Sysinfo.java
index 03acec812b1f4..5e28ce3189d02 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/Sysinfo.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/java/org/openhab/binding/tplinksmarthome/internal/model/Sysinfo.java
@@ -12,6 +12,9 @@
*/
package org.openhab.binding.tplinksmarthome.internal.model;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.smarthome.core.library.types.OnOffType;
import com.google.gson.annotations.SerializedName;
@@ -80,6 +83,32 @@ public OnOffType getRelayStatus() {
}
}
+ /**
+ * Status of a single outlet on power strip.
+ */
+ public static class Outlet {
+ private String alias;
+ private String id;
+ private long onTime;
+ private int state;
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public long getOnTime() {
+ return onTime;
+ }
+
+ public OnOffType getState() {
+ return state == 1 ? OnOffType.ON : OnOffType.OFF;
+ }
+ }
+
/**
* Status of the range extended Wi-Fi.
*/
@@ -122,6 +151,10 @@ public int getW2gRssi() {
private double latitude;
private double longitude;
+ // powerstrip/multiple plugs support.
+ private int childNum;
+ private List children = new ArrayList<>();
+
// dimmer specific system info
private int brightness;
@@ -251,6 +284,14 @@ public Plug getPlug() {
return plug;
}
+ public int getChildNum() {
+ return childNum;
+ }
+
+ public List getChildren() {
+ return children;
+ }
+
public Sysinfo getSystem() {
return system;
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS107.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS107.xml
new file mode 100644
index 0000000000000..452caec2571de
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS107.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ TP-Link HS107 Smart Wi-Fi Plug, 2-Outlets
+ PowerOutlet
+
+
+
+
+
+
+
+
+
+
+
+ deviceId
+
+
+
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS110.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS110.xml
index c7542b31de0cc..79a36c47f0f5a 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS110.xml
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS110.xml
@@ -14,7 +14,7 @@
-
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS300.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS300.xml
new file mode 100644
index 0000000000000..57779f37a8925
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/HS300.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ TP-Link HS300 Smart Wi-Fi Power Strip
+ PowerOutlet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deviceId
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP200.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP200.xml
new file mode 100644
index 0000000000000..0a96fb11f526b
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP200.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ TP-Link KP200 Smart Wi-Fi Power Outlet, 2-Sockets
+ PowerOutlet
+
+
+
+
+
+
+
+
+
+
+
+ deviceId
+
+
+
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP400.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP400.xml
new file mode 100644
index 0000000000000..d2fd8122dc7ba
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/KP400.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ TP-Link KP400 Smart Outdoor Plug
+ PowerOutlet
+
+
+
+
+
+
+
+
+
+
+
+ deviceId
+
+
+
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE270K.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE270K.xml
index 008810abd6852..9f10a59173d0b 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE270K.xml
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE270K.xml
@@ -10,7 +10,7 @@
PowerOutlet
-
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE370K.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE370K.xml
index efb63a052763e..19838ad31c8eb 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE370K.xml
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/RE370K.xml
@@ -10,7 +10,7 @@
PowerOutlet
-
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/channels.xml b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/channels.xml
index 871d48d660413..c8931f35f1d54 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/channels.xml
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/main/resources/ESH-INF/thing/channels.xml
@@ -5,7 +5,7 @@
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
-
+ SwitchShows the switch state of the Smart Home device.
@@ -27,7 +27,7 @@
Energy
-
+ NumberActual energy usage.
@@ -58,4 +58,32 @@
+
+
+
+ PowerOutlet
+
+
+
+
+
+
+
+
+ PowerOutlet
+
+
+
+
+
+
+ PowerOutlet
+
+
+
+
+
+
+
+
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/ChannelUIDConstants.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/ChannelUIDConstants.java
new file mode 100644
index 0000000000000..f36c1be9e0329
--- /dev/null
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/ChannelUIDConstants.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2010-2019 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.tplinksmarthome.internal;
+
+import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
+import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.*;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.smarthome.core.thing.ChannelUID;
+import org.eclipse.smarthome.core.thing.ThingUID;
+
+/**
+ *
+ * @author Hilbrand Bouwkamp - Initial contribution
+ */
+@NonNullByDefault
+public final class ChannelUIDConstants {
+
+ public static final ChannelUID CHANNEL_UID_BRIGHTNESS = createChannel(LB130, CHANNEL_BRIGHTNESS);
+ public static final ChannelUID CHANNEL_UID_COLOR = createChannel(LB130, CHANNEL_COLOR);
+ public static final ChannelUID CHANNEL_UID_COLOR_TEMPERATURE = createChannel(LB130, CHANNEL_COLOR_TEMPERATURE);
+ public static final ChannelUID CHANNEL_UID_ENERGY_CURRENT = createChannel(HS110, CHANNEL_ENERGY_CURRENT);
+ public static final ChannelUID CHANNEL_UID_ENERGY_POWER = createChannel(HS110, CHANNEL_ENERGY_POWER);
+ public static final ChannelUID CHANNEL_UID_ENERGY_TOTAL = createChannel(HS110, CHANNEL_ENERGY_TOTAL);
+ public static final ChannelUID CHANNEL_UID_ENERGY_VOLTAGE = createChannel(HS110, CHANNEL_ENERGY_VOLTAGE);
+ public static final ChannelUID CHANNEL_UID_LED = createChannel(HS100, CHANNEL_LED);
+ public static final ChannelUID CHANNEL_UID_OTHER = createChannel(HS100, "OTHER");
+ public static final ChannelUID CHANNEL_UID_RSSI = createChannel(HS100, CHANNEL_RSSI);
+ public static final ChannelUID CHANNEL_UID_SWITCH = createChannel(HS100, CHANNEL_SWITCH);
+
+ private static final String ID = "1234";
+
+ private ChannelUIDConstants() {
+ // Util class
+ }
+
+ private static ChannelUID createChannel(TPLinkSmartHomeThingType thingType, String channelId) {
+ return new ChannelUID(new ThingUID(thingType.thingTypeUID(), ID), channelId);
+ }
+
+ public static ChannelUID createChannel(TPLinkSmartHomeThingType thingType, String groupId, String channelId) {
+ return new ChannelUID(new ThingUID(thingType.thingTypeUID(), ID), groupId, channelId);
+ }
+}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/PropertiesCollectorTest.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/PropertiesCollectorTest.java
index 19652da9b94db..9fc45fea56f33 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/PropertiesCollectorTest.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/PropertiesCollectorTest.java
@@ -17,24 +17,20 @@
import java.io.IOException;
import java.util.Map;
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.junit.Test;
import org.openhab.binding.tplinksmarthome.internal.model.GetSysinfo;
-import org.openhab.binding.tplinksmarthome.internal.model.GsonUtil;
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
-import com.google.gson.Gson;
-
/**
* Test class for {@link PropertiesCollector} class.
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
+@NonNullByDefault
public class PropertiesCollectorTest {
- private final Gson gson = GsonUtil.createGson();
-
/**
* Tests if properties for a bulb device are correctly parsed.
*
@@ -65,11 +61,11 @@ public void testRangeExtenderProperties() throws IOException {
assertProperties("rangeextender_get_sysinfo_response", TPLinkSmartHomeThingType.RE270K, 11);
}
- private void assertProperties(@NonNull String responseFile, @NonNull TPLinkSmartHomeThingType thingType,
- int expectedSize) throws IOException {
+ private void assertProperties(String responseFile, TPLinkSmartHomeThingType thingType, int expectedSize)
+ throws IOException {
ThingTypeUID thingTypeUID = thingType.thingTypeUID();
Map props = PropertiesCollector.collectProperties(thingTypeUID, "localhost",
- ModelTestUtil.toJson(gson, responseFile, GetSysinfo.class).getSysinfo());
+ ModelTestUtil.jsonFromFile(responseFile, GetSysinfo.class).getSysinfo());
assertEquals("Number of properties not as expected for properties: " + props, expectedSize, props.size());
props.entrySet().stream().forEach(
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDeviceTest.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDeviceTest.java
index 39e344702a615..6283714d14992 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDeviceTest.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/BulbDeviceTest.java
@@ -13,15 +13,17 @@
package org.openhab.binding.tplinksmarthome.internal.device;
import static org.junit.Assert.*;
+import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
+import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeThingType.LB130;
import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.HSBType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
-import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.types.UnDefType;
import org.junit.Test;
import org.openhab.binding.tplinksmarthome.internal.model.ModelTestUtil;
@@ -31,15 +33,14 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
-public class BulbDeviceTest extends DeviceTestBase {
+@NonNullByDefault
+public class BulbDeviceTest extends DeviceTestBase {
private static final String DEVICE_OFF = "bulb_get_sysinfo_response_off";
- private final BulbDevice device = new BulbDevice(new ThingTypeUID(BINDING_ID, "lb130"), COLOR_TEMPERATURE_LB130_MIN,
- COLOR_TEMPERATURE_LB130_MAX);
-
public BulbDeviceTest() throws IOException {
- super("bulb_get_sysinfo_response_on");
+ super(new BulbDevice(LB130.thingTypeUID(), COLOR_TEMPERATURE_LB130_MIN, COLOR_TEMPERATURE_LB130_MAX),
+ "bulb_get_sysinfo_response_on");
}
@Override
@@ -52,106 +53,107 @@ public void setUp() throws IOException {
public void testHandleCommandBrightness() throws IOException {
assertInput("bulb_transition_light_state_brightness");
assertTrue("Brightness channel should be handled",
- device.handleCommand(CHANNEL_BRIGHTNESS, connection, new PercentType(33), configuration));
+ device.handleCommand(CHANNEL_UID_BRIGHTNESS, new PercentType(33)));
}
@Test
public void testHandleCommandBrightnessOnOff() throws IOException {
assertInput("bulb_transition_light_state_on");
assertTrue("Brightness channel with OnOff state should be handled",
- device.handleCommand(CHANNEL_BRIGHTNESS, connection, OnOffType.ON, configuration));
+ device.handleCommand(CHANNEL_UID_BRIGHTNESS, OnOffType.ON));
}
@Test
public void testHandleCommandColor() throws IOException {
assertInput("bulb_transition_light_state_color");
- assertTrue("Color channel should be handled",
- device.handleCommand(CHANNEL_COLOR, connection, new HSBType("55,44,33"), configuration));
+ assertTrue("Color channel should be handled", device.handleCommand(CHANNEL_UID_COLOR, new HSBType("55,44,33")));
}
public void testHandleCommandColorBrightness() throws IOException {
assertInput("bulb_transition_light_state_brightness");
assertTrue("Color channel with Percentage state (=brightness) should be handled",
- device.handleCommand(CHANNEL_COLOR, connection, new PercentType(33), configuration));
+ device.handleCommand(CHANNEL_UID_COLOR, new PercentType(33)));
}
public void testHandleCommandColorOnOff() throws IOException {
assertInput("bulb_transition_light_state_on");
assertTrue("Color channel with OnOff state should be handled",
- device.handleCommand(CHANNEL_COLOR, connection, OnOffType.ON, configuration));
+ device.handleCommand(CHANNEL_UID_COLOR, OnOffType.ON));
}
@Test
public void testHandleCommandColorTemperature() throws IOException {
assertInput("bulb_transition_light_state_color_temp");
assertTrue("Color temperature channel should be handled",
- device.handleCommand(CHANNEL_COLOR_TEMPERATURE, connection, new PercentType(40), configuration));
+ device.handleCommand(CHANNEL_UID_COLOR_TEMPERATURE, new PercentType(40)));
}
@Test
public void testHandleCommandColorTemperatureOnOff() throws IOException {
assertInput("bulb_transition_light_state_on");
assertTrue("Color temperature channel with OnOff state should be handled",
- device.handleCommand(CHANNEL_COLOR_TEMPERATURE, connection, OnOffType.ON, configuration));
+ device.handleCommand(CHANNEL_UID_COLOR_TEMPERATURE, OnOffType.ON));
}
@Test
public void testHandleCommandSwitch() throws IOException {
assertInput("bulb_transition_light_state_on");
- assertTrue("Switch channel should be handled",
- device.handleCommand(CHANNEL_SWITCH, connection, OnOffType.ON, configuration));
+ assertTrue("Switch channel should be handled", device.handleCommand(CHANNEL_UID_SWITCH, OnOffType.ON));
}
@Test
public void testUpdateChannelBrightnessOn() {
assertEquals("Brightness should be on", new PercentType(92),
- device.updateChannel(CHANNEL_BRIGHTNESS, deviceState));
+ device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
}
@Test
public void testUpdateChannelBrightnessOff() throws IOException {
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
assertEquals("Brightness should be off", PercentType.ZERO,
- device.updateChannel(CHANNEL_BRIGHTNESS, deviceState));
+ device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
}
@Test
public void testUpdateChannelColorOn() {
- assertEquals("Color should be on", new HSBType("7,44,92"), device.updateChannel(CHANNEL_COLOR, deviceState));
+ assertEquals("Color should be on", new HSBType("7,44,92"),
+ device.updateChannel(CHANNEL_UID_COLOR, deviceState));
}
@Test
public void testUpdateChannelColorOff() throws IOException {
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
- assertEquals("Color should be off", new HSBType("7,44,0"), device.updateChannel(CHANNEL_COLOR, deviceState));
+ assertEquals("Color should be off", new HSBType("7,44,0"),
+ device.updateChannel(CHANNEL_UID_COLOR, deviceState));
}
@Test
public void testUpdateChannelSwitchOn() {
- assertSame("Switch should be on", OnOffType.ON, device.updateChannel(CHANNEL_SWITCH, deviceState));
+ assertSame("Switch should be on", OnOffType.ON, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
}
@Test
public void testUpdateChannelSwitchOff() throws IOException {
deviceState = new DeviceState(ModelTestUtil.readJson(DEVICE_OFF));
- assertSame("Switch should be off", OnOffType.OFF, device.updateChannel(CHANNEL_SWITCH, deviceState));
+ assertSame("Switch should be off", OnOffType.OFF, device.updateChannel(CHANNEL_UID_SWITCH, deviceState));
}
@Test
public void testUpdateChannelColorTemperature() {
assertEquals("Color temperature should be set", new PercentType(3),
- device.updateChannel(CHANNEL_COLOR_TEMPERATURE, deviceState));
+ device.updateChannel(CHANNEL_UID_COLOR_TEMPERATURE, deviceState));
}
@Test
public void testUpdateChannelOther() {
- assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF, device.updateChannel("OTHER", deviceState));
+ assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
+ device.updateChannel(CHANNEL_UID_OTHER, deviceState));
}
@Test
public void testUpdateChannelPower() {
assertEquals("Power values should be set", new DecimalType(10.8),
- device.updateChannel(CHANNEL_ENERGY_POWER, deviceState));
+ device.updateChannel(CHANNEL_UID_ENERGY_POWER, deviceState));
}
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DeviceTestBase.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DeviceTestBase.java
index cb5ec2ff99ef3..041bcf198c955 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DeviceTestBase.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DeviceTestBase.java
@@ -22,8 +22,9 @@
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Before;
import org.mockito.Mock;
import org.openhab.binding.tplinksmarthome.internal.Connection;
@@ -36,28 +37,31 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
-public class DeviceTestBase {
+@NonNullByDefault
+public class DeviceTestBase {
- @NonNull
+ protected final T device;
protected final Connection connection;
- @NonNull
protected final TPLinkSmartHomeConfiguration configuration = new TPLinkSmartHomeConfiguration();
- protected DeviceState deviceState;
+ protected @NonNullByDefault({}) DeviceState deviceState;
private final String deviceStateFilename;
@Mock
- private Socket socket;
+ private @NonNullByDefault({}) Socket socket;
@Mock
- private OutputStream outputStream;
+ private @NonNullByDefault({}) OutputStream outputStream;
/**
* Constructor.
*
+ * @param device Device under test
* @param deviceStateFilename name of the file to read the device state json from to use in tests
+ *
* @throws IOException exception in case device not reachable
*/
- public DeviceTestBase(@NonNull String deviceStateFilename) throws IOException {
+ protected DeviceTestBase(T device, String deviceStateFilename) throws IOException {
+ this.device = device;
this.deviceStateFilename = deviceStateFilename;
configuration.ipAddress = "localhost";
configuration.refresh = 30;
@@ -68,6 +72,7 @@ protected Socket createSocket() throws IOException {
return socket;
};
};
+ device.initialize(connection, configuration);
}
@Before
@@ -84,7 +89,7 @@ public void setUp() throws IOException {
* @param responseFilenames names of the files to read that contains the answer. It's the unencrypted json string
* @throws IOException exception in case device not reachable
*/
- protected void setSocketReturnAssert(@NonNull String... responseFilenames) throws IOException {
+ protected void setSocketReturnAssert(String... responseFilenames) throws IOException {
AtomicInteger index = new AtomicInteger();
doAnswer(i -> {
@@ -103,15 +108,21 @@ protected void setSocketReturnAssert(@NonNull String... responseFilenames) throw
* @param filenames names of the files containing the reference json
* @throws IOException exception in case device not reachable
*/
- protected void assertInput(@NonNull String... filename) throws IOException {
+ protected void assertInput(String... filenames) throws IOException {
+ assertInput(Function.identity(), Function.identity(), filenames);
+ }
+
+ protected void assertInput(Function jsonProcessor, Function expectedProcessor,
+ String... filenames) throws IOException {
AtomicInteger index = new AtomicInteger();
doAnswer(arg -> {
- String json = ModelTestUtil.readJson(filename[index.get()]);
+ String json = jsonProcessor.apply(ModelTestUtil.readJson(filenames[index.get()]));
byte[] input = (byte[]) arg.getArguments()[0];
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(input)) {
- assertEquals(filename[index.get()], json, CryptUtil.decryptWithLength(inputStream));
+ String expectedString = expectedProcessor.apply(CryptUtil.decryptWithLength(inputStream));
+ assertEquals(filenames[index.get()], json, expectedString);
}
index.incrementAndGet();
return null;
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDeviceTest.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDeviceTest.java
index 97cd710cffd42..7c3ef0ea0aaf5 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDeviceTest.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/DimmerDeviceTest.java
@@ -13,10 +13,11 @@
package org.openhab.binding.tplinksmarthome.internal.device;
import static org.junit.Assert.*;
-import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.CHANNEL_BRIGHTNESS;
+import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.types.UnDefType;
@@ -28,22 +29,21 @@
*
* @author Hilbrand Bouwkamp - Initial contribution
*/
-public class DimmerDeviceTest extends DeviceTestBase {
+@NonNullByDefault
+public class DimmerDeviceTest extends DeviceTestBase {
private static final PercentType BRIGHTNESS_VALUE = new PercentType(50);
- private final DimmerDevice device = new DimmerDevice();
-
public DimmerDeviceTest() throws IOException {
- super("hs220_get_sysinfo_response_on");
+ super(new DimmerDevice(), "hs220_get_sysinfo_response_on");
}
@Test
public void testHandleCommandBrightnessOnOff() throws IOException {
assertInput("dimmer_set_switch_state_on");
- setSocketReturnAssert("dimmer_set_switch_state_response");
+ setSocketReturnAssert("dimmer_set_switch_state_on");
assertTrue("Brightness channel as OnOffType type should be handled",
- device.handleCommand(CHANNEL_BRIGHTNESS, connection, OnOffType.ON, configuration));
+ device.handleCommand(CHANNEL_UID_BRIGHTNESS, OnOffType.ON));
}
@Test
@@ -51,7 +51,7 @@ public void testHandleCommandBrightnessZero() throws IOException {
assertInput("dimmer_set_switch_state_off");
setSocketReturnAssert("dimmer_set_switch_state_response");
assertTrue("Brightness channel with percentage 0 should be handled",
- device.handleCommand(CHANNEL_BRIGHTNESS, connection, PercentType.ZERO, configuration));
+ device.handleCommand(CHANNEL_UID_BRIGHTNESS, PercentType.ZERO));
}
@Test
@@ -59,7 +59,7 @@ public void testHandleCommandBrightness() throws IOException {
assertInput("dimmer_set_brightness");
setSocketReturnAssert("dimmer_set_brightness_response");
assertTrue("Brightness channel should be handled",
- device.handleCommand(CHANNEL_BRIGHTNESS, connection, new PercentType(17), configuration));
+ device.handleCommand(CHANNEL_UID_BRIGHTNESS, new PercentType(17)));
}
@Test
@@ -67,17 +67,18 @@ public void testUpdateChannelSwitch() throws IOException {
deviceState = new DeviceState(ModelTestUtil.readJson("hs220_get_sysinfo_response_off"));
assertSame("Dimmer device should be off", OnOffType.OFF,
- ((PercentType) device.updateChannel(CHANNEL_BRIGHTNESS, deviceState)).as(OnOffType.class));
+ ((PercentType) device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState)).as(OnOffType.class));
}
@Test
public void testUpdateChannelBrightness() {
assertEquals("Dimmer brightness should be set", BRIGHTNESS_VALUE,
- device.updateChannel(CHANNEL_BRIGHTNESS, deviceState));
+ device.updateChannel(CHANNEL_UID_BRIGHTNESS, deviceState));
}
@Test
public void testUpdateChannelOther() {
- assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF, device.updateChannel("OTHER", deviceState));
+ assertSame("Unknown channel should return UNDEF", UnDefType.UNDEF,
+ device.updateChannel(CHANNEL_UID_OTHER, deviceState));
}
}
diff --git a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDeviceTest.java b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDeviceTest.java
index a3bf32795abfc..6f63fa7232a71 100644
--- a/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDeviceTest.java
+++ b/bundles/org.openhab.binding.tplinksmarthome/src/test/java/org/openhab/binding/tplinksmarthome/internal/device/EnergySwitchDeviceTest.java
@@ -13,13 +13,13 @@
package org.openhab.binding.tplinksmarthome.internal.device;
import static org.junit.Assert.*;
-import static org.openhab.binding.tplinksmarthome.internal.TPLinkSmartHomeBindingConstants.*;
+import static org.openhab.binding.tplinksmarthome.internal.ChannelUIDConstants.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.types.State;
import org.eclipse.smarthome.core.types.UnDefType;
@@ -35,13 +35,13 @@
* @author Hilbrand Bouwkamp - Initial contribution
*/
@RunWith(value = Parameterized.class)
+@NonNullByDefault
public class EnergySwitchDeviceTest {
private static final List